sym.c 26 KB

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