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