sym.c 26 KB

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