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