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