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 1323