sym.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376
  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(val < sp->value)
  649. top = mid;
  650. else if(mid != ntxt-1 && val >= txt[mid+1].sym->value)
  651. bot = mid;
  652. else
  653. return mid;
  654. }
  655. return -1;
  656. }
  657. /*
  658. * Find data symbol containing addr; binary search assumes data array is sorted by addr
  659. */
  660. static int
  661. srchdata(uvlong addr)
  662. {
  663. uvlong val;
  664. int top, bot, mid;
  665. Sym *sp;
  666. bot = 0;
  667. top = nglob;
  668. val = addr;
  669. for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
  670. sp = globals[mid];
  671. if(val < sp->value)
  672. top = mid;
  673. else if(mid < nglob-1 && val >= globals[mid+1]->value)
  674. bot = mid;
  675. else
  676. return mid;
  677. }
  678. return -1;
  679. }
  680. /*
  681. * Find symbol containing val in specified search space
  682. * There is a special case when a value falls beyond the end
  683. * of the text segment; if the search space is CTEXT, that value
  684. * (usually etext) is returned. If the search space is CANY, symbols in the
  685. * data space are searched for a match.
  686. */
  687. int
  688. findsym(uvlong val, int type, Symbol *s)
  689. {
  690. int i;
  691. if(buildtbls() == 0)
  692. return 0;
  693. if(type == CTEXT || type == CANY) {
  694. i = srchtext(val);
  695. if(i >= 0) {
  696. if(type == CTEXT || i != ntxt-1) {
  697. fillsym(txt[i].sym, s);
  698. s->handle = (void *) &txt[i];
  699. s->index = i;
  700. return 1;
  701. }
  702. }
  703. }
  704. if(type == CDATA || type == CANY) {
  705. i = srchdata(val);
  706. if(i >= 0) {
  707. fillsym(globals[i], s);
  708. s->index = i;
  709. return 1;
  710. }
  711. }
  712. return 0;
  713. }
  714. /*
  715. * Find the start and end address of the function containing addr
  716. */
  717. int
  718. fnbound(uvlong addr, uvlong *bounds)
  719. {
  720. int i;
  721. if(buildtbls() == 0)
  722. return 0;
  723. i = srchtext(addr);
  724. if(0 <= i && i < ntxt-1) {
  725. bounds[0] = txt[i].sym->value;
  726. bounds[1] = txt[i+1].sym->value;
  727. return 1;
  728. }
  729. return 0;
  730. }
  731. /*
  732. * get the ith local symbol for a function
  733. * the input symbol table is reverse ordered, so we reverse
  734. * accesses here to maintain approx. parameter ordering in a stack trace.
  735. */
  736. int
  737. localsym(Symbol *s, int index)
  738. {
  739. Txtsym *tp;
  740. if(s == 0 || index < 0)
  741. return 0;
  742. if(buildtbls() == 0)
  743. return 0;
  744. tp = (Txtsym *)s->handle;
  745. if(tp && tp->locals && index < tp->n) {
  746. fillsym(tp->locals[tp->n-index-1], s); /* reverse */
  747. s->handle = (void *)tp;
  748. s->index = index;
  749. return 1;
  750. }
  751. return 0;
  752. }
  753. /*
  754. * get the ith global symbol
  755. */
  756. int
  757. globalsym(Symbol *s, int index)
  758. {
  759. if(s == 0)
  760. return 0;
  761. if(buildtbls() == 0)
  762. return 0;
  763. if(index >=0 && index < nglob) {
  764. fillsym(globals[index], s);
  765. s->index = index;
  766. return 1;
  767. }
  768. return 0;
  769. }
  770. /*
  771. * find the pc given a file name and line offset into it.
  772. */
  773. uvlong
  774. file2pc(char *file, long line)
  775. {
  776. File *fp;
  777. long i;
  778. uvlong pc, start, end;
  779. short *name;
  780. if(buildtbls() == 0 || files == 0)
  781. return ~0;
  782. name = encfname(file);
  783. if(name == 0) { /* encode the file name */
  784. werrstr("file %s not found", file);
  785. return ~0;
  786. }
  787. /* find this history stack */
  788. for(i = 0, fp = files; i < nfiles; i++, fp++)
  789. if (hline(fp, name, &line))
  790. break;
  791. free(name);
  792. if(i >= nfiles) {
  793. werrstr("line %ld in file %s not found", line, file);
  794. return ~0;
  795. }
  796. start = fp->addr; /* first text addr this file */
  797. if(i < nfiles-1)
  798. end = (fp+1)->addr; /* first text addr next file */
  799. else
  800. end = 0; /* last file in load module */
  801. /*
  802. * At this point, line contains the offset into the file.
  803. * run the state machine to locate the pc closest to that value.
  804. */
  805. if(debug)
  806. print("find pc for %ld - between: %llux and %llux\n", line, start, end);
  807. pc = line2addr(line, start, end);
  808. if(pc == ~0) {
  809. werrstr("line %ld not in file %s", line, file);
  810. return ~0;
  811. }
  812. return pc;
  813. }
  814. /*
  815. * search for a path component index
  816. */
  817. static int
  818. pathcomp(char *s, int n)
  819. {
  820. int i;
  821. for(i = 0; i <= fmax; i++)
  822. if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0)
  823. return i;
  824. return -1;
  825. }
  826. /*
  827. * Encode a char file name as a sequence of short indices
  828. * into the file name dictionary.
  829. */
  830. static short*
  831. encfname(char *file)
  832. {
  833. int i, j;
  834. char *cp, *cp2;
  835. short *dest;
  836. if(*file == '/') /* always check first '/' */
  837. cp2 = file+1;
  838. else {
  839. cp2 = strchr(file, '/');
  840. if(!cp2)
  841. cp2 = strchr(file, 0);
  842. }
  843. cp = file;
  844. dest = 0;
  845. for(i = 0; *cp; i++) {
  846. j = pathcomp(cp, cp2-cp);
  847. if(j < 0)
  848. return 0; /* not found */
  849. dest = realloc(dest, (i+1)*sizeof(short));
  850. dest[i] = j;
  851. cp = cp2;
  852. while(*cp == '/') /* skip embedded '/'s */
  853. cp++;
  854. cp2 = strchr(cp, '/');
  855. if(!cp2)
  856. cp2 = strchr(cp, 0);
  857. }
  858. dest = realloc(dest, (i+1)*sizeof(short));
  859. dest[i] = 0;
  860. return dest;
  861. }
  862. /*
  863. * Search a history stack for a matching file name accumulating
  864. * the size of intervening files in the stack.
  865. */
  866. static int
  867. hline(File *fp, short *name, long *line)
  868. {
  869. Hist *hp;
  870. int offset, depth;
  871. long ln;
  872. for(hp = fp->hist; hp->name; hp++) /* find name in stack */
  873. if(hp->name[1] || hp->name[2]) {
  874. if(hcomp(hp, name))
  875. break;
  876. }
  877. if(!hp->name) /* match not found */
  878. return 0;
  879. if(debug)
  880. printhist("hline found ... ", hp, 1);
  881. /*
  882. * unwind the stack until empty or we hit an entry beyond our line
  883. */
  884. ln = *line;
  885. offset = hp->line-1;
  886. depth = 1;
  887. for(hp++; depth && hp->name; hp++) {
  888. if(debug)
  889. printhist("hline inspect ... ", hp, 1);
  890. if(hp->name[1] || hp->name[2]) {
  891. if(hp->offset){ /* Z record */
  892. offset = 0;
  893. if(hcomp(hp, name)) {
  894. if(*line <= hp->offset)
  895. break;
  896. ln = *line+hp->line-hp->offset;
  897. depth = 1; /* implicit pop */
  898. } else
  899. depth = 2; /* implicit push */
  900. } else if(depth == 1 && ln < hp->line-offset)
  901. break; /* Beyond our line */
  902. else if(depth++ == 1) /* push */
  903. offset -= hp->line;
  904. } else if(--depth == 1) /* pop */
  905. offset += hp->line;
  906. }
  907. *line = ln+offset;
  908. return 1;
  909. }
  910. /*
  911. * compare two encoded file names
  912. */
  913. static int
  914. hcomp(Hist *hp, short *sp)
  915. {
  916. uchar *cp;
  917. int i, j;
  918. short *s;
  919. cp = (uchar *)hp->name;
  920. s = sp;
  921. if (*s == 0)
  922. return 0;
  923. for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) {
  924. if(j == 0)
  925. break;
  926. if(*s == j)
  927. s++;
  928. else
  929. s = sp;
  930. }
  931. return *s == 0;
  932. }
  933. /*
  934. * Convert a pc to a "file:line {file:line}" string.
  935. */
  936. long
  937. fileline(char *str, int n, uvlong dot)
  938. {
  939. long line, top, bot, mid;
  940. File *f;
  941. *str = 0;
  942. if(buildtbls() == 0)
  943. return 0;
  944. /* binary search assumes file list is sorted by addr */
  945. bot = 0;
  946. top = nfiles;
  947. for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
  948. f = &files[mid];
  949. if(dot < f->addr)
  950. top = mid;
  951. else if(mid < nfiles-1 && dot >= (f+1)->addr)
  952. bot = mid;
  953. else {
  954. line = pc2line(dot);
  955. if(line > 0 && fline(str, n, line, f->hist, 0) >= 0)
  956. return 1;
  957. break;
  958. }
  959. }
  960. return 0;
  961. }
  962. /*
  963. * Convert a line number within a composite file to relative line
  964. * number in a source file. A composite file is the source
  965. * file with included files inserted in line.
  966. */
  967. static int
  968. fline(char *str, int n, long line, Hist *base, Hist **ret)
  969. {
  970. Hist *start; /* start of current level */
  971. Hist *h; /* current entry */
  972. long delta; /* sum of size of files this level */
  973. int k;
  974. start = base;
  975. h = base;
  976. delta = h->line;
  977. while(h && h->name && line > h->line) {
  978. if(h->name[1] || h->name[2]) {
  979. if(h->offset != 0) { /* #line Directive */
  980. delta = h->line-h->offset+1;
  981. start = h;
  982. base = h++;
  983. } else { /* beginning of File */
  984. if(start == base)
  985. start = h++;
  986. else {
  987. k = fline(str, n, line, start, &h);
  988. if(k <= 0)
  989. return k;
  990. }
  991. }
  992. } else {
  993. if(start == base && ret) { /* end of recursion level */
  994. *ret = h;
  995. return 1;
  996. } else { /* end of included file */
  997. delta += h->line-start->line;
  998. h++;
  999. start = base;
  1000. }
  1001. }
  1002. }
  1003. if(!h)
  1004. return -1;
  1005. if(start != base)
  1006. line = line-start->line+1;
  1007. else
  1008. line = line-delta+1;
  1009. if(!h->name)
  1010. strncpy(str, "<eof>", n);
  1011. else {
  1012. k = fileelem(fnames, (uchar*)start->name, str, n);
  1013. if(k+8 < n)
  1014. sprint(str+k, ":%ld", line);
  1015. }
  1016. /**********Remove comments for complete back-trace of include sequence
  1017. * if(start != base) {
  1018. * k = strlen(str);
  1019. * if(k+2 < n) {
  1020. * str[k++] = ' ';
  1021. * str[k++] = '{';
  1022. * }
  1023. * k += fileelem(fnames, (uchar*) base->name, str+k, n-k);
  1024. * if(k+10 < n)
  1025. * sprint(str+k, ":%ld}", start->line-delta);
  1026. * }
  1027. ********************/
  1028. return 0;
  1029. }
  1030. /*
  1031. * convert an encoded file name to a string.
  1032. */
  1033. int
  1034. fileelem(Sym **fp, uchar *cp, char *buf, int n)
  1035. {
  1036. int i, j;
  1037. char *c, *bp, *end;
  1038. bp = buf;
  1039. end = buf+n-1;
  1040. for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){
  1041. c = fp[j]->name;
  1042. if(bp != buf && bp[-1] != '/' && bp < end)
  1043. *bp++ = '/';
  1044. while(bp < end && *c)
  1045. *bp++ = *c++;
  1046. }
  1047. *bp = 0;
  1048. i = bp-buf;
  1049. if(i > 1) {
  1050. cleanname(buf);
  1051. i = strlen(buf);
  1052. }
  1053. return i;
  1054. }
  1055. /*
  1056. * compare the values of two symbol table entries.
  1057. */
  1058. static int
  1059. symcomp(void *a, void *b)
  1060. {
  1061. int i;
  1062. i = (*(Sym**)a)->value - (*(Sym**)b)->value;
  1063. if (i)
  1064. return i;
  1065. return strcmp((*(Sym**)a)->name, (*(Sym**)b)->name);
  1066. }
  1067. /*
  1068. * compare the values of the symbols referenced by two text table entries
  1069. */
  1070. static int
  1071. txtcomp(void *a, void *b)
  1072. {
  1073. return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value;
  1074. }
  1075. /*
  1076. * compare the values of the symbols referenced by two file table entries
  1077. */
  1078. static int
  1079. filecomp(void *a, void *b)
  1080. {
  1081. return ((File*)a)->addr - ((File*)b)->addr;
  1082. }
  1083. /*
  1084. * fill an interface Symbol structure from a symbol table entry
  1085. */
  1086. static void
  1087. fillsym(Sym *sp, Symbol *s)
  1088. {
  1089. s->type = sp->type;
  1090. s->value = sp->value;
  1091. s->name = sp->name;
  1092. s->index = 0;
  1093. switch(sp->type) {
  1094. case 'b':
  1095. case 'B':
  1096. case 'D':
  1097. case 'd':
  1098. s->class = CDATA;
  1099. break;
  1100. case 't':
  1101. case 'T':
  1102. case 'l':
  1103. case 'L':
  1104. s->class = CTEXT;
  1105. break;
  1106. case 'a':
  1107. s->class = CAUTO;
  1108. break;
  1109. case 'p':
  1110. s->class = CPARAM;
  1111. break;
  1112. case 'm':
  1113. s->class = CSTAB;
  1114. break;
  1115. default:
  1116. s->class = CNONE;
  1117. break;
  1118. }
  1119. s->handle = 0;
  1120. }
  1121. /*
  1122. * find the stack frame, given the pc
  1123. */
  1124. uvlong
  1125. pc2sp(uvlong pc)
  1126. {
  1127. uchar *c, u;
  1128. uvlong currpc, currsp;
  1129. if(spoff == 0)
  1130. return ~0;
  1131. currsp = 0;
  1132. currpc = txtstart - mach->pcquant;
  1133. if(pc<currpc || pc>txtend)
  1134. return ~0;
  1135. for(c = spoff; c < spoffend; c++) {
  1136. if (currpc >= pc)
  1137. return currsp;
  1138. u = *c;
  1139. if (u == 0) {
  1140. currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
  1141. c += 4;
  1142. }
  1143. else if (u < 65)
  1144. currsp += 4*u;
  1145. else if (u < 129)
  1146. currsp -= 4*(u-64);
  1147. else
  1148. currpc += mach->pcquant*(u-129);
  1149. currpc += mach->pcquant;
  1150. }
  1151. return ~0;
  1152. }
  1153. /*
  1154. * find the source file line number for a given value of the pc
  1155. */
  1156. long
  1157. pc2line(uvlong pc)
  1158. {
  1159. uchar *c, u;
  1160. uvlong currpc;
  1161. long currline;
  1162. if(pcline == 0)
  1163. return -1;
  1164. currline = 0;
  1165. currpc = txtstart-mach->pcquant;
  1166. if(pc<currpc || pc>txtend)
  1167. return ~0;
  1168. for(c = pcline; c < pclineend; c++) {
  1169. if(currpc >= pc)
  1170. return currline;
  1171. u = *c;
  1172. if(u == 0) {
  1173. currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
  1174. c += 4;
  1175. }
  1176. else if(u < 65)
  1177. currline += u;
  1178. else if(u < 129)
  1179. currline -= (u-64);
  1180. else
  1181. currpc += mach->pcquant*(u-129);
  1182. currpc += mach->pcquant;
  1183. }
  1184. return ~0;
  1185. }
  1186. /*
  1187. * find the pc associated with a line number
  1188. * basepc and endpc are text addresses bounding the search.
  1189. * if endpc == 0, the end of the table is used (i.e., no upper bound).
  1190. * usually, basepc and endpc contain the first text address in
  1191. * a file and the first text address in the following file, respectively.
  1192. */
  1193. uvlong
  1194. line2addr(long line, uvlong basepc, uvlong endpc)
  1195. {
  1196. uchar *c, u;
  1197. uvlong currpc, pc;
  1198. long currline;
  1199. long delta, d;
  1200. int found;
  1201. if(pcline == 0 || line == 0)
  1202. return ~0;
  1203. currline = 0;
  1204. currpc = txtstart-mach->pcquant;
  1205. pc = ~0;
  1206. found = 0;
  1207. delta = HUGEINT;
  1208. for(c = pcline; c < pclineend; c++) {
  1209. if(endpc && currpc >= endpc) /* end of file of interest */
  1210. break;
  1211. if(currpc >= basepc) { /* proper file */
  1212. if(currline >= line) {
  1213. d = currline-line;
  1214. found = 1;
  1215. } else
  1216. d = line-currline;
  1217. if(d < delta) {
  1218. delta = d;
  1219. pc = currpc;
  1220. }
  1221. }
  1222. u = *c;
  1223. if(u == 0) {
  1224. currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
  1225. c += 4;
  1226. }
  1227. else if(u < 65)
  1228. currline += u;
  1229. else if(u < 129)
  1230. currline -= (u-64);
  1231. else
  1232. currpc += mach->pcquant*(u-129);
  1233. currpc += mach->pcquant;
  1234. }
  1235. if(found)
  1236. return pc;
  1237. return ~0;
  1238. }
  1239. /*
  1240. * Print a history stack (debug). if count is 0, prints the whole stack
  1241. */
  1242. static void
  1243. printhist(char *msg, Hist *hp, int count)
  1244. {
  1245. int i;
  1246. uchar *cp;
  1247. char buf[128];
  1248. i = 0;
  1249. while(hp->name) {
  1250. if(count && ++i > count)
  1251. break;
  1252. print("%s Line: %lx (%ld) Offset: %lx (%ld) Name: ", msg,
  1253. hp->line, hp->line, hp->offset, hp->offset);
  1254. for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) {
  1255. if (cp != (uchar *)hp->name+1)
  1256. print("/");
  1257. print("%x", (*cp<<8)|cp[1]);
  1258. }
  1259. fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf));
  1260. print(" (%s)\n", buf);
  1261. hp++;
  1262. }
  1263. }
  1264. #ifdef DEBUG
  1265. /*
  1266. * print the history stack for a file. (debug only)
  1267. * if (name == 0) => print all history stacks.
  1268. */
  1269. void
  1270. dumphist(char *name)
  1271. {
  1272. int i;
  1273. File *f;
  1274. short *fname;
  1275. if(buildtbls() == 0)
  1276. return;
  1277. if(name)
  1278. fname = encfname(name);
  1279. for(i = 0, f = files; i < nfiles; i++, f++)
  1280. if(fname == 0 || hcomp(f->hist, fname))
  1281. printhist("> ", f->hist, f->n);
  1282. if(fname)
  1283. free(fname);
  1284. }
  1285. #endif