PageRenderTime 59ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/Albert/tools/db2src.cpp

http://dynee5.googlecode.com/
C++ | 2201 lines | 1864 code | 161 blank | 176 comment | 580 complexity | 28150432cea13efc628dfbd47615b426 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * db2src.cpp
  3. * Albert
  4. *
  5. * Created by Matthias Melcher on 08.11.09.
  6. * Copyright 2009 __MyCompanyName__. All rights reserved.
  7. *
  8. */
  9. //#define VERBOSE
  10. #if VERBOSE
  11. #define VERB1
  12. #define VERB2
  13. #define VERB3
  14. #define VERB4
  15. #define VERB5 if (0)
  16. #else
  17. #define VERB1
  18. #define VERB2
  19. #define VERB3 if (0)
  20. #define VERB4 if (0)
  21. #define VERB5 if (0)
  22. #endif
  23. #if 1
  24. #define ABORT_SCAN return
  25. #define ABORT_SCAN_0 return 0
  26. #else
  27. #define ABORT_SCAN throw "ERROR: aborting scan"
  28. #define ABORT_SCAN_0 throw "ERROR: aborting scan"
  29. #endif
  30. #include "Albert.h"
  31. #include "db2src.h"
  32. #include "decomp.h"
  33. #include <stdio.h>
  34. #include <unistd.h>
  35. #include <string.h>
  36. #include <ctype.h>
  37. #include <stdlib.h>
  38. #include <map>
  39. #define BDISP(x) ((((x) & 0xffffff) ^ 0x800000) - 0x800000) /* 26 bit */
  40. extern int disarm(char *dst, unsigned int addr, unsigned int cmd);
  41. extern int disarm_c(char *dst, unsigned int addr, unsigned int cmd);
  42. extern const char *getSymbol(unsigned int i);
  43. extern const char *getSafeSymbol(unsigned int i);
  44. //const char *db_path = "./";
  45. const char *db_path = "/Users/matt/dev/Albert/";
  46. const char *src_path = "src/";
  47. const char *c_path = "src/";
  48. const char *cpp_path = "src/";
  49. const char *os_path = "NewtonOS/";
  50. const unsigned int flags_type_mask = 0x000000ff;
  51. const unsigned int flags_type_unknown = 0x00000000;
  52. const unsigned int flags_type_arm_code = 0x00000001;
  53. const unsigned int flags_type_arm_byte = 0x00000002;
  54. const unsigned int flags_type_arm_word = 0x00000003;
  55. const unsigned int flags_type_arm_text = 0x00000004;
  56. const unsigned int flags_type_patch_table = 0x00000005;
  57. const unsigned int flags_type_jump_table = 0x00000006;
  58. const unsigned int flags_type_unused = 0x00000007;
  59. const unsigned int flags_type_rex = 0x00000008;
  60. const unsigned int flags_type_ns = 0x00000009;
  61. const unsigned int flags_type_ns_obj = 0x0000000a;
  62. const unsigned int flags_type_ns_ref = 0x0000000b;
  63. const unsigned int flags_type_dict = 0x0000000c;
  64. const unsigned int flags_type_classinfo = 0x0000000d;
  65. const unsigned int flags_type_arm_wtext = 0x0000000e;
  66. const unsigned int flags_type_data = 0x0000000f;
  67. const unsigned int flags_is_function = 0x30000000;
  68. const unsigned int flags_is_target = 0x10000000;
  69. const unsigned int flags_walked = 0x40000000;
  70. const char *type_lut[] = {
  71. "flags_type_unknown",
  72. "flags_type_arm_code",
  73. "flags_type_arm_byte",
  74. "flags_type_arm_word",
  75. "flags_type_arm_text",
  76. "flags_type_patch_table",
  77. "flags_type_jump_table",
  78. "flags_type_unused",
  79. "flags_type_rex",
  80. "flags_type_ns",
  81. "flags_type_ns_obj",
  82. "flags_type_ns_ref",
  83. "flags_type_dict",
  84. "flags_type_classinfo",
  85. "flags_type_arm_wtext",
  86. "flags_type_data",
  87. };
  88. unsigned char ROM[0x00800000];
  89. unsigned int ROM_flags[0x00200000];
  90. typedef std::multimap < unsigned int, unsigned int > AlCallGraph;
  91. typedef std::multimap < unsigned int, unsigned int >::iterator AlCallGraphIterator;
  92. AlCallGraph callGraph;
  93. typedef std::multimap < unsigned int, const char* > AlROMComment;
  94. typedef std::multimap < unsigned int, const char* >::iterator AlROMCommentIterator;
  95. typedef std::pair<AlROMCommentIterator,AlROMCommentIterator> AlROMCommentIteratorPair;
  96. AlROMComment ROMComment;
  97. unsigned char printable(unsigned char c) { return (c>32&&c<127)?c:'.'; }
  98. const char *p_ascii(unsigned char c)
  99. {
  100. static char buf[8];
  101. switch (c) {
  102. case 8: return "\\b";
  103. case 9: return "\\t";
  104. case 10: return "\\n";
  105. case 12: return "\\bf";
  106. case 13: return "\\r";
  107. case '"': return "\\\"";
  108. case '@': return "\\x40";
  109. case '\\': return "\\\\";
  110. }
  111. // 48:16 56:8 60:4 62:2
  112. if (c>=' ' && c<=126) {
  113. buf[0] = c; buf[1] = 0; return buf;
  114. }
  115. sprintf(buf, "\\%03o", c);
  116. return buf;
  117. }
  118. const char *four_cc(unsigned int x)
  119. {
  120. static char buf[5];
  121. unsigned char c = x>>24;
  122. buf[0] = (c>31 && c<127) ? c : '.';
  123. c = x>>16;
  124. buf[1] = (c>31 && c<127) ? c : '.';
  125. c = x>>8;
  126. buf[2] = (c>31 && c<127) ? c : '.';
  127. c = x;
  128. buf[3] = (c>31 && c<127) ? c : '.';
  129. buf[4] = 0;
  130. return buf;
  131. }
  132. void AsmFlush(FILE *f, const char *buf)
  133. {
  134. char dbuf[2048];
  135. // manipulate the buffer so that all comments are either starting at column 0
  136. // or at column 48 if possible
  137. const char *s = buf;
  138. char *d = dbuf;
  139. int col=0, t=0, x=0;
  140. // walk to the comment character
  141. for (;;) {
  142. char c = *s;
  143. switch (c) {
  144. case 0: *d=0; x=1; break;
  145. case '@': x=1; break;
  146. case '\t': *d++=c; col = (col+8) & 0xfff8; s++; break;
  147. case ' ': *d++=c; col++; s++; break;
  148. default: *d++=c; col++; t=1; s++; break;
  149. }
  150. if (x) break;
  151. }
  152. // handle a comment if there is one
  153. if (*s=='@') {
  154. if (t) {
  155. // we have text, set the comment at col 48
  156. while (col<48) {
  157. *d++ = '\t';
  158. col = (col+8) & 0xfff8;
  159. }
  160. strcpy(d, s); // append the comment to the line
  161. } else {
  162. // no text yet: move the comment to the start
  163. strcpy(dbuf, s); // simply move the text to the start of the line
  164. }
  165. }
  166. fputs(dbuf, f);
  167. }
  168. void AsmPrintf(FILE *f, const char *pat, ...)
  169. {
  170. static char buf[2048];
  171. static char *dst = buf;
  172. // concatenate segments until we can flush an entire line
  173. va_list va;
  174. va_start(va, pat);
  175. vsnprintf(dst, 2048, pat, va);
  176. va_end(va);
  177. dst = buf + strlen(buf);
  178. if (strchr(buf, '\n')) {
  179. AsmFlush(f, buf);
  180. dst = buf; buf[0] = 0;
  181. }
  182. }
  183. unsigned long rotate_right(unsigned long n, unsigned long i)
  184. {
  185. return (n >> i) | (n << (32 - i));
  186. }
  187. void rom_add_comment(unsigned int addr, const char *pat, ...)
  188. {
  189. static char buf[2048];
  190. va_list va;
  191. va_start(va, pat);
  192. vsnprintf(buf, 2048, pat, va);
  193. va_end(va);
  194. ROMComment.insert(std::make_pair(addr, strdup(buf)));
  195. }
  196. /**
  197. * Return the 4-byte word in rom
  198. */
  199. unsigned int rom_w(unsigned int addr)
  200. {
  201. if (addr>=0x00800000)
  202. return 0;
  203. else
  204. return (ROM[addr]<<24)|(ROM[addr+1]<<16)|(ROM[addr+2]<<8)|ROM[addr+3];
  205. }
  206. /**
  207. * Return a 8-byte real (double prcision floating point) in rom
  208. */
  209. double rom_real(unsigned int addr)
  210. {
  211. union { unsigned char c[8]; double v; };
  212. if (addr>=0x00800000)
  213. return 0.0;
  214. else {
  215. int i;
  216. for (i=0; i<8; i++)
  217. c[7-i] = ROM[addr+i];
  218. return v;
  219. }
  220. }
  221. /**
  222. * Return a 8-byte double form a fixed decimal point 4 byte variable
  223. */
  224. double rom_fixed(unsigned int addr)
  225. {
  226. int si = (signed int)rom_w(addr);
  227. double d = si;
  228. d = d/65536.0;
  229. return d;
  230. }
  231. /**
  232. * Return the 4-byte flag for a ROM word
  233. */
  234. unsigned int rom_flags(unsigned int addr)
  235. {
  236. if (addr>=0x00800000)
  237. return 0;
  238. else
  239. return ROM_flags[addr/4];
  240. }
  241. void rom_flags_set(unsigned int addr, unsigned int f)
  242. {
  243. if (addr<0x00800000)
  244. ROM_flags[addr/4] |= f;
  245. }
  246. void rom_flags_clear(unsigned int addr, unsigned int f)
  247. {
  248. if (addr<0x00800000)
  249. ROM_flags[addr/4] &= ~f;
  250. }
  251. void rom_flags_clear_all(unsigned int f)
  252. {
  253. unsigned int i;
  254. f = ~f;
  255. for (i = 0; i<0x00200000; i++)
  256. ROM_flags[i] &= f;
  257. }
  258. char rom_flags_is_set(unsigned int addr, unsigned int f)
  259. {
  260. if (addr>=0x00800000) return 0;
  261. return ((ROM_flags[addr/4]&f) == f);
  262. }
  263. void rom_flags_type(unsigned int addr, unsigned int t)
  264. {
  265. if (addr<0x00800000)
  266. ROM_flags[addr/4] = (ROM_flags[addr/4]&~flags_type_mask) | t;
  267. }
  268. void rom_flags_type(unsigned int addr, unsigned int end, unsigned int t)
  269. {
  270. rom_flags_set(addr, flags_is_target);
  271. for ( ; addr<end; addr++)
  272. rom_flags_type(addr, t);
  273. }
  274. unsigned int rom_flags_type(unsigned int addr)
  275. {
  276. if (addr<0x00800000)
  277. return (ROM_flags[addr/4]&flags_type_mask);
  278. else
  279. return 0;
  280. }
  281. class AlClass;
  282. class AlArg;
  283. class AlMemberFunction;
  284. //typedef std::map < unsigned int, const char* > OldSymbolList;
  285. //OldSymbolList symbolList, plainSymbolList;
  286. const char *get_symbol_at(unsigned int addr)
  287. {
  288. // FIXME: this should return the CPP decoded function call
  289. AlData *data = gMemoryMap.find(addr);
  290. if (data) {
  291. AlCPPMethod *m = dynamic_cast<AlCPPMethod*>(data);
  292. if (m) {
  293. return m->prototype();
  294. } else {
  295. return 0L;
  296. }
  297. } else {
  298. return 0;
  299. }
  300. }
  301. const char *get_plain_symbol_at(unsigned int addr)
  302. {
  303. AlData *data = gMemoryMap.find(addr);
  304. if (data)
  305. return data->label();
  306. else
  307. return 0;
  308. }
  309. typedef struct { const char *key; unsigned int addr; } MagicSym;
  310. MagicSym magicSym[] = {
  311. #include "magics1.h"
  312. #include "magics2.h"
  313. };
  314. MagicSym unlabeledSym[] = {
  315. #include "unlabeled.h"
  316. { 0, 0 }
  317. };
  318. void readSymbols(const char *cpp_filename, const char *plain_filename)
  319. {
  320. int i;
  321. // unlabeled functions that are called from within the code
  322. for (i=0; unlabeledSym[i].key; i++) {
  323. gMemoryMap.at(unlabeledSym[i].addr)->label(unlabeledSym[i].key);
  324. }
  325. // magic pointers
  326. for (i=0; magicSym[i].key; i++) {
  327. unsigned int maddr = rom_w(0x003AF004+4*magicSym[i].addr) & 0xfffffffc;
  328. gMemoryMap.at(maddr)->label(magicSym[i].key);
  329. }
  330. // we can find many NewtonScript labels by checking Rbuiltinfunctions
  331. // do this first so that the values may be overridden later
  332. {
  333. unsigned int frame = 0x00639580;
  334. unsigned int symlist = rom_w(frame+8)&~3;
  335. unsigned int i, n = (rom_w(frame)>>10)-3;
  336. for (i=0; i<n; i++) {
  337. unsigned int addr = rom_w(frame+12+4*i);
  338. unsigned int sym = rom_w(symlist+16+4*i);
  339. if ((addr&3)==1 && (sym&3)==1) {
  340. const char *str = getSafeSymbol(symlist+16+4*i);
  341. if (str) {
  342. char buf[256];
  343. sprintf(buf, "NSFn_%s", str);
  344. gMemoryMap.at(addr&~3)->label(buf);
  345. }
  346. }
  347. }
  348. }
  349. // more from files
  350. FILE *f = fopen(cpp_filename, "rb");
  351. if (!f) {
  352. puts("ERROR opening cpp symbol file");
  353. return;
  354. }
  355. for (;;) {
  356. char buf[1024], sym[1024];
  357. unsigned int addr;
  358. char *s = fgets(buf, 1024, f);
  359. if (!s) break;
  360. int n = sscanf(s, "0x%08x %[^\n]\n", &addr, sym);
  361. if (n==2 && AlCPPMethod::isCPPLabel(sym)) {
  362. AlCPPMethod *m = new AlCPPMethod();
  363. gMemoryMap.set(addr, m);
  364. m->decodeDecoratedLabel(sym);
  365. }
  366. }
  367. f = fopen(plain_filename, "rb");
  368. if (!f) {
  369. puts("ERROR opening plain symbol file");
  370. return;
  371. }
  372. for (;;) {
  373. char buf[1024], sym[1024];
  374. unsigned int addr;
  375. char *s = fgets(buf, 1024, f);
  376. if (!s) break;
  377. int n = sscanf(s, "0x%08x %[^\n]\n", &addr, sym);
  378. if (n==2) {
  379. gMemoryMap.at(addr)->label(sym);
  380. }
  381. }
  382. }
  383. void writeSymbolStatistics(const char *filename)
  384. {
  385. FILE *st = fopen(filename, "wb");
  386. unsigned int i, pi = 0;
  387. const char *pSym = get_plain_symbol_at(0);
  388. for (i=4; i<0x00800000; i+=4) {
  389. const char *sym = get_symbol_at(i);
  390. if (!sym)
  391. sym = get_plain_symbol_at(i);
  392. if (sym) {
  393. fprintf(st, "%10d - %s\n", i-pi, pSym);
  394. pSym = sym;
  395. pi = i;
  396. }
  397. }
  398. fclose(st);
  399. }
  400. char *gComment = 0;
  401. int gnComment = 0, gNComment = 0;
  402. void addComment(const char *s)
  403. {
  404. int n = strlen(s) + gnComment + 2;
  405. if (n>gNComment) {
  406. gNComment = n+512;
  407. gComment = (char*)realloc(gComment, gNComment);
  408. }
  409. if (gComment[0]) {
  410. gComment[gnComment]='\n';
  411. strcpy(gComment+gnComment+1, s);
  412. } else {
  413. strcpy(gComment, s);
  414. }
  415. gnComment = strlen(gComment);
  416. }
  417. void clearComment()
  418. {
  419. gComment[0] = 0;
  420. gnComment = 0;
  421. }
  422. char hasComment()
  423. {
  424. return (gComment && *gComment);
  425. }
  426. const char *lastComment()
  427. {
  428. return gComment;
  429. }
  430. char *dupComment()
  431. {
  432. if (hasComment()) {
  433. char *ret = strdup(gComment);
  434. clearComment();
  435. return ret;
  436. } else {
  437. return 0;
  438. }
  439. }
  440. void printComment(FILE *f, const char *s, const char *start, const char *line=0)
  441. {
  442. if (!s || !*s) return;
  443. if (!line) line = start;
  444. fprintf(f, "%s", start);
  445. for(;;) {
  446. char c = *s++;
  447. if (c==0) break;
  448. if (c=='\n') {
  449. fprintf(f, "\n%s", line);
  450. continue;
  451. }
  452. fputc(c, f);
  453. }
  454. fprintf(f, "\n");
  455. clearComment();
  456. }
  457. /**
  458. * Skip over space characters
  459. */
  460. char *skipSpace(char *s) {
  461. while (isspace(*s)) s++;
  462. return s;
  463. }
  464. char const *skipSpace(char const *s) {
  465. while (isspace(*s)) s++;
  466. return s;
  467. }
  468. class AlCString
  469. {
  470. public:
  471. static AlCString **pCString;
  472. static int pn, pN;
  473. unsigned int pAt, pNext;
  474. const char *pSym;
  475. const char *pString;
  476. const char *pComment;
  477. public:
  478. AlCString(FILE *f) {
  479. pAt = pNext = 0xffffffff;
  480. pSym = 0;
  481. pString = 0;
  482. for (;;) {
  483. char buf[256], cmd[32], arg[256];
  484. char *s = fgets(buf, 256, f);
  485. if (*s==0) break;
  486. s = skipSpace(s);
  487. if (sscanf(s, "%s", cmd)==0) continue;
  488. if (strcmp(cmd, "end")==0) {
  489. break;
  490. } else if (strcmp(cmd, "//")==0) {
  491. int sn = strlen(s);
  492. if (s[sn-1]=='\n') s[sn-1]=0;
  493. addComment(s+2);
  494. } else if (strcmp(cmd, "at")==0) {
  495. sscanf(s, "%s 0x%08x", cmd, &pAt);
  496. } else if (strcmp(cmd, "next")==0) {
  497. sscanf(s, "%s 0x%08x", cmd, &pNext);
  498. } else if (strcmp(cmd, "sym")==0) {
  499. sscanf(s, "%s %s", cmd, arg);
  500. pSym = strdup(arg);
  501. pComment = dupComment();
  502. } else {
  503. printf("WARNING: unsupported CString attribute '%s'\n", cmd);
  504. }
  505. }
  506. add(this);
  507. }
  508. void write_h(FILE *f) {
  509. // write the doxygen commentary
  510. if (pComment) {
  511. fprintf(f, "\n/**\n");
  512. printComment(f, pComment, " * ");
  513. fprintf(f, " *\n");
  514. }
  515. // write cstring header
  516. fprintf(f, "extern const char *%s;\n", pSym);
  517. }
  518. void write_c(FILE *f) {
  519. int i, last, x = 0;
  520. // write the C++ function
  521. fprintf(f, "const char *%s = \n \"", pSym);
  522. for (last=pNext-1; last>pAt; last--) {
  523. if (ROM[last]) break;
  524. }
  525. for (i=pAt; i<=last; i++,x++) {
  526. if (x==63) { fprintf(f, "\"\n \""); x=0; }
  527. char c = ROM[i];
  528. if (c==0) fprintf(f, "\\0");
  529. else if (c=='\n') fprintf(f, "\\n");
  530. else if (c=='\r') fprintf(f, "\\r");
  531. else if (c=='"') fprintf(f, "\\\"");
  532. else if (c=='\\') fprintf(f, "\\\\");
  533. else if (c<32 || c>126) fprintf(f, "\\%03o", (unsigned char)c);
  534. else fputc(c, f);
  535. }
  536. fprintf(f, "\";\n");
  537. }
  538. static AlCString *add(AlCString *str) {
  539. if (pn==pN) {
  540. pN += 100;
  541. pCString = (AlCString**)realloc(pCString, sizeof(AlCString**)*pN);
  542. }
  543. pCString[pn++] = str;
  544. return str;
  545. }
  546. static void write_all_h(FILE *f) {
  547. int i;
  548. for (i=0; i<pn; i++)
  549. pCString[i]->write_h(f);
  550. }
  551. static void write_all_c(FILE *f) {
  552. int i;
  553. for (i=0; i<pn; i++)
  554. pCString[i]->write_c(f);
  555. }
  556. };
  557. AlCString **AlCString::pCString;
  558. int AlCString::pn, AlCString::pN;
  559. class AlClass
  560. {
  561. public:
  562. static AlClass **pClass;
  563. static int pn, pN;
  564. const char *pSym;
  565. const char *pBaseClass;
  566. AlMemberFunction *pFn[200];
  567. int pnf;
  568. public:
  569. static AlClass *find(char const *sym) {
  570. int i;
  571. for (i=0; i<pn; i++) {
  572. if (strcmp(sym, pClass[i]->pSym)==0)
  573. return pClass[i];
  574. }
  575. if (pn==pN) {
  576. pN += 100;
  577. pClass = (AlClass**)realloc(pClass, sizeof(AlClass**)*pN);
  578. }
  579. AlClass *c = new AlClass(sym);
  580. pClass[pn++] = c;
  581. return c;
  582. }
  583. static void load(FILE *f) {
  584. AlClass *ac = 0L;
  585. for (;;) {
  586. char buf[256], cmd[32], arg[256];
  587. char *s = fgets(buf, 256, f);
  588. if (*s==0) break;
  589. s = skipSpace(s);
  590. if (sscanf(s, "%s", cmd)==0) continue;
  591. if (strcmp(cmd, "end")==0) {
  592. break;
  593. } else if (strcmp(cmd, "sym")==0) {
  594. sscanf(s, "%s %s", cmd, arg);
  595. ac = find(arg);
  596. } else if (strcmp(cmd, "base")==0) {
  597. sscanf(s, "%s %s", cmd, arg);
  598. if (strcmp(arg, "FIXME")!=0) {
  599. if (ac) ac->base_class(arg);
  600. }
  601. } else if (strcmp(cmd, "size")==0) {
  602. } else if (strcmp(cmd, "datac")==0) {
  603. } else if (strcmp(cmd, "data")==0) {
  604. } else if (strcmp(cmd, "file")==0) {
  605. } else if (strcmp(cmd, "//")==0) {
  606. } else if (strcmp(cmd, "#")==0) {
  607. } else {
  608. printf("WARNING: unsupported member function attribute '%s'\n", cmd);
  609. }
  610. }
  611. }
  612. static void write_all(char const *path) {
  613. int i;
  614. for (i=0; i<pn; i++) {
  615. pClass[i]->write(path);
  616. }
  617. }
  618. void init() {
  619. pSym = 0;
  620. pBaseClass = 0;
  621. pnf = 0;
  622. }
  623. AlClass(char const *sym) {
  624. init();
  625. pSym = strdup(sym);
  626. }
  627. void add(AlMemberFunction *fn) {
  628. if (pnf>=200) puts("Out of bounds!");
  629. pFn[pnf++] = fn;
  630. }
  631. void base_class(const char *name) {
  632. pBaseClass = strdup(name);
  633. }
  634. const char *base_class() {
  635. return pBaseClass;
  636. }
  637. void write_h(char const *path);
  638. void write_cpp(char const *path);
  639. void write(char const *path) {
  640. write_h(path);
  641. write_cpp(path);
  642. }
  643. };
  644. AlClass **AlClass::pClass;
  645. int AlClass::pn, AlClass::pN;
  646. class AlArg
  647. {
  648. public:
  649. const char *pType;
  650. const char *pSym;
  651. const char *pComment;
  652. public:
  653. AlArg(char *cmd) {
  654. pType = 0;
  655. pSym = 0;
  656. pComment = 0;
  657. char *type = cmd, *sym = 0, *cmt = 0;
  658. cmt = strstr(type, "//");
  659. if (cmt) { *cmt = 0; cmt+=2; }
  660. sym = strchr(type, '/');
  661. if (sym && sym[1]!='/') { *sym = 0; sym++; }
  662. if (type) pType = strdup(type);
  663. if (sym) pSym = strdup(sym);
  664. if (cmt)
  665. pComment = strdup(cmt);
  666. else
  667. pComment = dupComment();
  668. }
  669. void write_h(FILE *f, int i) {
  670. if (pSym) {
  671. fprintf(f, "%s %s", pType, pSym);
  672. } else {
  673. fprintf(f, "%s arg%d", pType, i);
  674. }
  675. }
  676. void write_c(FILE *f, int i) {
  677. if (pSym) {
  678. fprintf(f, "%s %s", pType, pSym);
  679. } else {
  680. fprintf(f, "%s arg%d", pType, i);
  681. }
  682. }
  683. void write_doxy(FILE *f, int i) {
  684. if (pSym) {
  685. fprintf(f, " * \\param %s", pSym);
  686. } else {
  687. fprintf(f, " * \\param arg%d", i);
  688. }
  689. if (pComment)
  690. printComment(f, pComment, " ", " * ");
  691. else
  692. fprintf(f, "\n");
  693. }
  694. };
  695. class AlMemberFunction
  696. {
  697. public:
  698. unsigned int pAt, pNext;
  699. const char *pSym;
  700. const char *pReturns;
  701. const char *pComment;
  702. AlClass *pClass;
  703. AlArg **pArg;
  704. int pnArg;
  705. char pIsStatic, pIsConst, pIsCtor, pIsDtor;
  706. public:
  707. AlMemberFunction(FILE *f) {
  708. pAt = pNext = 0xffffffff;
  709. pSym = 0;
  710. pReturns = 0;
  711. pComment = 0;
  712. pClass = 0;
  713. pArg = 0;
  714. pnArg = 0;
  715. pIsStatic = pIsConst = pIsCtor = pIsDtor = 0;
  716. for (;;) {
  717. char buf[256], cmd[32], arg[256];
  718. char *s = fgets(buf, 256, f);
  719. if (*s==0) break;
  720. s = skipSpace(s);
  721. if (sscanf(s, "%s", cmd)==0) continue;
  722. if (strcmp(cmd, "end")==0) {
  723. break;
  724. } else if (strcmp(cmd, "//")==0) {
  725. int sn = strlen(s);
  726. if (s[sn-1]=='\n') s[sn-1]=0;
  727. addComment(s+2);
  728. } else if (strcmp(cmd, "at")==0) {
  729. sscanf(s, "%s 0x%08x", cmd, &pAt);
  730. } else if (strcmp(cmd, "next")==0) {
  731. sscanf(s, "%s 0x%08x", cmd, &pNext);
  732. } else if (strcmp(cmd, "static")==0) {
  733. pIsStatic = 1;
  734. } else if (strcmp(cmd, "const")==0) {
  735. pIsConst = 1;
  736. } else if (strcmp(cmd, "sym")==0) {
  737. sscanf(s, "%s %s", cmd, arg);
  738. pSym = strdup(arg);
  739. pComment = dupComment();
  740. if (strcmp(pSym, pClass->pSym)==0)
  741. pIsCtor = 1;
  742. if (pSym[0]=='~' && strcmp(pSym+1, pClass->pSym)==0)
  743. pIsDtor = 1;
  744. } else if (strcmp(cmd, "returns")==0) {
  745. sscanf(s, "%s %[^\n]", cmd, arg);
  746. if (strcmp(arg, "FIXME")==0) {
  747. if (pIsCtor || pIsDtor)
  748. pReturns = 0;
  749. else
  750. pReturns = strdup("t_unknown");
  751. } else if (strcmp(arg, "NONE")==0) {
  752. pReturns = 0;
  753. } else {
  754. pReturns = strdup(arg);
  755. }
  756. //pReturnComment = dupComment();
  757. } else if (strcmp(cmd, "argc")==0) {
  758. sscanf(s, "%s %d", cmd, &pnArg);
  759. pArg = (AlArg**)calloc(sizeof(AlArg**), pnArg);
  760. } else if (strcmp(cmd, "arg")==0) {
  761. int l = strlen(s); if (s[l-1]=='\n') s[l-1] = 0;
  762. int ix;
  763. sscanf(s, "%s %d", cmd, &ix);
  764. s = strchr(s, ' '); if (!s) continue;
  765. s = strchr(s+1, ' '); if (!s) continue;
  766. pArg[ix] = new AlArg(s+1);
  767. } else if (strcmp(cmd, "class")==0) {
  768. sscanf(s, "%s %s", cmd, arg);
  769. AlClass *c = AlClass::find(arg);
  770. pClass = c; c->add(this);
  771. } else {
  772. printf("WARNING: unsupported member function attribute '%s'\n", cmd);
  773. }
  774. }
  775. }
  776. void write_h(FILE *f) {
  777. int i;
  778. // write function header
  779. fprintf(f, " ");
  780. if (pIsStatic)
  781. fprintf(f, "static ");
  782. if (pReturns)
  783. fprintf(f, "%s ", pReturns);
  784. fprintf(f, "%s(", pSym);
  785. for (i=0; i<pnArg; i++) {
  786. if (i>0) fprintf(f, ", ");
  787. pArg[i]->write_h(f, i);
  788. }
  789. fprintf(f, ")");
  790. if (pIsConst)
  791. fprintf(f, " const");
  792. fprintf(f, ";\n");
  793. }
  794. void write_cpp(FILE *f) {
  795. int i;
  796. // write the doxygen commentary
  797. fprintf(f, "/**\n");
  798. if (pComment)
  799. printComment(f, pComment, " * ");
  800. else
  801. fprintf(f, " * Member function %s of class %s.\n", pSym, pClass->pSym);
  802. fprintf(f, " *\n");
  803. for (i=0; i<pnArg;i++) {
  804. pArg[i]->write_doxy(f, i);
  805. }
  806. if (pReturns) {
  807. fprintf(f, " * \\returns %s\n", pReturns);
  808. }
  809. fprintf(f, " */\n");
  810. // write the C++ function
  811. if (pReturns)
  812. fprintf(f, "%s ", pReturns);
  813. fprintf(f, "%s::%s(", pClass->pSym, pSym);
  814. for (i=0; i<pnArg; i++) {
  815. if (i>0) fprintf(f, ", ");
  816. pArg[i]->write_c(f, i);
  817. }
  818. fprintf(f, ")");
  819. if (pIsConst)
  820. fprintf(f, " const");
  821. fprintf(f, "\n{\n");
  822. // find the program workflow (goto-stacking)
  823. // a typical switch-case statement starts with "add pc, pc, r#, lsl #2" = E08FF101
  824. // any register r can be used, other logical shifts have been used
  825. // "add" is followed by a "nop" because the ip is already one instruction further down
  826. // "addls" is followed by a jump to the "default" branch
  827. // find all "b" instructions and tag the branch destinations
  828. for (i=pAt; i<pNext; i+=4) {
  829. unsigned int cmd = rom_w(i);
  830. if ((cmd&0x0f000000)==0x0a000000) {
  831. rom_flags_set(BDISP(cmd)*4+i+8, 1);
  832. }
  833. }
  834. // write some simple C-style code (of course it is not real C code)
  835. for (i=pAt; i<pNext; i+=4) {
  836. char buf[256];
  837. if (rom_flags(i)&1)
  838. fprintf(f, "L%08X:\n", i);
  839. disarm_c(buf, i, rom_w(i));
  840. fprintf(f, " %s\n", buf);
  841. }
  842. fprintf(f, "}\n\n");
  843. }
  844. };
  845. void AlClass::write_h(char const *path) {
  846. char filename[2048];
  847. sprintf(filename, "%s%s.h", path, pSym);
  848. FILE *f = fopen(filename, "wb");
  849. fprintf(f, "// This file was automatically generated by Albert\n\n");
  850. fprintf(f, "#ifndef %s_H\n#define %s_H\n\n", pSym, pSym);
  851. fprintf(f, "#include \"albert/types.h\"\n\n");
  852. if (pBaseClass)
  853. fprintf(f, "class %s : public %s\n{\npublic:\n", pSym, pBaseClass);
  854. else
  855. fprintf(f, "class %s\n{\npublic:\n", pSym);
  856. int i;
  857. for (i=0; i<pnf; i++) {
  858. pFn[i]->write_h(f);
  859. }
  860. fprintf(f, "};\n\n");
  861. fprintf(f, "\n#endif\n");
  862. }
  863. void AlClass::write_cpp(char const *path) {
  864. char filename[2048];
  865. sprintf(filename, "%s%s.cpp", path, pSym);
  866. FILE *f = fopen(filename, "wb");
  867. fprintf(f, "// This file was automatically generated by Albert\n\n");
  868. fprintf(f, "#include \"%s.h\"\n\n", pSym);
  869. // FIXME insert class description and comments here
  870. int i;
  871. for (i=0; i<pnf; i++) {
  872. pFn[i]->write_cpp(f);
  873. }
  874. fprintf(f, "\n\n");
  875. }
  876. /**
  877. * Read the entire database into RAM
  878. */
  879. void load_db(char const *path, char const *filename)
  880. {
  881. printf("Reading %s...\n", filename);
  882. char name[2048];
  883. strcpy(name, path); strcat(name, filename);
  884. FILE *f = fopen(name, "rb");
  885. if (!f) {
  886. printf("ERROR: can't open database file %s\n", name);
  887. return;
  888. }
  889. while (!feof(f)) {
  890. char buf[1024], cmd[80], arg[80];
  891. char *s = fgets(buf, 1024, f);
  892. if (!s) break;
  893. s = skipSpace(s);
  894. char *hash = strchr(s, '#');
  895. if (hash) *hash = 0;
  896. if (*s==0) continue;
  897. cmd[0] = arg[0] = 0;
  898. sscanf(s, "%s %s\n", cmd, arg);
  899. if (strcmp(cmd, "import")==0) {
  900. load_db(path, arg);
  901. } else if (strcmp(cmd, "begin")==0) {
  902. if (strcmp(arg, "cpp_member_function")==0) {
  903. // create a cpp member function and read it
  904. new AlMemberFunction(f);
  905. } else if (strcmp(arg, "class")==0) {
  906. AlClass::load(f);
  907. } else if (strcmp(arg, "file")==0) {
  908. goto skip; // FIXME:
  909. } else if (strcmp(arg, "c_file")==0) {
  910. goto skip; // FIXME:
  911. } else if (strcmp(arg, "cpp_function")==0) {
  912. goto skip; // FIXME:
  913. } else if (strcmp(arg, "c_function")==0) {
  914. goto skip; // FIXME:
  915. } else if (strcmp(arg, "cstring")==0) {
  916. // create a "C"-style ASCII string
  917. new AlCString(f);
  918. } else if (strcmp(arg, "RAM")==0) {
  919. goto skip; // FIXME:
  920. } else if (strcmp(arg, "nsSymbol")==0) {
  921. goto skip; // FIXME:
  922. } else if (strcmp(arg, "data")==0) {
  923. goto skip; // FIXME:
  924. } else if (strcmp(arg, "stub")==0) {
  925. goto skip; // FIXME:
  926. } else if (strcmp(arg, "global_data")==0) {
  927. goto skip; // FIXME:
  928. } else if (strcmp(arg, "const_data")==0) {
  929. goto skip; // FIXME:
  930. } else if (strcmp(arg, "unknown")==0) {
  931. goto skip; // FIXME:
  932. } else {
  933. // skip to "end"
  934. // FIXME
  935. printf("WARNING: unsupported class '%s'\n", arg);
  936. skip:
  937. int depth = 1;
  938. for (;;) {
  939. s = fgets(buf, 1024, f);
  940. if (!s) break;
  941. s = skipSpace(s);
  942. cmd[0] = 0;
  943. sscanf(s, "%s", cmd);
  944. if (strcmp(cmd, "begin")==0) {
  945. depth++;
  946. } else if (strcmp(cmd, "end")==0) {
  947. depth--;
  948. if (depth==0)
  949. break;
  950. } else {
  951. // skip unknown command
  952. }
  953. }
  954. }
  955. } else {
  956. printf("WARNING: unsupported command '%s'\n", cmd);
  957. }
  958. }
  959. }
  960. unsigned int branch_address(unsigned int addr, unsigned int cmd=0xffffffff)
  961. {
  962. if (cmd==0xffffffff)
  963. cmd = rom_w(addr);
  964. if (cmd&0x00800000) { // jump backwards
  965. return (((cmd&0x00ffffff)|0xff000000)<<2)+addr+8;
  966. } else { // jump forward
  967. return ((cmd&0x007fffff)<<2)+addr+8;
  968. }
  969. }
  970. unsigned int branch_address_in_ROM(unsigned int addr, unsigned int cmd=0xffffffff)
  971. {
  972. unsigned int dest = branch_address(addr);
  973. if (dest>=0x01A00000 && dest<0x1D00000) {
  974. unsigned int next = ( ((dest>>5)&0xffffff80) | (dest&0x0000007f) ) - 0xCE000;
  975. dest = branch_address(dest, rom_w(next));
  976. }
  977. return dest;
  978. }
  979. void tagOffset(unsigned int addr, unsigned int cmd, unsigned int flags)
  980. {
  981. if (((cmd & 0x000f0000) == 0x000f0000) && ((cmd & 0x02000000) == 0))
  982. {
  983. int offset = cmd & 0xfff;
  984. if ((cmd & 0x00800000) == 0)
  985. offset = -offset;
  986. rom_flags_set(offset+addr+8, flags);
  987. }
  988. }
  989. void check_code_coverage(unsigned int addr, unsigned int flags=0);
  990. void check_switch_case(unsigned int addr, int n_case)
  991. {
  992. int i;
  993. printf("Switch/Case statement with %d cases starting at %08x\n", n_case, addr);
  994. for (i=0; i<n_case; i++) { // nuber of cases plus default case
  995. VERB4 printf("case %d at %08x\n", i, addr+4*i);
  996. check_code_coverage(addr+4*i, 0);
  997. }
  998. }
  999. // recursively dive into the ARM code from this point on and follow all possible
  1000. // execution paths
  1001. void check_code_coverage(unsigned int addr, unsigned int flags)
  1002. {
  1003. // mark this as jump target
  1004. if (addr<0x00800000 && flags) rom_flags_set(addr, flags); // mark this as a jump target
  1005. for(;;) {
  1006. if (addr>=0x00800000) {
  1007. // see: http://40hz.org/Pages/Newton%20Patches
  1008. if (addr>=0x01A00000 && addr<0x1D00000) {
  1009. unsigned int prev = addr;
  1010. unsigned int next = ( ((addr>>5)&0xffffff80) | (addr&0x0000007f) ) - 0xCE000;
  1011. addr = branch_address(addr, rom_w(next));
  1012. const char *prev_sym = get_symbol_at(prev);
  1013. const char *addr_sym = get_symbol_at(addr);
  1014. VERB3 printf("Redirecting call from %08x to %08x (%s->%s)\n", prev, addr, prev_sym, addr_sym);
  1015. if ( prev!=0x01bdef54 && prev!=0x01bb294c && prev!=0x01bb4a50 && prev!=0x01bdef64 && prev!=0x01b4c658
  1016. && (prev_sym==0 || addr_sym==0 || strcmp(prev_sym, addr_sym)!=0) ) {
  1017. VERB2 printf("ERROR: Symbols don't match. Verify lookup table offsets! At: 0x%08x (0x%08x)\n", prev, addr);
  1018. VERB2 printf(" (%s!=%s)\n", prev_sym, addr_sym);
  1019. return;
  1020. }
  1021. } else {
  1022. VERB2 printf("Can't follow addresses outside of ROM: %08x (%s)\n", addr, get_symbol_at(addr));
  1023. return;
  1024. }
  1025. }
  1026. // hmm, this is a dead end!
  1027. if (addr==0x0001862C) return; // FIXME: dead end!
  1028. // we verified this address already - leave
  1029. if (rom_flags_type(addr)) return;
  1030. // mark this as executable
  1031. rom_flags_type(addr, flags_type_arm_code);
  1032. // crude interpretation of commands
  1033. unsigned int cmd = rom_w(addr);
  1034. {
  1035. char buf[1024]; memset(buf, 0, 1024);
  1036. sprintf(buf, ": ");
  1037. disarm(buf+3, addr, cmd);
  1038. VERB4 puts(buf);
  1039. }
  1040. if ( (cmd&0xf0000000) == 0xf0000000) {
  1041. // special treatment for 0xf... commands
  1042. VERB1 printf("Aborting: Hit unknown command at %08x: %08x\n", addr, cmd);
  1043. return;
  1044. } else {
  1045. // ldr immediate test
  1046. if ( (cmd&0x0e5f0000) == 0x041f0000) { // test for word access inside the ROM
  1047. int offset = cmd & 0xfff;
  1048. if ((cmd & 0x00800000) == 0) offset = -offset;
  1049. VERB5 printf(" Read word at 0x%08X\n", addr+8+offset);
  1050. rom_flags_type(addr+8+offset, flags_type_arm_word);
  1051. }
  1052. // follow execution threads
  1053. if ( (cmd&0x0fefffff)==0x01a0f00e) { // quick return command (mov pc,lr)
  1054. if ( (cmd&0xf0000000)==0xe0000000) return; // unconditional - we are done, otherwise continue
  1055. } else if ( (cmd&0x0f000000) == 0x0a000000) { // jump instruction
  1056. if ( (cmd&0xf0000000) == 0xe0000000) { // unconditional
  1057. VERB3 printf("%08x: unconditional jump to %08x\n", addr, branch_address(addr));
  1058. addr = branch_address(addr);
  1059. rom_flags_set(addr, flags_is_target);
  1060. continue;
  1061. } else { // conditional, follow both branches (finsih-thread-first recursion)
  1062. unsigned int next = branch_address(addr);
  1063. VERB3 printf("%08x: conditional jump to %08x, follow later\n", addr, next);
  1064. check_code_coverage(addr+4, 0);
  1065. VERB3 printf("%08x: following up on conditional jump to %08x\n", addr, next);
  1066. addr = next;
  1067. rom_flags_set(addr, flags_is_target);
  1068. continue;
  1069. }
  1070. } else if ( (cmd&0x0f000000) == 0x0b000000) { // branch instruction, follow both branches
  1071. unsigned int next = branch_address(addr);
  1072. VERB3 printf("%08x: subroutine call to %08x, follow later\n", addr, next);
  1073. check_code_coverage(addr+4, 0);
  1074. VERB3 printf("%08x: following up on subroutine call to %08x\n", addr, next);
  1075. addr = next;
  1076. rom_flags_set(addr, flags_is_target);
  1077. continue;
  1078. } else if ( (cmd&0x0db6f000) == 0x0120f000) { // msr command does not modifiy pc
  1079. } else if ( (cmd&0x0c000000) == 0x00000000) { // data processing, only important if pc is changed
  1080. if ( (cmd&0x0000f000) == 0x0000f000) { // is the destination register the pc?
  1081. if ( (cmd&0xfffffff0) == 0x908FF100 && (rom_w(addr-4)&0xfff0f000) == 0xE3500000) {
  1082. // cmp rx, #n; addls pc, pc, rx lsl 2
  1083. // This is the pattern for a switch/case statement with default clause. A jump table of size n+1 follows.
  1084. int n_case = (rom_w(addr-4)&0x00000fff)+1, i; // FIXME: is this right?
  1085. VERB3 printf("Switch/Case statement with %d cases at %08x: %08x\n", n_case, addr, cmd);
  1086. rom_add_comment(addr, "switch/case statement (0..%d)", n_case);
  1087. addr+=4;
  1088. for (i=0; i<=n_case; i++) { // nuber of cases plus default case
  1089. if (i>0) {
  1090. rom_add_comment(addr+4*i, "case %d (0x%02X):", i-1, i-1);
  1091. } else {
  1092. rom_add_comment(addr+4*i, "default:");
  1093. }
  1094. unsigned int cmd = rom_w(addr+4*i);
  1095. if ((cmd&0x0f000000)==0x0a000000) {
  1096. unsigned int dst = BDISP(cmd)*4+(addr+4*i)+8;
  1097. if (i>0) {
  1098. rom_add_comment(dst, "switch at 0x%08X: case %d (0x%02X)", addr-4, i-1, i-1);
  1099. } else {
  1100. rom_add_comment(dst, "switch at 0x%08X: default", addr-4);
  1101. }
  1102. }
  1103. VERB4 printf("case %d at %08x\n", i-1, addr+4*i);
  1104. check_code_coverage(addr+4*i, 0);
  1105. }
  1106. return;
  1107. }
  1108. unsigned int cmd1 = rom_w(addr-4);
  1109. if ( (cmd1&0x0fffffff)==0x01A0E00F && (cmd&0xf0000000)==(cmd1&0xf0000000)) { // mov lr,pc; ...
  1110. // The return address is written into the link register, so in all probability this is a function call
  1111. VERB2 printf("Later: Register based call at %08x: %08x\n", addr, cmd);
  1112. addr += 4; continue;
  1113. }
  1114. if (addr==0x0038d9a4) { check_switch_case(0x0038d9ac, 33); return; }
  1115. if (addr==0x0038ec98) { check_switch_case(0x0038eca0, 9); return; }
  1116. if ((cmd&0xf0000000)==0xe0000000) { // always
  1117. VERB1 printf("Aborting: Data processing command modifying R15 at %08x: %08x\n", addr, cmd);
  1118. ABORT_SCAN;
  1119. } else {
  1120. addr += 4; continue;
  1121. }
  1122. }
  1123. } else if ( (cmd&0x0f000000) == 0x0e000000) { // mcr, mrc (FIXME: probably not changing pc)
  1124. } else if ( (cmd&0x0e000010) == 0x06000010) { // unknown (used to trigger interrupt, FIXME: and then?)
  1125. int i;
  1126. switch ((cmd&0x00ffff00)>>8) {
  1127. case 0: // SystemBoot
  1128. case 1: // ExitToShell
  1129. case 2: // Debugger
  1130. case 3: // DebugStr
  1131. case 4: // PublicFiller
  1132. case 7: // SendTestResults
  1133. case 8: // TapFileCntl
  1134. return;
  1135. case 5: // SystemPanic
  1136. for (i=addr+4; i<0x00800000; i++) {
  1137. rom_flags_type(i, flags_type_arm_text);
  1138. if (ROM[i]==0) break;
  1139. }
  1140. addr = (i+1+3)&0xfffffffc; // align i+1 to 4
  1141. if (rom_w(addr)==0) return;
  1142. continue;
  1143. }
  1144. VERB2 printf("Aborting: opcode 'undefined' found at %08x: %08x\n", addr, cmd);
  1145. ABORT_SCAN;
  1146. } else if ( (cmd&0x0c100000) == 0x04000000) { // str (store to memory)
  1147. } else if ( (cmd&0x0c100000) == 0x04100000) { // ldr (load from memory)
  1148. if ( (cmd&0x0000f000) == 0x0000f000) { // is the destination register the pc?
  1149. unsigned int cmd1 = rom_w(addr-4);
  1150. if ( (cmd1&0x0fffffff)==0x01A0E00F && (cmd&0xf0000000)==(cmd1&0xf0000000)) { // mov lr,pc; ...
  1151. // The return address is writte into the link register, so in all probability this is a function call
  1152. VERB2 printf("Later: Register based call at %08x: %08x\n", addr, cmd);
  1153. addr += 4; continue;
  1154. }
  1155. if ((cmd&0xf0000000)==0xe0000000) { // always
  1156. VERB1 printf("Aborting: LDR command modifying R15 at %08x: %08x\n", addr, cmd);
  1157. ABORT_SCAN;
  1158. } else {
  1159. addr += 4; continue;
  1160. }
  1161. }
  1162. tagOffset(addr, cmd, flags_is_target);
  1163. } else if ( (cmd&0x0f000000) == 0x0f000000) { // swi (software interrupt)
  1164. } else if ( (cmd&0x0e000000) == 0x0c000000) { // (coprocessor dat transfer) FIXME: may actuall tfer to pc?!
  1165. } else if ( (cmd&0x0e100000) == 0x08000000) { // stm (store multiple to memory)
  1166. } else if ( (cmd&0x0e100000) == 0x08100000) { // ldm (load from memory)
  1167. if ( (cmd&0x00008000) == 0x00008000) { // is the pc among the destination registers?
  1168. // we'll assume it's a return command
  1169. if ( (cmd&0xf0000000)==0xe0000000) return; // unconditional - we are done
  1170. // conditional - continue to check
  1171. }
  1172. } else {
  1173. VERB1 printf("Aborting: Hit unknown command at %08x: %08x\n", addr, cmd);
  1174. ABORT_SCAN;
  1175. }
  1176. }
  1177. addr += 4;
  1178. }
  1179. }
  1180. void preset_rom_use()
  1181. {
  1182. int i;
  1183. for (i=0x00002000; i<0x0001285c; i++ ) {
  1184. rom_flags_type(i, flags_type_patch_table);
  1185. }
  1186. for (i=0x00013000; i<0x00015e0c; i++ ) {
  1187. rom_flags_type(i, flags_type_jump_table);
  1188. }
  1189. for (i=0x0071fc4c; i<0x007ec7fc; i++ ) {
  1190. rom_flags_type(i, flags_type_rex);
  1191. }
  1192. for (i=0x007ec7fc; i<0x00800000; i++ ) {
  1193. rom_flags_type(i, flags_type_unused);
  1194. }
  1195. for (i=0x006853dc; i<0x0071a95c; i++ ) {
  1196. rom_flags_type(i, flags_type_dict);
  1197. }
  1198. }
  1199. void check_classinfo(unsigned int addr)
  1200. {
  1201. unsigned int i;
  1202. if (rom_w(addr)!=0xE24F0044) {
  1203. printf("ClassInfo: unsupported offset at %08x: %08x\n", addr, rom_w(addr));
  1204. return;
  1205. }
  1206. unsigned int base = addr - 0x44 + 8;
  1207. unsigned int class_name = rom_w(base+4)+base+4;
  1208. unsigned int base_class = rom_w(base+8)+base+8;
  1209. printf("class \"%s\" is derived from \"%s\"\n", ROM+class_name, ROM+base_class);
  1210. unsigned int vtbl_start = rom_w(base+16)+base+16;
  1211. unsigned int vtbl_end = rom_w(base+20)+base+20;
  1212. for (i=vtbl_start; i<vtbl_end; i+=4) {
  1213. if (rom_w(i)) check_code_coverage(i, flags_is_function);
  1214. }
  1215. if (rom_w(base+24)) check_code_coverage(base+24, flags_is_function); // sizeof
  1216. if (rom_w(base+28)) check_code_coverage(base+28, flags_is_function); // ??
  1217. if (rom_w(base+32)) check_code_coverage(base+32, flags_is_function); // ??
  1218. if (rom_w(base+36)) check_code_coverage(base+36, flags_is_function); // ctor
  1219. if (rom_w(base+40)) check_code_coverage(base+40, flags_is_function); // dtor
  1220. for (i=base; i<vtbl_end; i+=4) {
  1221. if (!rom_flags_type(i)) rom_flags_type(i, flags_type_classinfo);
  1222. }
  1223. return;
  1224. }
  1225. static unsigned int classinfo[] = {
  1226. #include "classinfo.h"
  1227. };
  1228. void check_all_classinfos()
  1229. {
  1230. int i;
  1231. for (i=0; i<sizeof(classinfo)/sizeof(unsigned int); i++) {
  1232. check_classinfo(classinfo[i]);
  1233. }
  1234. }
  1235. static unsigned int db_cpp[] = {
  1236. #include "db_cpp.h"
  1237. };
  1238. void check_all_code_coverage()
  1239. {
  1240. int i;
  1241. // all ::CLassInfo functions and structures
  1242. check_all_classinfos();
  1243. // system vectors
  1244. check_code_coverage(0x00000000, flags_is_function);
  1245. check_code_coverage(0x00000004, flags_is_function);
  1246. check_code_coverage(0x00000008, flags_is_function);
  1247. check_code_coverage(0x0000000c, flags_is_function);
  1248. check_code_coverage(0x00000010, flags_is_function);
  1249. check_code_coverage(0x00000014, flags_is_function);
  1250. check_code_coverage(0x00000018, flags_is_function);
  1251. check_code_coverage(0x0000001c, flags_is_function);
  1252. // known entry points (C++ functions)
  1253. for (i=0; i<sizeof(db_cpp)/sizeof(unsigned int); i++) {
  1254. check_code_coverage(db_cpp[i], flags_is_function);
  1255. }
  1256. // ROMBoot unclear positions
  1257. check_code_coverage(0x000188d0, 0);
  1258. // ROMPublicJumpTable
  1259. for (i=0x00013000; i<0x00015e0c; i+=4 ) {
  1260. check_code_coverage(i, flags_is_function);
  1261. }
  1262. // some jump vector table we found. These jumps all go into the ROM patch table
  1263. for (i=0x0001a618; i<0x00021438; i+=4 ) {
  1264. check_code_coverage(i, 0);
  1265. }
  1266. // some places that are not reached via static analysis
  1267. #include "manual_checks.h"
  1268. }
  1269. /*
  1270. 3a.f000: Magic Pointer Table (873 entries)
  1271. num_entries
  1272. pointer to entry[0] NSRef: Pointer
  1273. ...
  1274. 67.fa40: Binary Objects
  1275. 71.fc4c: ROM code end, beginning of REX (ROM Extension, may contain code)
  1276. */
  1277. unsigned int check_ns_obj(unsigned int addr);
  1278. void ns_print_binary(unsigned int addr, unsigned int size)
  1279. {
  1280. int i;
  1281. switch (rom_w(addr+8)) {
  1282. case 0x00055552:
  1283. printf(": Symbol '%s\n", ROM+addr+16);
  1284. break;
  1285. case 0x003c13a5:
  1286. printf(": 'string \"");
  1287. for (i=13; i<size; i+=2) putchar(ROM[addr+i]);
  1288. printf("\"\n");
  1289. i=0;
  1290. break;
  1291. }
  1292. }
  1293. void check_ns_ref(unsigned int addr, char target=1)
  1294. {
  1295. if (rom_flags_type(addr)) return;
  1296. rom_flags_type(addr, flags_type_ns_ref);
  1297. if (target) rom_flags_set(addr, flags_is_target);
  1298. unsigned int val = rom_w(addr);
  1299. if ( (val&0x00000003) == 0x00000000 ) { // Integer
  1300. int v = (int)val;
  1301. VERB3 printf("NSRef: Integer %d at %08x: %08x\n", v/4, addr, val);
  1302. // top 30 bit are a (small) integer
  1303. } else if ( (val&0x00000003) == 0x00000001 ) { // Pointer
  1304. VERB3 printf("NSRef: Pointer at %08x: %08x\n", addr, val);
  1305. check_ns_obj(val&0xfffffffc);
  1306. } else if ( (val&0x00000003) == 0x00000002 ) { // Special
  1307. // TODO: ...
  1308. if (val==0x1a) {
  1309. VERB3 printf("NSRef: TRUE %08x\n", addr);
  1310. } else if (val==0x02) {
  1311. VERB3 printf("NSRef: NIL at %08x\n", addr);
  1312. } else if (val==0x00055552) {
  1313. VERB3 printf("NSRef: symbol definition at %08x\n", addr);
  1314. } else if (val==0x32) {
  1315. VERB3 printf("NSRef: native function (?) at %08x\n", addr);
  1316. } else if ((val&0xfff0000f) == 0x0000000a ) { // Character
  1317. VERB1 printf("NSRef: Unicode Char 0x%04x at %08x\n", val, addr);
  1318. } else {
  1319. VERB3 printf("NSRef: unknown special at %08x: %08x\n", addr, val);
  1320. ABORT_SCAN;
  1321. }
  1322. } else if ( (val&0x00000003) == 0x00000003 ) { // Magic Pointer
  1323. // no need to follow, we have all magic pointers covered
  1324. VERB3 printf("NSRef: Magic %d:%d at %08x: %08x\n", (val&0xffffc000)>>14, (val&0x00003ffc)>>2, addr, val);
  1325. }
  1326. }
  1327. unsigned int check_ns_obj(unsigned int addr)
  1328. {
  1329. unsigned int val = rom_w(addr);
  1330. unsigned int flags = rom_w(addr+4);
  1331. if ( (val&0x0000007c) != 0x00000040 || flags!=0 ) {
  1332. VERB1 printf("int: not an NS object at %08x: %08x\n", addr, val);
  1333. ABORT_SCAN_0;
  1334. }
  1335. unsigned int i, size = (val&0xffffff00)>>8;
  1336. if (rom_flags_type(addr)) return size;
  1337. rom_flags_type(addr, flags_type_ns_obj);
  1338. rom_flags_type(addr+4, flags_type_ns);
  1339. rom_flags_set(addr, flags_is_target);
  1340. // follow the members of the object
  1341. if ( (val&0x00000003) == 0x00000000 ) {
  1342. // binary object
  1343. VERB3 printf("NS Binary Object at %08x (%d bytes):\n", addr, size);
  1344. check_ns_ref(addr+8, 0);
  1345. // mark the binary part as checked
  1346. for (i=12; i<size; i+=4) rom_flags_type(addr+i, flags_type_ns);
  1347. VERB4 ns_print_binary(addr, size);
  1348. // followed by binary data and optional fill bytes
  1349. } else if ( (val&0x00000003) == 0x00000001 ) {
  1350. // array
  1351. VERB3 printf("NS Array at %08x (%d bytes = %d entries):\n", addr, size, size/4-3);
  1352. VERB3 printf("class: %08x\n", rom_w(addr+8));
  1353. for (i=12; i<size; i+=4) {
  1354. VERB3 printf("%5d: %08x\n", i/4-3, rom_w(addr+i));
  1355. }
  1356. for (i=8; i<size; i+=4) {
  1357. check_ns_ref(addr+i, 0);
  1358. }
  1359. } else if ( (val&0x00000003) == 0x00000003 ) {
  1360. // frame
  1361. VERB3 printf("NS Frame at %08x (%d bytes = %d entries):\n", addr, size, size/4-3);
  1362. VERB3 printf(" map: %08x\n", rom_w(addr+8));
  1363. for (i=12; i<size; i+=4) {
  1364. VERB3 printf("%5d: %08x\n", i/4-3, rom_w(addr+i));
  1365. }
  1366. for (i=8; i<size; i+=4) {
  1367. check_ns_ref(addr+i, 0);
  1368. }
  1369. } else {
  1370. VERB1 printf("ERROR: unsupported NS object at %08x: %08x\n", addr, val);
  1371. ABORT_SCAN_0;
  1372. }
  1373. return size;
  1374. }
  1375. void check_all_ns_coverage()
  1376. {
  1377. int i;
  1378. // 0x0068068C
  1379. // array of asm/NS pointers. Why are they ordered like this?
  1380. // these are always two words:
  1381. // the first word, Rlabel, is a NSRef
  1382. // the second word, RSlabel, is always an asm pointer to the previous word
  1383. for (i=0x0067fa44; i<0x00681c9c; i+=8) {
  1384. check_ns_ref(i);
  1385. }
  1386. // simple pointers, but what are they used for?
  1387. for (i=0x00681c9c; i<0x006853dc; i+=8) {
  1388. check_ns_ref(i);
  1389. }
  1390. int n_magic = rom_w(0x003af000);
  1391. for (i=0; i<n_magic; i++) {
  1392. check_ns_ref(0x003af004+4*i, 0);
  1393. }
  1394. // 0x003afda8 gROMSoupData to 0x0067FA40 gROMSoupDataSize
  1395. for (i=0x003afda8; i<0x0067fa40; ) {
  1396. unsigned int size = check_ns_obj(i);
  1397. if (size>0) {
  1398. i+=(size+3)&0xfffffffc; // align to four bytes
  1399. } else {
  1400. VERB1 printf("ERROR: lost track of NS objects at %08x!\n", i);
  1401. ABORT_SCAN;
  1402. }
  1403. }
  1404. }
  1405. // Dictionaries starting at 0x006853DC (InitROMDictionaryData)
  1406. void writeNewtonROMTexts()
  1407. {
  1408. printf("\n====> Writing all Newton ROM ASCII text entries\n\n");
  1409. unsigned int i;
  1410. FILE *text = fopen("/Users/matt/dev/Albert/data/text.txt", "wb");
  1411. if (!text) {
  1412. puts("Can't write text!");
  1413. } else {
  1414. int j, n = 0;
  1415. for (i=0; i<0x00800000; i+=4) {
  1416. if (rom_flags_type(i)==flags_type_arm_text) {
  1417. for (j=0; j<4; j++) {
  1418. if (n==0) {
  1419. fprintf(text, "0x%08x: \"", i+j);
  1420. n = 1;
  1421. }
  1422. char c = ROM[i+j];
  1423. if (c==0) {
  1424. fprintf(text, "\\0\"\n");
  1425. n = 0;
  1426. } else if (c<' ') {
  1427. fprintf(text, "\\%c", c+96); // FIXME: lookup table needed
  1428. } else if (c>=127) {
  1429. fprintf(text, "\\x%2x", c);
  1430. } else {
  1431. fputc(c, text);
  1432. }
  1433. }
  1434. }
  1435. }
  1436. fclose(text);
  1437. }
  1438. }
  1439. char hasLabel(unsigned int i)
  1440. {
  1441. if (rom_flags_is_set(i, flags_is_target)) {
  1442. return 1;
  1443. }
  1444. if (get_plain_symbol_at(i)) {
  1445. return 1;
  1446. }
  1447. if (get_symbol_at(i)) {
  1448. return 1;
  1449. }
  1450. return 0;
  1451. }
  1452. void writeLabel(FILE *newt, unsigned int i)
  1453. {
  1454. const char *sym = get_symbol_at(i);
  1455. const char *psym = get_plain_symbol_at(i);
  1456. if (psym && sym) {
  1457. AsmPrintf(newt, "\n");
  1458. AsmPrintf(newt, "%s:\t 0x%08X: %s\n", psym, i, sym);
  1459. } else if (psym) {
  1460. AsmPrintf(newt, "\n");
  1461. AsmPrintf(newt, "%s:\n", psym);
  1462. } else if (sym) {
  1463. AsmPrintf(newt, "L%08X:\t@ %s\n", i, sym);
  1464. } else if (rom_flags_is_set(i, flags_is_target)) {
  1465. AsmPrintf(newt, "L%08X:\n", i);
  1466. }
  1467. }
  1468. /*
  1469. Write a numeric label, only if the function above did not write a label yet.
  1470. */
  1471. void writeLabelIfNone(FILE *newt, unsigned int i)
  1472. {
  1473. const char *sym = get_symbol_at(i);
  1474. const char *psym = get_plain_symbol_at(i);
  1475. if (psym || sym) {
  1476. } else if (rom_flags_is_set(i, flags_is_target)) {
  1477. } else {
  1478. AsmPrintf(newt, "L%08X:\n", i);
  1479. }
  1480. }
  1481. void writeComments(FILE* newt, unsigned int i)
  1482. {
  1483. AlROMCommentIterator it;
  1484. AlROMCommentIteratorPair its = ROMComment.equal_range(i);
  1485. for (it = its.first; it!=its.second; ++it) {
  1486. const char *rem = (*it).second;
  1487. if (rem)
  1488. fprintf(newt, "\t@; %s\n", rem);
  1489. }
  1490. }
  1491. void writeNewtonROM()
  1492. {
  1493. printf("\n====> Writing Newton ROM in ARM assembler code\n\n");
  1494. unsigned int i;
  1495. FILE *newt = fopen("/Users/matt/dev/Albert/NewtonOS/newtonos.s", "wb");
  1496. if (!newt) {
  1497. perror("Can't write NewtonOS!");
  1498. } else {
  1499. rom_flags_type(0x003AE204, flags_type_arm_word); // will create illegal instructions!
  1500. rom_flags_type(0x003AE20C, flags_type_arm_word);
  1501. unsigned int n_unused = 0, unused_filler = 0;
  1502. fprintf(newt, "\n\t.include\t\"macros.s\"\n\n\t.text\n\t.org\t0\n\n");
  1503. fprintf(newt, "\t.global\t_start\n_start:\n");
  1504. for (i=0; i<0x00800000; i+=4) {
  1505. unsigned int val = rom_w(i);
  1506. writeLabel(newt, i);
  1507. writeComments(newt, i);
  1508. switch (rom_flags_type(i)) {
  1509. case flags_type_unused:
  1510. if (!n_unused) unused_filler = rom_w(i);
  1511. n_unused++;
  1512. if ( (i+4)>=0x00800000
  1513. || rom_flags_type(i+4)!=flags_type_unused
  1514. || rom_w(i+4)!=unused_filler) {
  1515. AsmPrintf(newt, "\t.fill\t%d, %d, 0x%08x\n", n_unused, 4, unused_filler);
  1516. n_unused = 0;
  1517. }
  1518. break;
  1519. case flags_type_ns_ref:
  1520. i = decodeNSRef(newt, i);
  1521. break;
  1522. case flags_type_ns_obj:
  1523. i = decodeNSObj(newt, i);
  1524. break;
  1525. case flags_type_arm_code: {
  1526. AlData *d = gMemoryMap.find(i);
  1527. if (d) d->exportAsm(newt);
  1528. char buf[256];
  1529. disarm(buf, i, rom_w(i));
  1530. char *cmt = strchr(buf, ';');
  1531. if (cmt) *cmt = '@';
  1532. AsmPrintf(newt, "\t%s\n", buf);
  1533. break; }
  1534. // mcr p15, 0, r8, c1, c0, 2
  1535. // mrc p15, 0, r0, c1, c0, 0
  1536. case flags_type_arm_text: {
  1537. int n = 0;
  1538. writeLabelIfNone(newt, i);
  1539. AsmPrintf(newt, "\t.ascii\t\"");
  1540. i -= 4;
  1541. do {
  1542. i += 4; n++;
  1543. AsmPrintf(newt, "%s", p_ascii(ROM[i]));
  1544. AsmPrintf(newt, "%s", p_ascii(ROM[i+1]));
  1545. AsmPrintf(newt, "%s", p_ascii(ROM[i+2]));
  1546. AsmPrintf(newt, "%s", p_ascii(ROM[i+3]));
  1547. } while (
  1548. rom_flags_type(i+4)==flags_type_arm_text
  1549. && ROM[i] && ROM[i+1] && ROM[i+2] && ROM[i+3]
  1550. && !hasLabel(i+4)
  1551. && n<16);
  1552. AsmPrintf(newt, "\"\n");
  1553. break; }
  1554. case flags_type_patch_table:
  1555. case flags_type_jump_table: // TODO: these are jump tables! Find out how to calculate the offsets!
  1556. case flags_type_arm_byte: // TODO: currently not used
  1557. case flags_type_rex: // TODO: interprete the contents
  1558. case flags_type_ns:
  1559. case flags_type_dict:
  1560. case flags_type_classinfo: // TODO: differentiate this
  1561. AsmPrintf(newt, "\t.word\t0x%08X\t@ 0x%08X \"%c%c%c%c\" %d (%s)\n", val, i,
  1562. printable(ROM[i]), printable(ROM[i+1]), printable(ROM[i+2]), printable(ROM[i+3]),
  1563. rom_w(i), type_lut[rom_flags_type(i)]);
  1564. break;
  1565. case flags_type_data:
  1566. case flags_type_unknown:
  1567. case flags_type_arm_word:
  1568. default:
  1569. {
  1570. // if it matches a label, is it a pointer?
  1571. // if all bytes are ASCII, is it an ID?
  1572. // if it is a negative number, is it an error message?
  1573. const char *sym = 0L;
  1574. if (val) sym = get_symbol_at(val);
  1575. if (!sym) sym = "";
  1576. AsmPrintf(newt, "\t.word\t0x%08X\t@ 0x%08X \"%c%c%c%c\" %d (%s) %s?\n", val, i,
  1577. printable(ROM[i]), printable(ROM[i+1]), printable(ROM[i+2]), printable(ROM[i+3]),
  1578. rom_w(i), type_lut[rom_flags_type(i)], sym);
  1579. }
  1580. break;
  1581. }
  1582. }
  1583. // write all symbols that are not within the ROM area, but are called from ROM
  1584. f

Large files files are truncated, but you can click here to view the full file