SymbolTable.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. #include "SymbolTable.h"
  2. #include "DebuggerData.h"
  3. #include <QFile>
  4. #include <QTextStream>
  5. #include <QStringList>
  6. #include <QRegExp>
  7. #include <QFileInfo>
  8. #include <QXmlStreamWriter>
  9. #include <QMap>
  10. // class SymbolTable
  11. SymbolTable::SymbolTable()
  12. {
  13. connect(&fileWatcher, SIGNAL(fileChanged(const QString&)), this, SLOT(fileChanged(const QString&)));
  14. }
  15. SymbolTable::~SymbolTable()
  16. {
  17. clear();
  18. }
  19. void SymbolTable::add(Symbol* symbol)
  20. {
  21. symbols.append(symbol);
  22. symbol->table = this;
  23. mapSymbol(symbol);
  24. }
  25. void SymbolTable::removeAt(int index)
  26. {
  27. Symbol* symbol = symbols.takeAt(index);
  28. unmapSymbol(symbol);
  29. delete symbol;
  30. }
  31. void SymbolTable::remove(Symbol* symbol)
  32. {
  33. symbols.removeAll(symbol);
  34. unmapSymbol(symbol);
  35. delete symbol;
  36. }
  37. void SymbolTable::clear()
  38. {
  39. addressSymbols.clear();
  40. valueSymbols.clear();
  41. qDeleteAll(symbols);
  42. symbols.clear();
  43. }
  44. int SymbolTable::size() const
  45. {
  46. return symbols.size();
  47. }
  48. void SymbolTable::mapSymbol(Symbol* symbol)
  49. {
  50. if (symbol->type() != Symbol::VALUE) {
  51. addressSymbols.insert(symbol->value(), symbol);
  52. }
  53. if (symbol->type() != Symbol::JUMPLABEL) {
  54. valueSymbols.insert(symbol->value(), symbol);
  55. }
  56. }
  57. void SymbolTable::unmapSymbol(Symbol* symbol)
  58. {
  59. QMutableMapIterator<int, Symbol*> i(addressSymbols);
  60. while (i.hasNext()) {
  61. i.next();
  62. if (i.value() == symbol) i.remove();
  63. }
  64. QMutableHashIterator<int, Symbol*> j(valueSymbols);
  65. while (j.hasNext()) {
  66. j.next();
  67. if (j.value() == symbol) j.remove();
  68. }
  69. }
  70. void SymbolTable::symbolTypeChanged(Symbol* symbol)
  71. {
  72. unmapSymbol(symbol);
  73. mapSymbol(symbol);
  74. }
  75. void SymbolTable::symbolValueChanged(Symbol* symbol)
  76. {
  77. unmapSymbol(symbol);
  78. mapSymbol(symbol);
  79. }
  80. Symbol* SymbolTable::findFirstAddressSymbol(int addr, MemoryLayout* ml)
  81. {
  82. for (currentAddress = addressSymbols.begin();
  83. currentAddress != addressSymbols.end(); ++currentAddress) {
  84. if ((*currentAddress)->value() >= addr) {
  85. if ((*currentAddress)->isSlotValid(ml)) {
  86. return *currentAddress;
  87. }
  88. }
  89. }
  90. return 0;
  91. }
  92. Symbol* SymbolTable::getCurrentAddressSymbol()
  93. {
  94. return currentAddress != addressSymbols.end() ? *currentAddress : 0;
  95. }
  96. Symbol* SymbolTable::findNextAddressSymbol(MemoryLayout* ml)
  97. {
  98. for (++currentAddress; currentAddress != addressSymbols.end();
  99. ++currentAddress) {
  100. if ((*currentAddress)->isSlotValid(ml)) {
  101. return *currentAddress;
  102. }
  103. }
  104. return 0;
  105. }
  106. Symbol* SymbolTable::getValueSymbol(int val, Symbol::Register reg, MemoryLayout* ml)
  107. {
  108. for (QMultiHash<int, Symbol*>::iterator it = valueSymbols.find(val);
  109. it != valueSymbols.end() && it.key() == val; ++it) {
  110. if ((it.value()->validRegisters() & reg) &&
  111. it.value()->isSlotValid(ml)) {
  112. return it.value();
  113. }
  114. }
  115. return 0;
  116. }
  117. Symbol* SymbolTable::getAddressSymbol(int addr, MemoryLayout* ml)
  118. {
  119. for (QMultiMap<int, Symbol*>::iterator it = addressSymbols.find(addr);
  120. it != addressSymbols.end() && it.key() == addr; ++it) {
  121. if (it.value()->isSlotValid(ml)) {
  122. return it.value();
  123. }
  124. }
  125. return 0;
  126. }
  127. Symbol* SymbolTable::getAddressSymbol(const QString& label, bool case_sensitive)
  128. {
  129. for (QMultiMap<int, Symbol*>::iterator it = addressSymbols.begin();
  130. it != addressSymbols.end(); ++it) {
  131. if (it.value()->text().compare(label, Qt::CaseSensitive)==0)
  132. return it.value();
  133. if (!case_sensitive && it.value()->text().compare(label, Qt::CaseInsensitive)==0)
  134. return it.value();
  135. }
  136. return 0;
  137. }
  138. QStringList SymbolTable::labelList(bool include_vars, const MemoryLayout* ml) const
  139. {
  140. QStringList labels;
  141. for (QMultiMap<int, Symbol*>::const_iterator it = addressSymbols.begin();
  142. it != addressSymbols.end(); ++it)
  143. {
  144. if (it.value()->type() == Symbol::JUMPLABEL || (include_vars && it.value()->type() == Symbol::VARIABLELABEL ) )
  145. if( ml == 0 || it.value()->isSlotValid(ml) )
  146. labels << it.value()->text();
  147. }
  148. return labels;
  149. }
  150. int SymbolTable::symbolFilesSize() const
  151. {
  152. return symbolFiles.size();
  153. }
  154. const QString& SymbolTable::symbolFile(int index) const
  155. {
  156. return symbolFiles.at(index).fileName;
  157. }
  158. const QDateTime& SymbolTable::symbolFileRefresh(int index) const
  159. {
  160. return symbolFiles.at(index).refreshTime;
  161. }
  162. bool SymbolTable::readFile(const QString& filename, FileType type)
  163. {
  164. if (type == DETECT_FILE) {
  165. if (filename.toLower().endsWith(".map")) {
  166. // HiTech link map file
  167. type = LINKMAP_FILE;
  168. } else if (filename.toLower().endsWith(".sym")) {
  169. // auto detect which sym file
  170. QFile file(filename);
  171. if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
  172. QTextStream in(&file);
  173. QString line = in.readLine();
  174. if (line[0] == ';') {
  175. type = ASMSX_FILE;
  176. } else if (line.contains("; last def. pass")) {
  177. type = TNIASM0_FILE;
  178. } else if (line.contains(": %equ ")) {
  179. type = TNIASM1_FILE;
  180. } else if (line.contains(": equ ")) {
  181. type = SJASM_FILE;
  182. } else {
  183. // this is a blunt conclusion but I
  184. // don't know a way to detect this file
  185. // type
  186. type = HTC_FILE;
  187. }
  188. }
  189. } else {
  190. QString ext = filename.toLower();
  191. /* They are the same type of file. For some reason the Debian
  192. * manpage uses the extension ".sys"
  193. * pasmo doc -> pasmo [options] file.asm file.bin [file.symbol [file.publics] ]
  194. * pasmo manpage in Debian -> pasmo [options] file.asm file.bin [file.sys]
  195. */
  196. if (ext.endsWith(".symbol") || ext.endsWith(".publics") || ext.endsWith(".sys") ) {
  197. type = PASMO_FILE;
  198. }
  199. }
  200. }
  201. switch (type) {
  202. case TNIASM0_FILE:
  203. return readTNIASM0File(filename);
  204. case TNIASM1_FILE:
  205. return readTNIASM1File(filename);
  206. case SJASM_FILE:
  207. return readSJASMFile(filename);
  208. case ASMSX_FILE:
  209. return readASMSXFile(filename);
  210. case HTC_FILE:
  211. return readHTCFile(filename);
  212. case LINKMAP_FILE:
  213. return readLinkMapFile(filename);
  214. case PASMO_FILE:
  215. return readPASMOFile(filename);
  216. default:
  217. return false;
  218. }
  219. }
  220. void SymbolTable::appendFile(const QString& file, FileType type)
  221. {
  222. SymbolFileRecord rec;
  223. rec.fileName = file;
  224. rec.fileType = type;
  225. rec.refreshTime = QDateTime::currentDateTime();
  226. symbolFiles.append(rec);
  227. fileWatcher.addPath(file);
  228. }
  229. // Universal value parsing routine. Accepts:
  230. // - 0123h, 1234h, 1234H (hex)
  231. // - 0x1234 (hex)
  232. // - 1234 (dec)
  233. // - 0123 (oct)
  234. // The string may (optionally) end with a '; comment' part (with or without
  235. // whitespace around the ';' character).
  236. static bool parseValue(const QString& str, int& result)
  237. {
  238. QStringList l = str.split(";"); // ignore stuff after ';'
  239. QString s = l.at(0).trimmed();
  240. bool success;
  241. if (s.endsWith('h', Qt::CaseInsensitive)) {
  242. s.chop(1);
  243. result = s.toInt(&success, 16);
  244. } else {
  245. result = s.toInt(&success, 0); // any base (e.g. 0x..)
  246. }
  247. return success;
  248. }
  249. bool SymbolTable::readSymbolFile(
  250. const QString& filename, FileType type, const QString& equ)
  251. {
  252. QFile file(filename);
  253. if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
  254. return false;
  255. }
  256. appendFile(filename, type);
  257. QTextStream in(&file);
  258. while (!in.atEnd()) {
  259. QString line = in.readLine();
  260. QStringList l = line.split(equ);
  261. if (l.size() != 2) continue;
  262. int value;
  263. if (!parseValue(l.at(1), value)) continue;
  264. Symbol* sym = new Symbol(l.at(0), value);
  265. sym->setSource(&symbolFiles.back().fileName);
  266. add(sym);
  267. }
  268. return true;
  269. }
  270. bool SymbolTable::readTNIASM0File(const QString& filename)
  271. {
  272. return readSymbolFile(filename, TNIASM0_FILE, ": equ ");
  273. }
  274. bool SymbolTable::readTNIASM1File(const QString& filename)
  275. {
  276. return readSymbolFile(filename, TNIASM1_FILE, ": %equ ");
  277. }
  278. bool SymbolTable::readSJASMFile(const QString& filename)
  279. {
  280. return readSymbolFile(filename, SJASM_FILE, ": equ ");
  281. }
  282. bool SymbolTable::readASMSXFile(const QString& filename)
  283. {
  284. QFile file( filename );
  285. if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
  286. return false;
  287. }
  288. appendFile(filename, ASMSX_FILE);
  289. QTextStream in(&file);
  290. int filePart = 0;
  291. while (!in.atEnd()) {
  292. QString line = in.readLine();
  293. if (line[0] == ';') {
  294. if (line.startsWith("; global and local")) {
  295. filePart = 1;
  296. } else if (line.startsWith("; other")) {
  297. filePart = 2;
  298. }
  299. } else {
  300. if ((line[0] == '$') || (line[4] == 'h') ||
  301. (line[5] == 'h') || (line[8] == 'h')) {
  302. if (filePart == 1) {
  303. QStringList l = line.split(" ");
  304. Symbol* sym;
  305. if (line[0] == '$') {
  306. sym = new Symbol(l.at(1).trimmed(), l.at(0).right(4).toInt(0, 16));
  307. } else if ((line[4] == 'h') || (line[5] == 'h')) {
  308. sym = new Symbol(l.at(1).trimmed(), l.at(0).mid(l.at(0).indexOf('h') - 4, 4).toInt(0, 16));
  309. } else {
  310. QString m = l.at(0);
  311. QStringList n = m.split(":"); // n.at(0) = MegaROM page
  312. sym = new Symbol(l.at(1).trimmed(), n.at(1).left(4).toInt(0, 16));
  313. }
  314. sym->setSource(&symbolFiles.back().fileName);
  315. add(sym);
  316. } else if (filePart == 2) {
  317. //
  318. }
  319. }
  320. }
  321. }
  322. return true;
  323. }
  324. bool SymbolTable::readPASMOFile(const QString& filename)
  325. {
  326. QFile file( filename );
  327. if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
  328. return false;
  329. }
  330. appendFile(filename, PASMO_FILE);
  331. QTextStream in(&file);
  332. while (!in.atEnd()) {
  333. QString line;
  334. QStringList l;
  335. Symbol* sym;
  336. line = in.readLine();
  337. l = line.split(QRegExp("(\t+)|( +)"));
  338. if (l.size() == 3) {
  339. sym = new Symbol(l.at(0), l.at(2).left(5).toInt(0, 16));
  340. sym->setSource(&symbolFiles.back().fileName);
  341. add(sym);
  342. }
  343. }
  344. return true;
  345. }
  346. bool SymbolTable::readHTCFile(const QString& filename)
  347. {
  348. QFile file(filename);
  349. if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
  350. return false;
  351. }
  352. appendFile(filename, HTC_FILE);
  353. QTextStream in(&file);
  354. while (!in.atEnd()) {
  355. QString line = in.readLine();
  356. QStringList l = line.split(' ');
  357. if (l.size() != 3) continue;
  358. int value;
  359. if (!parseValue("0x" + l.at(1), value)) continue;
  360. Symbol* sym = new Symbol(l.at(0), value);
  361. sym->setSource(&symbolFiles.back().fileName);
  362. add(sym);
  363. }
  364. return true;
  365. }
  366. bool SymbolTable::readLinkMapFile(const QString& filename)
  367. {
  368. const QString magic("Machine type");
  369. const QString tableStart("*\tSymbol Table");
  370. QRegExp rx(" [0-9A-Fa-f]{4} (?![ 0-9])");
  371. QRegExp rp("^([^ ]+) +[^ ]* +([0-9A-Fa-f]{4}) $");
  372. QFile file(filename);
  373. if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
  374. return false;
  375. }
  376. appendFile(filename, LINKMAP_FILE);
  377. QTextStream in(&file);
  378. if (in.atEnd()) return false;
  379. if (!in.readLine().startsWith(magic)) return false;
  380. while (true) {
  381. if (in.atEnd()) return false;
  382. if (in.readLine().startsWith(tableStart)) break;
  383. }
  384. while (!in.atEnd()) {
  385. QString line = in.readLine();
  386. Q_ASSERT(!line.endsWith("\r"));
  387. if (line.isEmpty()) continue;
  388. line += " ";
  389. int len = line.length();
  390. int l;
  391. int pos = 0;
  392. bool ok = false;
  393. // HiTech uses multiple columns of non-fixed width and
  394. // a column for psect may be blank so the address may in
  395. // the first or second match.
  396. for (int tries = 0; (tries < 2) && !ok; ++tries) {
  397. pos = rx.indexIn(line, pos);
  398. l = pos + rx.matchedLength();
  399. if ((l > 0) && (len % l) == 0) {
  400. ok = true;
  401. for (int posn = pos + l; (posn < len) && ok; posn += l) {
  402. ok = (posn == rx.indexIn(line, posn));
  403. }
  404. }
  405. pos = l - 1;
  406. }
  407. if (!ok) continue;
  408. for (pos = 0; pos < len; pos += l) {
  409. QString part = line.mid(pos, l);
  410. if (rp.indexIn(part) == 0) {
  411. QStringList l = rp.capturedTexts();
  412. Symbol* sym = new Symbol(l.at(1), l.last().toInt(0, 16));
  413. sym->setSource(&symbolFiles.back().fileName);
  414. add(sym);
  415. }
  416. }
  417. }
  418. return true;
  419. }
  420. void SymbolTable::fileChanged(const QString & /*path*/)
  421. {
  422. emit symbolFileChanged();
  423. }
  424. void SymbolTable::reloadFiles()
  425. {
  426. for (int i = 0; i < symbolFiles.size(); ++i) {
  427. // check if file is newer
  428. QFileInfo fi = QFileInfo(symbolFiles[i].fileName);
  429. if (fi.lastModified() <= symbolFiles[i].refreshTime) continue;
  430. // file info
  431. QString name = symbolFiles[i].fileName;
  432. FileType type = symbolFiles[i].fileType;
  433. // symbol file is newer
  434. QMap<QString, Symbol> symCopy;
  435. // copy all symbols originating from this file
  436. QMutableListIterator<Symbol*> si(symbols);
  437. while (si.hasNext()) {
  438. si.next();
  439. if (si.value()->source() == &symbolFiles[i].fileName) {
  440. symCopy.insert(si.value()->text(), Symbol(*si.value()));
  441. }
  442. }
  443. // remove existing file
  444. unloadFile(name);
  445. // read the new file
  446. readFile(name, type);
  447. // find old symbols in newly loaded file
  448. QMutableListIterator<Symbol*> ni(symbols);
  449. QString* newFile = &symbolFiles.back().fileName;
  450. while (ni.hasNext()) {
  451. ni.next();
  452. if (ni.value()->source() != newFile) continue;
  453. // find symbol in old list
  454. QMap<QString, Symbol>::iterator sit = symCopy.find(ni.value()->text());
  455. if (sit == symCopy.end()) continue;
  456. // symbol existed before, copy settings
  457. ni.value()->setValidSlots(sit->validSlots());
  458. ni.value()->setValidRegisters(sit->validRegisters());
  459. ni.value()->setType(sit->type());
  460. if (sit->status() == Symbol::LOST) {
  461. ni.value()->setStatus(Symbol::ACTIVE);
  462. } else {
  463. ni.value()->setStatus(sit->status());
  464. }
  465. symCopy.erase(sit);
  466. }
  467. // all symbols left in map are lost
  468. for (QMap<QString, Symbol>::iterator sit = symCopy.begin();
  469. sit != symCopy.end(); ++sit) {
  470. Symbol* sym = new Symbol(sit.value());
  471. sym->setStatus(Symbol::LOST);
  472. sym->setSource(newFile);
  473. add(sym);
  474. }
  475. }
  476. }
  477. void SymbolTable::unloadFile(const QString& file, bool keepSymbols)
  478. {
  479. int index = -1;
  480. for (int i = 0; i < symbolFiles.size(); ++i) {
  481. if (symbolFiles[i].fileName == file) {
  482. index = i;
  483. break;
  484. }
  485. }
  486. if (index >= 0) {
  487. QString* name = &symbolFiles[index].fileName;
  488. if (!keepSymbols) {
  489. // remove symbols from address map
  490. QMutableMapIterator<int, Symbol*> mi(addressSymbols);
  491. while (mi.hasNext()) {
  492. mi.next();
  493. if (mi.value()->source() == name) mi.remove();
  494. }
  495. // remove symbols from value hash
  496. QMutableHashIterator<int, Symbol*> hi(valueSymbols);
  497. while (hi.hasNext()) {
  498. hi.next();
  499. if (hi.value()->source() == name) hi.remove();
  500. }
  501. }
  502. // remove symbols from value hash
  503. QMutableListIterator<Symbol*> i(symbols);
  504. while (i.hasNext()) {
  505. i.next();
  506. Symbol* sym = i.value();
  507. if (sym->source() == name) {
  508. if (keepSymbols) {
  509. sym->setSource(0);
  510. } else {
  511. i.remove();
  512. delete sym;
  513. }
  514. }
  515. }
  516. // remove record
  517. fileWatcher.removePath(symbolFiles[index].fileName);
  518. symbolFiles.removeAt(index);
  519. }
  520. }
  521. /*
  522. * Session loading/saving
  523. */
  524. void SymbolTable::saveSymbols(QXmlStreamWriter& xml)
  525. {
  526. // write files
  527. QMap<const QString*, int> fileIds;
  528. for (int i = 0; i < symbolFiles.size(); ++i) {
  529. // add id mapping
  530. fileIds[&symbolFiles[i].fileName] = i;
  531. // write element
  532. xml.writeStartElement("SymbolFile");
  533. switch (symbolFiles[i].fileType) {
  534. case TNIASM0_FILE:
  535. xml.writeAttribute("type","tniasm0");
  536. break;
  537. case TNIASM1_FILE:
  538. xml.writeAttribute("type","tniasm1");
  539. break;
  540. case ASMSX_FILE:
  541. xml.writeAttribute("type","asmsx");
  542. break;
  543. case LINKMAP_FILE:
  544. xml.writeAttribute("type","linkmap");
  545. break;
  546. default:
  547. break;
  548. }
  549. xml.writeAttribute("refreshTime",
  550. QString::number(symbolFiles[i].refreshTime.toTime_t()));
  551. xml.writeCharacters(symbolFiles[i].fileName);
  552. xml.writeEndElement();
  553. }
  554. // write symbols
  555. for (QList<Symbol*>::iterator sit = symbols.begin();
  556. sit != symbols.end(); ++sit) {
  557. Symbol* sym = *sit;
  558. xml.writeStartElement("Symbol");
  559. // status
  560. if (sym->status() == Symbol::HIDDEN) {
  561. xml.writeAttribute("status", "hidden");
  562. } else if (sym->status() == Symbol::LOST) {
  563. xml.writeAttribute("status", "lost");
  564. }
  565. // type
  566. if (sym->type() == Symbol::JUMPLABEL) {
  567. xml.writeTextElement("type", "jump");
  568. } else if (sym->type() == Symbol::VARIABLELABEL) {
  569. xml.writeTextElement("type", "variable");
  570. } else {
  571. xml.writeTextElement("type", "value");
  572. }
  573. // text, value, slots and registers
  574. xml.writeTextElement("name", sym->text());
  575. xml.writeTextElement("value", QString::number(sym->value()));
  576. xml.writeTextElement("validSlots", QString::number(sym->validSlots()));
  577. xml.writeTextElement("validRegisters", QString::number(sym->validRegisters()));
  578. // write source filename
  579. if (sym->source()) {
  580. xml.writeTextElement("source", QString::number(fileIds[sym->source()]));
  581. }
  582. // complete
  583. xml.writeEndElement();
  584. }
  585. }
  586. void SymbolTable::loadSymbols(QXmlStreamReader& xml)
  587. {
  588. Symbol* sym;
  589. while (!xml.atEnd()) {
  590. xml.readNext();
  591. // exit if closing of main tag
  592. if (xml.isEndElement() && xml.name() == "Symbols") break;
  593. // begin tag
  594. if (xml.isStartElement()) {
  595. if (xml.name() == "SymbolFile") {
  596. // read attributes and text
  597. QString ftype = xml.attributes().value("type").toString().toLower();
  598. QString rtime = xml.attributes().value("refreshTime").toString();
  599. QString fname = xml.readElementText();
  600. // check type
  601. FileType type = TNIASM0_FILE;
  602. if (ftype == "tniasm1") {
  603. type = TNIASM1_FILE;
  604. } else if (ftype == "asmsx") {
  605. type = ASMSX_FILE;
  606. } else if (ftype == "linkmap") {
  607. type = LINKMAP_FILE;
  608. }
  609. // append file
  610. appendFile(fname, type);
  611. // change time
  612. symbolFiles.back().refreshTime.setTime_t(rtime.toUInt());
  613. } else if (xml.name() == "Symbol") {
  614. // add empty symbol
  615. sym = new Symbol("", 0);
  616. add(sym);
  617. // get status attribute
  618. QString stat = xml.attributes().value("status").toString().toLower();
  619. if (stat == "hidden") {
  620. sym->setStatus(Symbol::HIDDEN);
  621. } else if( stat == "lost" ) {
  622. sym->setStatus(Symbol::LOST);
  623. }
  624. } else if (xml.name() == "type") {
  625. // read symbol type element
  626. QString type = xml.readElementText().trimmed().toLower();
  627. if (type == "jump") {
  628. sym->setType(Symbol::JUMPLABEL);
  629. } else if( type == "variable" ) {
  630. sym->setType(Symbol::VARIABLELABEL);
  631. } else if( type == "value" ) {
  632. sym->setType(Symbol::VALUE);
  633. }
  634. } else if (xml.name() == "name") {
  635. // read symbol name
  636. sym->setText(xml.readElementText());
  637. } else if (xml.name() == "value") {
  638. // read symbol value
  639. sym->setValue(xml.readElementText().toInt());
  640. } else if (xml.name() == "validSlots") {
  641. // read numeric valid slot mask
  642. sym->setValidSlots(xml.readElementText().toInt());
  643. } else if (xml.name() == "validRegisters") {
  644. // read numeric valid registers mask
  645. sym->setValidRegisters(xml.readElementText().toInt());
  646. } else if (xml.name() == "source") {
  647. // read source file id
  648. int id = xml.readElementText().toInt();
  649. if (id >= 0 && id < symbolFiles.size()) {
  650. sym->setSource(&symbolFiles[id].fileName);
  651. }
  652. }
  653. }
  654. }
  655. }
  656. // class Symbol
  657. Symbol::Symbol(const QString& str, int addr, int val)
  658. : symText(str), symValue(addr), symSlots(val)
  659. {
  660. symStatus = ACTIVE;
  661. symType = JUMPLABEL;
  662. symSource = 0;
  663. if (addr & 0xFF00) {
  664. symRegisters = REG_ALL16;
  665. } else {
  666. symRegisters = REG_ALL;
  667. }
  668. table = 0;
  669. }
  670. Symbol::Symbol(const Symbol& symbol)
  671. {
  672. table = 0;
  673. symStatus = symbol.symStatus;
  674. symText = symbol.symText;
  675. symValue = symbol.symValue;
  676. symSlots = symbol.symSlots;
  677. symSegments = symbol.symSegments;
  678. symRegisters = symbol.symRegisters;
  679. symSource = symbol.symSource;
  680. symType = symbol.symType;
  681. }
  682. const QString& Symbol::text() const
  683. {
  684. return symText;
  685. }
  686. void Symbol::setText(const QString& str)
  687. {
  688. symText = str;
  689. }
  690. int Symbol::value() const
  691. {
  692. return symValue;
  693. }
  694. void Symbol::setValue(int addr)
  695. {
  696. if (addr == symValue) return;
  697. symValue = addr;
  698. if (table) table->symbolValueChanged(this);
  699. }
  700. int Symbol::validSlots() const
  701. {
  702. return symSlots;
  703. }
  704. void Symbol::setValidSlots(int val)
  705. {
  706. symSlots = val & 0xFFFF;
  707. }
  708. int Symbol::validRegisters() const
  709. {
  710. return symRegisters;
  711. }
  712. void Symbol::setValidRegisters(int regs)
  713. {
  714. symRegisters = regs;
  715. if (symValue & 0xFF00) {
  716. symRegisters &= REG_ALL16;
  717. }
  718. }
  719. const QString* Symbol::source() const
  720. {
  721. return symSource;
  722. }
  723. void Symbol::setSource(const QString* name)
  724. {
  725. symSource = name;
  726. }
  727. Symbol::SymbolStatus Symbol::status() const
  728. {
  729. return symStatus;
  730. }
  731. void Symbol::setStatus(SymbolStatus s)
  732. {
  733. symStatus = s;
  734. }
  735. Symbol::SymbolType Symbol::type() const
  736. {
  737. return symType;
  738. }
  739. void Symbol::setType(SymbolType t)
  740. {
  741. if (symType == t) return;
  742. symType = t;
  743. if (table) table->symbolTypeChanged(this);
  744. }
  745. bool Symbol::isSlotValid(const MemoryLayout* ml) const
  746. {
  747. if (!ml) return true;
  748. int page = symValue >> 14;
  749. int ps = ml->primarySlot[page] & 3;
  750. int ss = 0;
  751. if (ml->isSubslotted[page]) ss = ml->secondarySlot[page] & 3;
  752. if (symSlots & (1 << (4 * ps + ss))) {
  753. if (symSegments.empty()) return true;
  754. for (int i = 0; i < symSegments.size(); ++i) {
  755. if (ml->mapperSegment[page] == symSegments[i]) {
  756. return true;
  757. }
  758. }
  759. }
  760. return false;
  761. }