|
|
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.