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