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