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