sym.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <mach.h>
  5. #define HUGEINT 0x7fffffff
  6. #define NNAME 20 /* a relic of the past */
  7. typedef struct txtsym Txtsym;
  8. typedef struct file File;
  9. typedef struct hist Hist;
  10. struct txtsym { /* Text Symbol table */
  11. int n; /* number of local vars */
  12. Sym **locals; /* array of ptrs to autos */
  13. Sym *sym; /* function symbol entry */
  14. };
  15. struct hist { /* Stack of include files & #line directives */
  16. char *name; /* Assumes names Null terminated in file */
  17. long line; /* line # where it was included */
  18. long offset; /* line # of #line directive */
  19. };
  20. struct file { /* Per input file header to history stack */
  21. long addr; /* address of first text sym */
  22. union {
  23. Txtsym *txt; /* first text symbol */
  24. Sym *sym; /* only during initilization */
  25. };
  26. int n; /* size of history stack */
  27. Hist *hist; /* history stack */
  28. };
  29. static int debug = 0;
  30. static Sym **autos; /* Base of auto variables */
  31. static File *files; /* Base of file arena */
  32. static int fmax; /* largest file path index */
  33. static Sym **fnames; /* file names path component table */
  34. static Sym **globals; /* globals by addr table */
  35. static Hist *hist; /* base of history stack */
  36. static int isbuilt; /* internal table init flag */
  37. static long nauto; /* number of automatics */
  38. static long nfiles; /* number of files */
  39. static long nglob; /* number of globals */
  40. static long nhist; /* number of history stack entries */
  41. static long nsym; /* number of symbols */
  42. static int ntxt; /* number of text symbols */
  43. static uchar *pcline; /* start of pc-line state table */
  44. static uchar *pclineend; /* end of pc-line table */
  45. static uchar *spoff; /* start of pc-sp state table */
  46. static uchar *spoffend; /* end of pc-sp offset table */
  47. static Sym *symbols; /* symbol table */
  48. static Txtsym *txt; /* Base of text symbol table */
  49. static long txtstart; /* start of text segment */
  50. static long txtend; /* end of text segment */
  51. static void cleansyms(void);
  52. static int decodename(Biobuf*, Sym*);
  53. static short *encfname(char*);
  54. static int fline(char*, int, long, Hist*, Hist**);
  55. static void fillsym(Sym*, Symbol*);
  56. static int findglobal(char*, Symbol*);
  57. static int findlocvar(Symbol*, char *, Symbol*);
  58. static int findtext(char*, Symbol*);
  59. static int hcomp(Hist*, short*);
  60. static int hline(File*, short*, ulong*);
  61. static void printhist(char*, Hist*, int);
  62. static int buildtbls(void);
  63. static int symcomp(void*, void*);
  64. static int symerrmsg(int, char*);
  65. static int txtcomp(void*, void*);
  66. static int filecomp(void*, void*);
  67. /*
  68. * initialize the symbol tables
  69. */
  70. int
  71. syminit(int fd, Fhdr *fp)
  72. {
  73. Sym *p;
  74. int i, size;
  75. Biobuf b;
  76. if(fp->symsz == 0)
  77. return 0;
  78. if(fp->type == FNONE)
  79. return 0;
  80. cleansyms();
  81. textseg(fp->txtaddr, fp);
  82. /* minimum symbol record size = 4+1+2 bytes */
  83. symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym));
  84. if(symbols == 0) {
  85. werrstr("can't malloc %ld bytes", fp->symsz);
  86. return -1;
  87. }
  88. Binit(&b, fd, OREAD);
  89. Bseek(&b, fp->symoff, 0);
  90. nsym = 0;
  91. size = 0;
  92. for(p = symbols; size < fp->symsz; p++, nsym++) {
  93. if(Bread(&b, &p->value, sizeof(p->value)) != sizeof(p->value))
  94. return symerrmsg(sizeof(p->value), "symbol");
  95. p->value = beswal(p->value);
  96. if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
  97. return symerrmsg(sizeof(p->value), "symbol");
  98. i = decodename(&b, p);
  99. if(i < 0)
  100. return -1;
  101. size += i+sizeof(p->value)+sizeof(p->type);
  102. /* count global & auto vars, text symbols, and file names */
  103. switch (p->type) {
  104. case 'l':
  105. case 'L':
  106. case 't':
  107. case 'T':
  108. ntxt++;
  109. break;
  110. case 'd':
  111. case 'D':
  112. case 'b':
  113. case 'B':
  114. nglob++;
  115. break;
  116. case 'f':
  117. if(strcmp(p->name, ".frame") == 0) {
  118. p->type = 'm';
  119. nauto++;
  120. }
  121. else if(p->value > fmax)
  122. fmax = p->value; /* highest path index */
  123. break;
  124. case 'a':
  125. case 'p':
  126. case 'm':
  127. nauto++;
  128. break;
  129. case 'z':
  130. if(p->value == 1) { /* one extra per file */
  131. nhist++;
  132. nfiles++;
  133. }
  134. nhist++;
  135. break;
  136. default:
  137. break;
  138. }
  139. }
  140. if (debug)
  141. print("NG: %ld NT: %d NF: %d\n", nglob, ntxt, fmax);
  142. if (fp->sppcsz) { /* pc-sp offset table */
  143. spoff = (uchar *)malloc(fp->sppcsz);
  144. if(spoff == 0) {
  145. werrstr("can't malloc %ld bytes", fp->sppcsz);
  146. return -1;
  147. }
  148. Bseek(&b, fp->sppcoff, 0);
  149. i = Bread(&b, spoff, fp->sppcsz);
  150. if(i != fp->sppcsz){
  151. spoff = 0;
  152. return symerrmsg(fp->sppcsz, "sp-pc");
  153. }
  154. spoffend = spoff+fp->sppcsz;
  155. }
  156. if (fp->lnpcsz) { /* pc-line number table */
  157. pcline = (uchar *)malloc(fp->lnpcsz);
  158. if(pcline == 0) {
  159. werrstr("can't malloc %ld bytes", fp->lnpcsz);
  160. return -1;
  161. }
  162. Bseek(&b, fp->lnpcoff, 0);
  163. i = Bread(&b, pcline, fp->lnpcsz);
  164. if(i != fp->lnpcsz){
  165. pcline = 0;
  166. return symerrmsg(fp->lnpcsz, "pc-line");
  167. }
  168. pclineend = pcline+fp->lnpcsz;
  169. }
  170. return nsym;
  171. }
  172. static int
  173. symerrmsg(int n, char *table)
  174. {
  175. werrstr("can't read %d bytes of %s table", n, table);
  176. return -1;
  177. }
  178. static int
  179. decodename(Biobuf *bp, Sym *p)
  180. {
  181. char *cp;
  182. int c1, c2;
  183. int n;
  184. if((p->type & 0x80) == 0) { /* old-style, fixed length names */
  185. p->name = malloc(NNAME);
  186. if(p->name == 0) {
  187. werrstr("can't malloc %d bytes", NNAME);
  188. return -1;
  189. }
  190. if(Bread(bp, p->name, NNAME) != NNAME)
  191. return symerrmsg(NNAME, "symbol");
  192. Bseek(bp, 3, 1);
  193. return NNAME+3;
  194. }
  195. p->type &= ~0x80;
  196. if(p->type == 'z' || p->type == 'Z') {
  197. n = Bseek(bp, 0, 1);
  198. if(Bgetc(bp) < 0) {
  199. werrstr("can't read symbol name");
  200. return -1;
  201. }
  202. for(;;) {
  203. c1 = Bgetc(bp);
  204. c2 = Bgetc(bp);
  205. if(c1 < 0 || c2 < 0) {
  206. werrstr("can't read symbol name");
  207. return -1;
  208. }
  209. if(c1 == 0 && c2 == 0)
  210. break;
  211. }
  212. n = Bseek(bp, 0, 1)-n;
  213. p->name = malloc(n);
  214. if(p->name == 0) {
  215. werrstr("can't malloc %d bytes", n);
  216. return -1;
  217. }
  218. Bseek(bp, -n, 1);
  219. if(Bread(bp, p->name, n) != n) {
  220. werrstr("can't read %d bytes of symbol name", n);
  221. return -1;
  222. }
  223. } else {
  224. cp = Brdline(bp, '\0');
  225. if(cp == 0) {
  226. werrstr("can't read symbol name");
  227. return -1;
  228. }
  229. n = Blinelen(bp);
  230. p->name = malloc(n);
  231. if(p->name == 0) {
  232. werrstr("can't malloc %d bytes", n);
  233. return -1;
  234. }
  235. strcpy(p->name, cp);
  236. }
  237. return n;
  238. }
  239. /*
  240. * free any previously loaded symbol tables
  241. */
  242. static void
  243. cleansyms(void)
  244. {
  245. if(globals)
  246. free(globals);
  247. globals = 0;
  248. nglob = 0;
  249. if(txt)
  250. free(txt);
  251. txt = 0;
  252. ntxt = 0;
  253. if(fnames)
  254. free(fnames);
  255. fnames = 0;
  256. fmax = 0;
  257. if(files)
  258. free(files);
  259. files = 0;
  260. nfiles = 0;
  261. if(hist)
  262. free(hist);
  263. hist = 0;
  264. nhist = 0;
  265. if(autos)
  266. free(autos);
  267. autos = 0;
  268. nauto = 0;
  269. isbuilt = 0;
  270. if(symbols)
  271. free(symbols);
  272. symbols = 0;
  273. nsym = 0;
  274. if(spoff)
  275. free(spoff);
  276. spoff = 0;
  277. if(pcline)
  278. free(pcline);
  279. pcline = 0;
  280. }
  281. /*
  282. * delimit the text segment
  283. */
  284. void
  285. textseg(ulong base, Fhdr *fp)
  286. {
  287. txtstart = base;
  288. txtend = base+fp->txtsz;
  289. }
  290. /*
  291. * symbase: return base and size of raw symbol table
  292. * (special hack for high access rate operations)
  293. */
  294. Sym *
  295. symbase(long *n)
  296. {
  297. *n = nsym;
  298. return symbols;
  299. }
  300. /*
  301. * Get the ith symbol table entry
  302. */
  303. Sym *
  304. getsym(int index)
  305. {
  306. if(index >= 0 && index < nsym)
  307. return &symbols[index];
  308. return 0;
  309. }
  310. /*
  311. * initialize internal symbol tables
  312. */
  313. static int
  314. buildtbls(void)
  315. {
  316. int i, j, nh, ng, nt;
  317. File *f;
  318. Txtsym *tp;
  319. Hist *hp;
  320. Sym *p, **ap;
  321. if(isbuilt)
  322. return 1;
  323. isbuilt = 1;
  324. /* allocate the tables */
  325. if(nglob) {
  326. globals = malloc(nglob*sizeof(*globals));
  327. if(!globals) {
  328. werrstr("can't malloc global symbol table");
  329. return 0;
  330. }
  331. }
  332. if(ntxt) {
  333. txt = malloc(ntxt*sizeof(*txt));
  334. if (!txt) {
  335. werrstr("can't malloc text symbol table");
  336. return 0;
  337. }
  338. }
  339. fnames = malloc((fmax+1)*sizeof(*fnames));
  340. if (!fnames) {
  341. werrstr("can't malloc file name table");
  342. return 0;
  343. }
  344. memset(fnames, 0, (fmax+1)*sizeof(*fnames));
  345. files = malloc(nfiles*sizeof(*files));
  346. if(!files) {
  347. werrstr("can't malloc file table");
  348. return 0;
  349. }
  350. hist = malloc(nhist*sizeof(Hist));
  351. if(hist == 0) {
  352. werrstr("can't malloc history stack");
  353. return 0;
  354. }
  355. autos = malloc(nauto*sizeof(Sym*));
  356. if(autos == 0) {
  357. werrstr("can't malloc auto symbol table");
  358. return 0;
  359. }
  360. /* load the tables */
  361. ng = nt = nh = 0;
  362. f = 0;
  363. tp = 0;
  364. i = nsym;
  365. hp = hist;
  366. ap = autos;
  367. for(p = symbols; i-- > 0; p++) {
  368. switch(p->type) {
  369. case 'D':
  370. case 'd':
  371. case 'B':
  372. case 'b':
  373. if(debug)
  374. print("Global: %s %lux\n", p->name, p->value);
  375. globals[ng++] = p;
  376. break;
  377. case 'z':
  378. if(p->value == 1) { /* New file */
  379. if(f) {
  380. f->n = nh;
  381. f->hist[nh].name = 0; /* one extra */
  382. hp += nh+1;
  383. f++;
  384. }
  385. else
  386. f = files;
  387. f->hist = hp;
  388. f->sym = 0;
  389. f->addr = 0;
  390. nh = 0;
  391. }
  392. /* alloc one slot extra as terminator */
  393. f->hist[nh].name = p->name;
  394. f->hist[nh].line = p->value;
  395. f->hist[nh].offset = 0;
  396. if(debug)
  397. printhist("-> ", &f->hist[nh], 1);
  398. nh++;
  399. break;
  400. case 'Z':
  401. if(f && nh > 0)
  402. f->hist[nh-1].offset = p->value;
  403. break;
  404. case 'T':
  405. case 't': /* Text: terminate history if first in file */
  406. case 'L':
  407. case 'l':
  408. tp = &txt[nt++];
  409. tp->n = 0;
  410. tp->sym = p;
  411. tp->locals = ap;
  412. if(debug)
  413. print("TEXT: %s at %lux\n", p->name, p->value);
  414. if(f && !f->sym) { /* first */
  415. f->sym = p;
  416. f->addr = p->value;
  417. }
  418. break;
  419. case 'a':
  420. case 'p':
  421. case 'm': /* Local Vars */
  422. if(!tp)
  423. print("Warning: Free floating local var: %s\n",
  424. p->name);
  425. else {
  426. if(debug)
  427. print("Local: %s %lux\n", p->name, p->value);
  428. tp->locals[tp->n] = p;
  429. tp->n++;
  430. ap++;
  431. }
  432. break;
  433. case 'f': /* File names */
  434. if(debug)
  435. print("Fname: %s\n", p->name);
  436. fnames[p->value] = p;
  437. break;
  438. default:
  439. break;
  440. }
  441. }
  442. /* sort global and text tables into ascending address order */
  443. qsort(globals, nglob, sizeof(Sym*), symcomp);
  444. qsort(txt, ntxt, sizeof(Txtsym), txtcomp);
  445. qsort(files, nfiles, sizeof(File), filecomp);
  446. tp = txt;
  447. for(i = 0, f = files; i < nfiles; i++, f++) {
  448. for(j = 0; j < ntxt; j++) {
  449. if(f->sym == tp->sym) {
  450. if(debug) {
  451. print("LINK: %s to at %lux", f->sym->name, f->addr);
  452. printhist("... ", f->hist, 1);
  453. }
  454. f->txt = tp++;
  455. break;
  456. }
  457. if(++tp >= txt+ntxt) /* wrap around */
  458. tp = txt;
  459. }
  460. }
  461. return 1;
  462. }
  463. /*
  464. * find symbol function.var by name.
  465. * fn != 0 && var != 0 => look for fn in text, var in data
  466. * fn != 0 && var == 0 => look for fn in text
  467. * fn == 0 && var != 0 => look for var first in text then in data space.
  468. */
  469. int
  470. lookup(char *fn, char *var, Symbol *s)
  471. {
  472. int found;
  473. if(buildtbls() == 0)
  474. return 0;
  475. if(fn) {
  476. found = findtext(fn, s);
  477. if(var == 0) /* case 2: fn not in text */
  478. return found;
  479. else if(!found) /* case 1: fn not found */
  480. return 0;
  481. } else if(var) {
  482. found = findtext(var, s);
  483. if(found)
  484. return 1; /* case 3: var found in text */
  485. } else return 0; /* case 4: fn & var == zero */
  486. if(found)
  487. return findlocal(s, var, s); /* case 1: fn found */
  488. return findglobal(var, s); /* case 3: var not found */
  489. }
  490. /*
  491. * find a function by name
  492. */
  493. static int
  494. findtext(char *name, Symbol *s)
  495. {
  496. int i;
  497. for(i = 0; i < ntxt; i++) {
  498. if(strcmp(txt[i].sym->name, name) == 0) {
  499. fillsym(txt[i].sym, s);
  500. s->handle = (void *) &txt[i];
  501. s->index = i;
  502. return 1;
  503. }
  504. }
  505. return 0;
  506. }
  507. /*
  508. * find global variable by name
  509. */
  510. static int
  511. findglobal(char *name, Symbol *s)
  512. {
  513. int i;
  514. for(i = 0; i < nglob; i++) {
  515. if(strcmp(globals[i]->name, name) == 0) {
  516. fillsym(globals[i], s);
  517. s->index = i;
  518. return 1;
  519. }
  520. }
  521. return 0;
  522. }
  523. /*
  524. * find the local variable by name within a given function
  525. */
  526. int
  527. findlocal(Symbol *s1, char *name, Symbol *s2)
  528. {
  529. if(s1 == 0)
  530. return 0;
  531. if(buildtbls() == 0)
  532. return 0;
  533. return findlocvar(s1, name, s2);
  534. }
  535. /*
  536. * find the local variable by name within a given function
  537. * (internal function - does no parameter validation)
  538. */
  539. static int
  540. findlocvar(Symbol *s1, char *name, Symbol *s2)
  541. {
  542. Txtsym *tp;
  543. int i;
  544. tp = (Txtsym *)s1->handle;
  545. if(tp && tp->locals) {
  546. for(i = 0; i < tp->n; i++)
  547. if (strcmp(tp->locals[i]->name, name) == 0) {
  548. fillsym(tp->locals[i], s2);
  549. s2->handle = (void *)tp;
  550. s2->index = tp->n-1 - i;
  551. return 1;
  552. }
  553. }
  554. return 0;
  555. }
  556. /*
  557. * Get ith text symbol
  558. */
  559. int
  560. textsym(Symbol *s, int index)
  561. {
  562. if(buildtbls() == 0)
  563. return 0;
  564. if(index < 0 || index >= ntxt)
  565. return 0;
  566. fillsym(txt[index].sym, s);
  567. s->handle = (void *)&txt[index];
  568. s->index = index;
  569. return 1;
  570. }
  571. /*
  572. * Get ith file name
  573. */
  574. int
  575. filesym(int index, char *buf, int n)
  576. {
  577. Hist *hp;
  578. if(buildtbls() == 0)
  579. return 0;
  580. if(index < 0 || index >= nfiles)
  581. return 0;
  582. hp = files[index].hist;
  583. if(!hp || !hp->name)
  584. return 0;
  585. return fileelem(fnames, (uchar*)hp->name, buf, n);
  586. }
  587. /*
  588. * Lookup name of local variable located at an offset into the frame.
  589. * The type selects either a parameter or automatic.
  590. */
  591. int
  592. getauto(Symbol *s1, int off, int type, Symbol *s2)
  593. {
  594. Txtsym *tp;
  595. Sym *p;
  596. int i, t;
  597. if(s1 == 0)
  598. return 0;
  599. if(type == CPARAM)
  600. t = 'p';
  601. else if(type == CAUTO)
  602. t = 'a';
  603. else
  604. return 0;
  605. if(buildtbls() == 0)
  606. return 0;
  607. tp = (Txtsym *)s1->handle;
  608. if(tp == 0)
  609. return 0;
  610. for(i = 0; i < tp->n; i++) {
  611. p = tp->locals[i];
  612. if(p->type == t && p->value == off) {
  613. fillsym(p, s2);
  614. s2->handle = s1->handle;
  615. s2->index = tp->n-1 - i;
  616. return 1;
  617. }
  618. }
  619. return 0;
  620. }
  621. /*
  622. * Find text symbol containing addr; binary search assumes text array is sorted by addr
  623. */
  624. static int
  625. srchtext(long addr)
  626. {
  627. ulong val;
  628. int top, bot, mid;
  629. Sym *sp;
  630. val = addr;
  631. bot = 0;
  632. top = ntxt;
  633. for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
  634. sp = txt[mid].sym;
  635. if(val < (ulong)sp->value)
  636. top = mid;
  637. else if(mid != ntxt-1 && val >= (ulong)txt[mid+1].sym->value)
  638. bot = mid;
  639. else
  640. return mid;
  641. }
  642. return -1;
  643. }
  644. /*
  645. * Find data symbol containing addr; binary search assumes data array is sorted by addr
  646. */
  647. static
  648. int srchdata(long addr)
  649. {
  650. ulong val;
  651. int top, bot, mid;
  652. Sym *sp;
  653. bot = 0;
  654. top = nglob;
  655. val = addr;
  656. for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
  657. sp = globals[mid];
  658. if(val < (ulong)sp->value)
  659. top = mid;
  660. else if(mid < nglob-1 && val >= (ulong)globals[mid+1]->value)
  661. bot = mid;
  662. else
  663. return mid;
  664. }
  665. return -1;
  666. }
  667. /*
  668. * Find symbol containing val in specified search space
  669. * There is a special case when a value falls beyond the end
  670. * of the text segment; if the search space is CTEXT, that value
  671. * (usually etext) is returned. If the search space is CANY, symbols in the
  672. * data space are searched for a match.
  673. */
  674. int
  675. findsym(long w, int type, Symbol *s)
  676. {
  677. int i;
  678. if(buildtbls() == 0)
  679. return 0;
  680. if(type == CTEXT || type == CANY) {
  681. i = srchtext(w);
  682. if(i >= 0) {
  683. if(type == CTEXT || i != ntxt-1) {
  684. fillsym(txt[i].sym, s);
  685. s->handle = (void *) &txt[i];
  686. s->index = i;
  687. return 1;
  688. }
  689. }
  690. }
  691. if(type == CDATA || type == CANY) {
  692. i = srchdata(w);
  693. if(i >= 0) {
  694. fillsym(globals[i], s);
  695. s->index = i;
  696. return 1;
  697. }
  698. }
  699. return 0;
  700. }
  701. /*
  702. * Find the start and end address of the function containing addr
  703. */
  704. int
  705. fnbound(long addr, ulong *bounds)
  706. {
  707. int i;
  708. if(buildtbls() == 0)
  709. return 0;
  710. i = srchtext(addr);
  711. if(0 <= i && i < ntxt-1) {
  712. bounds[0] = txt[i].sym->value;
  713. bounds[1] = txt[i+1].sym->value;
  714. return 1;
  715. }
  716. return 0;
  717. }
  718. /*
  719. * get the ith local symbol for a function
  720. * the input symbol table is reverse ordered, so we reverse
  721. * accesses here to maintain approx. parameter ordering in a stack trace.
  722. */
  723. int
  724. localsym(Symbol *s, int index)
  725. {
  726. Txtsym *tp;
  727. if(s == 0 || index < 0)
  728. return 0;
  729. if(buildtbls() == 0)
  730. return 0;
  731. tp = (Txtsym *)s->handle;
  732. if(tp && tp->locals && index < tp->n) {
  733. fillsym(tp->locals[tp->n-index-1], s); /* reverse */
  734. s->handle = (void *)tp;
  735. s->index = index;
  736. return 1;
  737. }
  738. return 0;
  739. }
  740. /*
  741. * get the ith global symbol
  742. */
  743. int
  744. globalsym(Symbol *s, int index)
  745. {
  746. if(s == 0)
  747. return 0;
  748. if(buildtbls() == 0)
  749. return 0;
  750. if(index >=0 && index < nglob) {
  751. fillsym(globals[index], s);
  752. s->index = index;
  753. return 1;
  754. }
  755. return 0;
  756. }
  757. /*
  758. * find the pc given a file name and line offset into it.
  759. */
  760. long
  761. file2pc(char *file, ulong line)
  762. {
  763. File *fp;
  764. int i;
  765. long pc;
  766. ulong start, end;
  767. short *name;
  768. if(buildtbls() == 0 || files == 0)
  769. return -1;
  770. name = encfname(file);
  771. if(name == 0) { /* encode the file name */
  772. werrstr("file %s not found", file);
  773. return -1;
  774. }
  775. /* find this history stack */
  776. for(i = 0, fp = files; i < nfiles; i++, fp++)
  777. if (hline(fp, name, &line))
  778. break;
  779. free(name);
  780. if(i >= nfiles) {
  781. werrstr("line %ld in file %s not found", line, file);
  782. return -1;
  783. }
  784. start = fp->addr; /* first text addr this file */
  785. if(i < nfiles-1)
  786. end = (fp+1)->addr; /* first text addr next file */
  787. else
  788. end = 0; /* last file in load module */
  789. /*
  790. * At this point, line contains the offset into the file.
  791. * run the state machine to locate the pc closest to that value.
  792. */
  793. if(debug)
  794. print("find pc for %ld - between: %lux and %lux\n", line, start, end);
  795. pc = line2addr(line, start, end);
  796. if(pc == -1) {
  797. werrstr("line %ld not in file %s", line, file);
  798. return -1;
  799. }
  800. return pc;
  801. }
  802. /*
  803. * search for a path component index
  804. */
  805. static int
  806. pathcomp(char *s, int n)
  807. {
  808. int i;
  809. for(i = 0; i <= fmax; i++)
  810. if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0)
  811. return i;
  812. return -1;
  813. }
  814. /*
  815. * Encode a char file name as a sequence of short indices
  816. * into the file name dictionary.
  817. */
  818. static short*
  819. encfname(char *file)
  820. {
  821. int i, j;
  822. char *cp, *cp2;
  823. short *dest;
  824. if(*file == '/') /* always check first '/' */
  825. cp2 = file+1;
  826. else {
  827. cp2 = strchr(file, '/');
  828. if(!cp2)
  829. cp2 = strchr(file, 0);
  830. }
  831. cp = file;
  832. dest = 0;
  833. for(i = 0; *cp; i++) {
  834. j = pathcomp(cp, cp2-cp);
  835. if(j < 0)
  836. return 0; /* not found */
  837. dest = realloc(dest, (i+1)*sizeof(short));
  838. dest[i] = j;
  839. cp = cp2;
  840. while(*cp == '/') /* skip embedded '/'s */
  841. cp++;
  842. cp2 = strchr(cp, '/');
  843. if(!cp2)
  844. cp2 = strchr(cp, 0);
  845. }
  846. dest = realloc(dest, (i+1)*sizeof(short));
  847. dest[i] = 0;
  848. return dest;
  849. }
  850. /*
  851. * Search a history stack for a matching file name accumulating
  852. * the size of intervening files in the stack.
  853. */
  854. static int
  855. hline(File *fp, short *name, ulong *line)
  856. {
  857. Hist *hp;
  858. int offset, depth;
  859. long ln;
  860. for(hp = fp->hist; hp->name; hp++) /* find name in stack */
  861. if(hp->name[1] || hp->name[2]) {
  862. if(hcomp(hp, name))
  863. break;
  864. }
  865. if(!hp->name) /* match not found */
  866. return 0;
  867. if(debug)
  868. printhist("hline found ... ", hp, 1);
  869. /*
  870. * unwind the stack until empty or we hit an entry beyond our line
  871. */
  872. ln = *line;
  873. offset = hp->line-1;
  874. depth = 1;
  875. for(hp++; depth && hp->name; hp++) {
  876. if(debug)
  877. printhist("hline inspect ... ", hp, 1);
  878. if(hp->name[1] || hp->name[2]) {
  879. if(hp->offset){ /* Z record */
  880. offset = 0;
  881. if(hcomp(hp, name)) {
  882. if(*line <= hp->offset)
  883. break;
  884. ln = *line+hp->line-hp->offset;
  885. depth = 1; /* implicit pop */
  886. } else
  887. depth = 2; /* implicit push */
  888. } else if(depth == 1 && ln < hp->line-offset)
  889. break; /* Beyond our line */
  890. else if(depth++ == 1) /* push */
  891. offset -= hp->line;
  892. } else if(--depth == 1) /* pop */
  893. offset += hp->line;
  894. }
  895. *line = ln+offset;
  896. return 1;
  897. }
  898. /*
  899. * compare two encoded file names
  900. */
  901. static int
  902. hcomp(Hist *hp, short *sp)
  903. {
  904. uchar *cp;
  905. int i, j;
  906. short *s;
  907. cp = (uchar *)hp->name;
  908. s = sp;
  909. if (*s == 0)
  910. return 0;
  911. for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) {
  912. if(j == 0)
  913. break;
  914. if(*s == j)
  915. s++;
  916. else
  917. s = sp;
  918. }
  919. return *s == 0;
  920. }
  921. /*
  922. * Convert a pc to a "file:line {file:line}" string.
  923. */
  924. int
  925. fileline(char *str, int n, ulong dot)
  926. {
  927. long line;
  928. int top, bot, mid;
  929. File *f;
  930. *str = 0;
  931. if(buildtbls() == 0)
  932. return 0;
  933. /* binary search assumes file list is sorted by addr */
  934. bot = 0;
  935. top = nfiles;
  936. for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
  937. f = &files[mid];
  938. if(dot < f->addr)
  939. top = mid;
  940. else if(mid < nfiles-1 && dot >= (f+1)->addr)
  941. bot = mid;
  942. else {
  943. line = pc2line(dot);
  944. if(line > 0 && fline(str, n, line, f->hist, 0) >= 0)
  945. return 1;
  946. break;
  947. }
  948. }
  949. return 0;
  950. }
  951. /*
  952. * Convert a line number within a composite file to relative line
  953. * number in a source file. A composite file is the source
  954. * file with included files inserted in line.
  955. */
  956. static int
  957. fline(char *str, int n, long line, Hist *base, Hist **ret)
  958. {
  959. Hist *start; /* start of current level */
  960. Hist *h; /* current entry */
  961. int delta; /* sum of size of files this level */
  962. int k;
  963. start = base;
  964. h = base;
  965. delta = h->line;
  966. while(h && h->name && line > h->line) {
  967. if(h->name[1] || h->name[2]) {
  968. if(h->offset != 0) { /* #line Directive */
  969. delta = h->line-h->offset+1;
  970. start = h;
  971. base = h++;
  972. } else { /* beginning of File */
  973. if(start == base)
  974. start = h++;
  975. else {
  976. k = fline(str, n, line, start, &h);
  977. if(k <= 0)
  978. return k;
  979. }
  980. }
  981. } else {
  982. if(start == base && ret) { /* end of recursion level */
  983. *ret = h;
  984. return 1;
  985. } else { /* end of included file */
  986. delta += h->line-start->line;
  987. h++;
  988. start = base;
  989. }
  990. }
  991. }
  992. if(!h)
  993. return -1;
  994. if(start != base)
  995. line = line-start->line+1;
  996. else
  997. line = line-delta+1;
  998. if(!h->name)
  999. strncpy(str, "<eof>", n);
  1000. else {
  1001. k = fileelem(fnames, (uchar*)start->name, str, n);
  1002. if(k+8 < n)
  1003. sprint(str+k, ":%ld", line);
  1004. }
  1005. /**********Remove comments for complete back-trace of include sequence
  1006. * if(start != base) {
  1007. * k = strlen(str);
  1008. * if(k+2 < n) {
  1009. * str[k++] = ' ';
  1010. * str[k++] = '{';
  1011. * }
  1012. * k += fileelem(fnames, (uchar*) base->name, str+k, n-k);
  1013. * if(k+10 < n)
  1014. * sprint(str+k, ":%ld}", start->line-delta);
  1015. * }
  1016. ********************/
  1017. return 0;
  1018. }
  1019. /*
  1020. * convert an encoded file name to a string.
  1021. */
  1022. int
  1023. fileelem(Sym **fp, uchar *cp, char *buf, int n)
  1024. {
  1025. int i, j;
  1026. char *c, *bp, *end;
  1027. bp = buf;
  1028. end = buf+n-1;
  1029. for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){
  1030. c = fp[j]->name;
  1031. if(bp != buf && bp[-1] != '/' && bp < end)
  1032. *bp++ = '/';
  1033. while(bp < end && *c)
  1034. *bp++ = *c++;
  1035. }
  1036. *bp = 0;
  1037. i = bp-buf;
  1038. if(i > 1) {
  1039. cleanname(buf);
  1040. i = strlen(buf);
  1041. }
  1042. return i;
  1043. }
  1044. /*
  1045. * compare the values of two symbol table entries.
  1046. */
  1047. static int
  1048. symcomp(void *a, void *b)
  1049. {
  1050. int i;
  1051. i = (*(Sym**)a)->value - (*(Sym**)b)->value;
  1052. if (i)
  1053. return i;
  1054. return strcmp((*(Sym**)a)->name, (*(Sym**)b)->name);
  1055. }
  1056. /*
  1057. * compare the values of the symbols referenced by two text table entries
  1058. */
  1059. static int
  1060. txtcomp(void *a, void *b)
  1061. {
  1062. return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value;
  1063. }
  1064. /*
  1065. * compare the values of the symbols referenced by two file table entries
  1066. */
  1067. static int
  1068. filecomp(void *a, void *b)
  1069. {
  1070. return ((File*)a)->addr - ((File*)b)->addr;
  1071. }
  1072. /*
  1073. * fill an interface Symbol structure from a symbol table entry
  1074. */
  1075. static void
  1076. fillsym(Sym *sp, Symbol *s)
  1077. {
  1078. s->type = sp->type;
  1079. s->value = sp->value;
  1080. s->name = sp->name;
  1081. s->index = 0;
  1082. switch(sp->type) {
  1083. case 'b':
  1084. case 'B':
  1085. case 'D':
  1086. case 'd':
  1087. s->class = CDATA;
  1088. break;
  1089. case 't':
  1090. case 'T':
  1091. case 'l':
  1092. case 'L':
  1093. s->class = CTEXT;
  1094. break;
  1095. case 'a':
  1096. s->class = CAUTO;
  1097. break;
  1098. case 'p':
  1099. s->class = CPARAM;
  1100. break;
  1101. case 'm':
  1102. s->class = CSTAB;
  1103. break;
  1104. default:
  1105. s->class = CNONE;
  1106. break;
  1107. }
  1108. s->handle = 0;
  1109. }
  1110. /*
  1111. * find the stack frame, given the pc
  1112. */
  1113. long
  1114. pc2sp(ulong pc)
  1115. {
  1116. uchar *c;
  1117. uchar u;
  1118. ulong currpc;
  1119. long currsp;
  1120. if(spoff == 0)
  1121. return -1;
  1122. currsp = 0;
  1123. currpc = txtstart - mach->pcquant;
  1124. if(pc<currpc || pc>txtend)
  1125. return -1;
  1126. for(c = spoff; c < spoffend; c++) {
  1127. if (currpc >= pc)
  1128. return currsp;
  1129. u = *c;
  1130. if (u == 0) {
  1131. currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
  1132. c += 4;
  1133. }
  1134. else if (u < 65)
  1135. currsp += 4*u;
  1136. else if (u < 129)
  1137. currsp -= 4*(u-64);
  1138. else
  1139. currpc += mach->pcquant*(u-129);
  1140. currpc += mach->pcquant;
  1141. }
  1142. return -1;
  1143. }
  1144. /*
  1145. * find the source file line number for a given value of the pc
  1146. */
  1147. long
  1148. pc2line(ulong pc)
  1149. {
  1150. uchar *c;
  1151. uchar u;
  1152. ulong currpc;
  1153. long currline;
  1154. if(pcline == 0)
  1155. return -1;
  1156. currline = 0;
  1157. currpc = txtstart-mach->pcquant;
  1158. if(pc<currpc || pc>txtend)
  1159. return -1;
  1160. for(c = pcline; c < pclineend; c++) {
  1161. if(currpc >= pc)
  1162. return currline;
  1163. u = *c;
  1164. if(u == 0) {
  1165. currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
  1166. c += 4;
  1167. }
  1168. else if(u < 65)
  1169. currline += u;
  1170. else if(u < 129)
  1171. currline -= (u-64);
  1172. else
  1173. currpc += mach->pcquant*(u-129);
  1174. currpc += mach->pcquant;
  1175. }
  1176. return -1;
  1177. }
  1178. /*
  1179. * find the pc associated with a line number
  1180. * basepc and endpc are text addresses bounding the search.
  1181. * if endpc == 0, the end of the table is used (i.e., no upper bound).
  1182. * usually, basepc and endpc contain the first text address in
  1183. * a file and the first text address in the following file, respectively.
  1184. */
  1185. long
  1186. line2addr(ulong line, ulong basepc, ulong endpc)
  1187. {
  1188. uchar *c;
  1189. uchar u;
  1190. ulong currpc;
  1191. long currline;
  1192. long delta, d;
  1193. long pc, found;
  1194. if(pcline == 0 || line == 0)
  1195. return -1;
  1196. currline = 0;
  1197. currpc = txtstart-mach->pcquant;
  1198. pc = -1;
  1199. found = 0;
  1200. delta = HUGEINT;
  1201. for(c = pcline; c < pclineend; c++) {
  1202. if(endpc && currpc >= endpc) /* end of file of interest */
  1203. break;
  1204. if(currpc >= basepc) { /* proper file */
  1205. if(currline >= line) {
  1206. d = currline-line;
  1207. found = 1;
  1208. } else
  1209. d = line-currline;
  1210. if(d < delta) {
  1211. delta = d;
  1212. pc = currpc;
  1213. }
  1214. }
  1215. u = *c;
  1216. if(u == 0) {
  1217. currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
  1218. c += 4;
  1219. }
  1220. else if(u < 65)
  1221. currline += u;
  1222. else if(u < 129)
  1223. currline -= (u-64);
  1224. else
  1225. currpc += mach->pcquant*(u-129);
  1226. currpc += mach->pcquant;
  1227. }
  1228. if(found)
  1229. return pc;
  1230. return -1;
  1231. }
  1232. /*
  1233. * Print a history stack (debug). if count is 0, prints the whole stack
  1234. */
  1235. static void
  1236. printhist(char *msg, Hist *hp, int count)
  1237. {
  1238. int i;
  1239. uchar *cp;
  1240. char buf[128];
  1241. i = 0;
  1242. while(hp->name) {
  1243. if(count && ++i > count)
  1244. break;
  1245. print("%s Line: %lx (%ld) Offset: %lx (%ld) Name: ", msg,
  1246. hp->line, hp->line, hp->offset, hp->offset);
  1247. for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) {
  1248. if (cp != (uchar *)hp->name+1)
  1249. print("/");
  1250. print("%x", (*cp<<8)|cp[1]);
  1251. }
  1252. fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf));
  1253. print(" (%s)\n", buf);
  1254. hp++;
  1255. }
  1256. }
  1257. #ifdef DEBUG
  1258. /*
  1259. * print the history stack for a file. (debug only)
  1260. * if (name == 0) => print all history stacks.
  1261. */
  1262. void
  1263. dumphist(char *name)
  1264. {
  1265. int i;
  1266. File *f;
  1267. short *fname;
  1268. if(buildtbls() == 0)
  1269. return;
  1270. if(name)
  1271. fname = encfname(name);
  1272. for(i = 0, f = files; i < nfiles; i++, f++)
  1273. if(fname == 0 || hcomp(f->hist, fname))
  1274. printhist("> ", f->hist, f->n);
  1275. if(fname)
  1276. free(fname);
  1277. }
  1278. #endif