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