github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/libmach/sym.c (about) 1 // Inferno libmach/sym.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/libmach/sym.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. 5 // Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). 6 // Portions Copyright © 1997-1999 Vita Nuova Limited. 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). 8 // Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others. 9 // Portions Copyright © 2009 The Go Authors. All rights reserved. 10 // 11 // Permission is hereby granted, free of charge, to any person obtaining a copy 12 // of this software and associated documentation files (the "Software"), to deal 13 // in the Software without restriction, including without limitation the rights 14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 // copies of the Software, and to permit persons to whom the Software is 16 // furnished to do so, subject to the following conditions: 17 // 18 // The above copyright notice and this permission notice shall be included in 19 // all copies or substantial portions of the Software. 20 // 21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 // THE SOFTWARE. 28 29 #include <u.h> 30 #include <libc.h> 31 #include <bio.h> 32 #include <mach.h> 33 34 #define HUGEINT 0x7fffffff 35 #define NNAME 20 /* a relic of the past */ 36 37 typedef struct txtsym Txtsym; 38 typedef struct file File; 39 typedef struct hist Hist; 40 41 struct txtsym { /* Text Symbol table */ 42 int n; /* number of local vars */ 43 Sym **locals; /* array of ptrs to autos */ 44 Sym *sym; /* function symbol entry */ 45 }; 46 47 struct hist { /* Stack of include files & #line directives */ 48 char *name; /* Assumes names Null terminated in file */ 49 int32 line; /* line # where it was included */ 50 int32 offset; /* line # of #line directive */ 51 }; 52 53 struct file { /* Per input file header to history stack */ 54 uvlong addr; /* address of first text sym */ 55 union { 56 Txtsym *txt; /* first text symbol */ 57 Sym *sym; /* only during initilization */ 58 }; 59 int n; /* size of history stack */ 60 Hist *hist; /* history stack */ 61 }; 62 63 static int debug = 0; 64 65 static Sym **autos; /* Base of auto variables */ 66 static File *files; /* Base of file arena */ 67 static int fmaxi; /* largest file path index */ 68 static Sym **fnames; /* file names path component table */ 69 static Sym **globals; /* globals by addr table */ 70 static Hist *hist; /* base of history stack */ 71 static int isbuilt; /* internal table init flag */ 72 static int32 nauto; /* number of automatics */ 73 static int32 nfiles; /* number of files */ 74 static int32 nglob; /* number of globals */ 75 static int32 nhist; /* number of history stack entries */ 76 static int32 nsym; /* number of symbols */ 77 static int ntxt; /* number of text symbols */ 78 static uchar *pcline; /* start of pc-line state table */ 79 static uchar *pclineend; /* end of pc-line table */ 80 static uchar *spoff; /* start of pc-sp state table */ 81 static uchar *spoffend; /* end of pc-sp offset table */ 82 static Sym *symbols; /* symbol table */ 83 static Txtsym *txt; /* Base of text symbol table */ 84 static uvlong txtstart; /* start of text segment */ 85 static uvlong txtend; /* end of text segment */ 86 static uvlong firstinstr; /* as found from symtab; needed for amd64 */ 87 88 static void cleansyms(void); 89 static int32 decodename(Biobuf*, Sym*); 90 static short *encfname(char*); 91 static int fline(char*, int, int32, Hist*, Hist**); 92 static void fillsym(Sym*, Symbol*); 93 static int findglobal(char*, Symbol*); 94 static int findlocvar(Symbol*, char *, Symbol*); 95 static int findtext(char*, Symbol*); 96 static int hcomp(Hist*, short*); 97 static int hline(File*, short*, int32*); 98 static void printhist(char*, Hist*, int); 99 static int buildtbls(void); 100 static int symcomp(const void*, const void*); 101 static int symerrmsg(int, char*); 102 static int txtcomp(const void*, const void*); 103 static int filecomp(const void*, const void*); 104 105 /* 106 * Go 1.2 pcln table (also contains pcsp). 107 */ 108 #define Go12PclnMagic 0xfffffffb 109 #define Go12PclnMagicRev 0xfbffffff 110 static int isgo12pcline(void); 111 static uvlong go12pc2sp(uvlong); 112 static int32 go12fileline(char*, int, uvlong); 113 static void go12clean(void); 114 static uvlong go12file2pc(char*, int); 115 116 /* 117 * initialize the symbol tables 118 */ 119 int 120 syminit(int fd, Fhdr *fp) 121 { 122 Sym *p; 123 int32 i, l, size, symsz; 124 vlong vl; 125 Biobuf b; 126 int svalsz, newformat, shift; 127 uvlong (*swav)(uvlong); 128 uint32 (*swal)(uint32); 129 uchar buf[8], c; 130 131 if(fp->symsz == 0) 132 return 0; 133 if(fp->type == FNONE) 134 return 0; 135 136 swav = beswav; 137 swal = beswal; 138 139 cleansyms(); 140 textseg(fp->txtaddr, fp); 141 /* minimum symbol record size = 4+1+2 bytes */ 142 symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym)); 143 if(symbols == 0) { 144 werrstr("can't malloc %d bytes", fp->symsz); 145 return -1; 146 } 147 Binit(&b, fd, OREAD); 148 Bseek(&b, fp->symoff, 0); 149 memset(buf, 0, sizeof buf); 150 Bread(&b, buf, sizeof buf); 151 newformat = 0; 152 symsz = fp->symsz; 153 if(memcmp(buf, "\xfd\xff\xff\xff\x00\x00\x00", 7) == 0) { 154 swav = leswav; 155 swal = leswal; 156 newformat = 1; 157 } else if(memcmp(buf, "\xff\xff\xff\xfd\x00\x00\x00", 7) == 0) { 158 newformat = 1; 159 } else if(memcmp(buf, "\xfe\xff\xff\xff\x00\x00", 6) == 0) { 160 // Table format used between Go 1.0 and Go 1.1: 161 // little-endian but otherwise same as the old Go 1.0 table. 162 // Not likely to be seen much in practice, but easy to handle. 163 swav = leswav; 164 swal = leswal; 165 Bseek(&b, fp->symoff+6, 0); 166 symsz -= 6; 167 } else { 168 Bseek(&b, fp->symoff, 0); 169 } 170 svalsz = 0; 171 if(newformat) { 172 svalsz = buf[7]; 173 if(svalsz != 4 && svalsz != 8) { 174 werrstr("invalid word size %d bytes", svalsz); 175 return -1; 176 } 177 symsz -= 8; 178 } 179 180 nsym = 0; 181 size = 0; 182 for(p = symbols; size < symsz; p++, nsym++) { 183 if(newformat) { 184 // Go 1.1 format. See comment at top of ../pkg/runtime/symtab.c. 185 if(Bread(&b, &c, 1) != 1) 186 return symerrmsg(1, "symbol"); 187 if((c&0x3F) < 26) 188 p->type = (c&0x3F)+ 'A'; 189 else 190 p->type = (c&0x3F) - 26 + 'a'; 191 size++; 192 193 if(c&0x40) { 194 // Fixed-width address. 195 if(svalsz == 8) { 196 if(Bread(&b, &vl, 8) != 8) 197 return symerrmsg(8, "symbol"); 198 p->value = swav(vl); 199 } else { 200 if(Bread(&b, &l, 4) != 4) 201 return symerrmsg(4, "symbol"); 202 p->value = (u32int)swal(l); 203 } 204 size += svalsz; 205 } else { 206 // Varint address. 207 shift = 0; 208 p->value = 0; 209 for(;;) { 210 if(Bread(&b, buf, 1) != 1) 211 return symerrmsg(1, "symbol"); 212 p->value |= (uint64)(buf[0]&0x7F)<<shift; 213 shift += 7; 214 size++; 215 if((buf[0]&0x80) == 0) 216 break; 217 } 218 } 219 p->gotype = 0; 220 if(c&0x80) { 221 // Has Go type. Fixed-width address. 222 if(svalsz == 8) { 223 if(Bread(&b, &vl, 8) != 8) 224 return symerrmsg(8, "symbol"); 225 p->gotype = swav(vl); 226 } else { 227 if(Bread(&b, &l, 4) != 4) 228 return symerrmsg(4, "symbol"); 229 p->gotype = (u32int)swal(l); 230 } 231 size += svalsz; 232 } 233 234 // Name. 235 p->type |= 0x80; // for decodename 236 i = decodename(&b, p); 237 if(i < 0) 238 return -1; 239 size += i; 240 } else { 241 // Go 1.0 format: Plan 9 format + go type symbol. 242 if(fp->_magic && (fp->magic & HDR_MAGIC)){ 243 svalsz = 8; 244 if(Bread(&b, &vl, 8) != 8) 245 return symerrmsg(8, "symbol"); 246 p->value = swav(vl); 247 } 248 else{ 249 svalsz = 4; 250 if(Bread(&b, &l, 4) != 4) 251 return symerrmsg(4, "symbol"); 252 p->value = (u32int)swal(l); 253 } 254 if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type)) 255 return symerrmsg(sizeof(p->value), "symbol"); 256 257 i = decodename(&b, p); 258 if(i < 0) 259 return -1; 260 size += i+svalsz+sizeof(p->type); 261 262 if(svalsz == 8){ 263 if(Bread(&b, &vl, 8) != 8) 264 return symerrmsg(8, "symbol"); 265 p->gotype = swav(vl); 266 } 267 else{ 268 if(Bread(&b, &l, 4) != 4) 269 return symerrmsg(4, "symbol"); 270 p->gotype = (u32int)swal(l); 271 } 272 size += svalsz; 273 } 274 275 /* count global & auto vars, text symbols, and file names */ 276 switch (p->type) { 277 case 'l': 278 case 'L': 279 case 't': 280 case 'T': 281 ntxt++; 282 break; 283 case 'd': 284 case 'D': 285 case 'b': 286 case 'B': 287 nglob++; 288 break; 289 case 'f': 290 if(strcmp(p->name, ".frame") == 0) { 291 p->type = 'm'; 292 nauto++; 293 } 294 else if(p->value > fmaxi) 295 fmaxi = p->value; /* highest path index */ 296 break; 297 case 'a': 298 case 'p': 299 case 'm': 300 nauto++; 301 break; 302 case 'z': 303 if(p->value == 1) { /* one extra per file */ 304 nhist++; 305 nfiles++; 306 } 307 nhist++; 308 break; 309 default: 310 break; 311 } 312 } 313 if (debug) 314 print("NG: %d NT: %d NF: %d\n", nglob, ntxt, fmaxi); 315 if (fp->sppcsz) { /* pc-sp offset table */ 316 spoff = (uchar *)malloc(fp->sppcsz); 317 if(spoff == 0) { 318 werrstr("can't malloc %d bytes", fp->sppcsz); 319 return -1; 320 } 321 Bseek(&b, fp->sppcoff, 0); 322 if(Bread(&b, spoff, fp->sppcsz) != fp->sppcsz){ 323 spoff = 0; 324 return symerrmsg(fp->sppcsz, "sp-pc"); 325 } 326 spoffend = spoff+fp->sppcsz; 327 } 328 if (fp->lnpcsz) { /* pc-line number table */ 329 pcline = (uchar *)malloc(fp->lnpcsz); 330 if(pcline == 0) { 331 werrstr("can't malloc %d bytes", fp->lnpcsz); 332 return -1; 333 } 334 Bseek(&b, fp->lnpcoff, 0); 335 if(Bread(&b, pcline, fp->lnpcsz) != fp->lnpcsz){ 336 pcline = 0; 337 return symerrmsg(fp->lnpcsz, "pc-line"); 338 } 339 pclineend = pcline+fp->lnpcsz; 340 } 341 return nsym; 342 } 343 344 static int 345 symerrmsg(int n, char *table) 346 { 347 werrstr("can't read %d bytes of %s table", n, table); 348 return -1; 349 } 350 351 static int32 352 decodename(Biobuf *bp, Sym *p) 353 { 354 char *cp; 355 int c1, c2; 356 int32 n; 357 vlong o; 358 359 if((p->type & 0x80) == 0) { /* old-style, fixed length names */ 360 p->name = malloc(NNAME); 361 if(p->name == 0) { 362 werrstr("can't malloc %d bytes", NNAME); 363 return -1; 364 } 365 if(Bread(bp, p->name, NNAME) != NNAME) 366 return symerrmsg(NNAME, "symbol"); 367 Bseek(bp, 3, 1); 368 return NNAME+3; 369 } 370 371 p->type &= ~0x80; 372 if(p->type == 'z' || p->type == 'Z') { 373 o = Bseek(bp, 0, 1); 374 if(BGETC(bp) < 0) { 375 werrstr("can't read symbol name"); 376 return -1; 377 } 378 for(;;) { 379 c1 = BGETC(bp); 380 c2 = BGETC(bp); 381 if(c1 < 0 || c2 < 0) { 382 werrstr("can't read symbol name"); 383 return -1; 384 } 385 if(c1 == 0 && c2 == 0) 386 break; 387 } 388 n = Bseek(bp, 0, 1)-o; 389 p->name = malloc(n); 390 if(p->name == 0) { 391 werrstr("can't malloc %d bytes", n); 392 return -1; 393 } 394 Bseek(bp, -n, 1); 395 if(Bread(bp, p->name, n) != n) { 396 werrstr("can't read %d bytes of symbol name", n); 397 return -1; 398 } 399 } else { 400 cp = Brdline(bp, '\0'); 401 if(cp == 0) { 402 werrstr("can't read symbol name"); 403 return -1; 404 } 405 n = Blinelen(bp); 406 p->name = malloc(n); 407 if(p->name == 0) { 408 werrstr("can't malloc %d bytes", n); 409 return -1; 410 } 411 strcpy(p->name, cp); 412 } 413 return n; 414 } 415 416 /* 417 * free any previously loaded symbol tables 418 */ 419 static void 420 cleansyms(void) 421 { 422 if(globals) 423 free(globals); 424 globals = 0; 425 nglob = 0; 426 if(txt) 427 free(txt); 428 txt = 0; 429 ntxt = 0; 430 if(fnames) 431 free(fnames); 432 fnames = 0; 433 fmaxi = 0; 434 435 if(files) 436 free(files); 437 files = 0; 438 nfiles = 0; 439 if(hist) 440 free(hist); 441 hist = 0; 442 nhist = 0; 443 if(autos) 444 free(autos); 445 autos = 0; 446 nauto = 0; 447 isbuilt = 0; 448 if(symbols) 449 free(symbols); 450 symbols = 0; 451 nsym = 0; 452 if(spoff) 453 free(spoff); 454 spoff = 0; 455 if(pcline) 456 free(pcline); 457 pcline = 0; 458 go12clean(); 459 } 460 461 /* 462 * delimit the text segment 463 */ 464 void 465 textseg(uvlong base, Fhdr *fp) 466 { 467 txtstart = base; 468 txtend = base+fp->txtsz; 469 } 470 471 /* 472 * symbase: return base and size of raw symbol table 473 * (special hack for high access rate operations) 474 */ 475 Sym * 476 symbase(int32 *n) 477 { 478 *n = nsym; 479 return symbols; 480 } 481 482 /* 483 * Get the ith symbol table entry 484 */ 485 Sym * 486 getsym(int index) 487 { 488 if(index >= 0 && index < nsym) 489 return &symbols[index]; 490 return 0; 491 } 492 493 /* 494 * initialize internal symbol tables 495 */ 496 static int 497 buildtbls(void) 498 { 499 int32 i; 500 int j, nh, ng, nt; 501 File *f; 502 Txtsym *tp; 503 Hist *hp; 504 Sym *p, **ap; 505 506 if(isbuilt) 507 return 1; 508 isbuilt = 1; 509 /* allocate the tables */ 510 firstinstr = 0; 511 if(nglob) { 512 globals = malloc(nglob*sizeof(*globals)); 513 if(!globals) { 514 werrstr("can't malloc global symbol table"); 515 return 0; 516 } 517 } 518 if(ntxt) { 519 txt = malloc(ntxt*sizeof(*txt)); 520 if (!txt) { 521 werrstr("can't malloc text symbol table"); 522 return 0; 523 } 524 } 525 fnames = malloc((fmaxi+1)*sizeof(*fnames)); 526 if (!fnames) { 527 werrstr("can't malloc file name table"); 528 return 0; 529 } 530 memset(fnames, 0, (fmaxi+1)*sizeof(*fnames)); 531 files = malloc(nfiles*sizeof(*files)); 532 if(!files) { 533 werrstr("can't malloc file table"); 534 return 0; 535 } 536 hist = malloc(nhist*sizeof(Hist)); 537 if(hist == 0) { 538 werrstr("can't malloc history stack"); 539 return 0; 540 } 541 autos = malloc(nauto*sizeof(Sym*)); 542 if(autos == 0) { 543 werrstr("can't malloc auto symbol table"); 544 return 0; 545 } 546 /* load the tables */ 547 ng = nt = nh = 0; 548 f = 0; 549 tp = 0; 550 i = nsym; 551 hp = hist; 552 ap = autos; 553 for(p = symbols; i-- > 0; p++) { 554 //print("sym %d type %c name %s value %llux\n", p-symbols, p->type, p->name, p->value); 555 switch(p->type) { 556 case 'D': 557 case 'd': 558 case 'B': 559 case 'b': 560 if(debug) 561 print("Global: %s %llux\n", p->name, p->value); 562 globals[ng++] = p; 563 break; 564 case 'z': 565 if(p->value == 1) { /* New file */ 566 if(f) { 567 f->n = nh; 568 f->hist[nh].name = 0; /* one extra */ 569 hp += nh+1; 570 f++; 571 } 572 else 573 f = files; 574 f->hist = hp; 575 f->sym = 0; 576 f->addr = 0; 577 nh = 0; 578 } 579 /* alloc one slot extra as terminator */ 580 f->hist[nh].name = p->name; 581 f->hist[nh].line = p->value; 582 f->hist[nh].offset = 0; 583 if(debug) 584 printhist("-> ", &f->hist[nh], 1); 585 nh++; 586 break; 587 case 'Z': 588 if(f && nh > 0) 589 f->hist[nh-1].offset = p->value; 590 break; 591 case 'T': 592 case 't': /* Text: terminate history if first in file */ 593 case 'L': 594 case 'l': 595 tp = &txt[nt++]; 596 tp->n = 0; 597 tp->sym = p; 598 tp->locals = ap; 599 if(debug) 600 print("TEXT: %s at %llux\n", p->name, p->value); 601 if (firstinstr == 0 || p->value < firstinstr) 602 firstinstr = p->value; 603 if(f && !f->sym) { /* first */ 604 f->sym = p; 605 f->addr = p->value; 606 } 607 break; 608 case 'a': 609 case 'p': 610 case 'm': /* Local Vars */ 611 if(!tp) 612 print("Warning: Free floating local var: %s\n", 613 p->name); 614 else { 615 if(debug) 616 print("Local: %s %llux\n", p->name, p->value); 617 tp->locals[tp->n] = p; 618 tp->n++; 619 ap++; 620 } 621 break; 622 case 'f': /* File names */ 623 if(debug) 624 print("Fname: %s\n", p->name); 625 fnames[p->value] = p; 626 break; 627 default: 628 break; 629 } 630 } 631 /* sort global and text tables into ascending address order */ 632 qsort(globals, nglob, sizeof(Sym*), symcomp); 633 qsort(txt, ntxt, sizeof(Txtsym), txtcomp); 634 qsort(files, nfiles, sizeof(File), filecomp); 635 tp = txt; 636 for(i = 0, f = files; i < nfiles; i++, f++) { 637 for(j = 0; j < ntxt; j++) { 638 if(f->sym == tp->sym) { 639 if(debug) { 640 print("LINK: %s to at %llux", f->sym->name, f->addr); 641 printhist("... ", f->hist, 1); 642 } 643 f->txt = tp++; 644 break; 645 } 646 if(++tp >= txt+ntxt) /* wrap around */ 647 tp = txt; 648 } 649 } 650 return 1; 651 } 652 653 /* 654 * find symbol function.var by name. 655 * fn != 0 && var != 0 => look for fn in text, var in data 656 * fn != 0 && var == 0 => look for fn in text 657 * fn == 0 && var != 0 => look for var first in text then in data space. 658 */ 659 int 660 lookup(char *fn, char *var, Symbol *s) 661 { 662 int found; 663 664 if(buildtbls() == 0) 665 return 0; 666 if(fn) { 667 found = findtext(fn, s); 668 if(var == 0) /* case 2: fn not in text */ 669 return found; 670 else if(!found) /* case 1: fn not found */ 671 return 0; 672 } else if(var) { 673 found = findtext(var, s); 674 if(found) 675 return 1; /* case 3: var found in text */ 676 } else return 0; /* case 4: fn & var == zero */ 677 678 if(found) 679 return findlocal(s, var, s); /* case 1: fn found */ 680 return findglobal(var, s); /* case 3: var not found */ 681 682 } 683 684 /* 685 * strcmp, but allow '_' to match center dot (rune 00b7 == bytes c2 b7) 686 */ 687 int 688 cdotstrcmp(char *sym, char *user) 689 { 690 for (;;) { 691 while (*sym == *user) { 692 if (*sym++ == '\0') 693 return 0; 694 user++; 695 } 696 /* unequal - but maybe '_' matches center dot */ 697 if (user[0] == '_' && (sym[0]&0xFF) == 0xc2 && (sym[1]&0xFF) == 0xb7) { 698 /* '_' matches center dot - advance and continue */ 699 user++; 700 sym += 2; 701 continue; 702 } 703 break; 704 } 705 return *user - *sym; 706 } 707 708 /* 709 * find a function by name 710 */ 711 static int 712 findtext(char *name, Symbol *s) 713 { 714 int i; 715 716 for(i = 0; i < ntxt; i++) { 717 if(cdotstrcmp(txt[i].sym->name, name) == 0) { 718 fillsym(txt[i].sym, s); 719 s->handle = (void *) &txt[i]; 720 s->index = i; 721 return 1; 722 } 723 } 724 return 0; 725 } 726 /* 727 * find global variable by name 728 */ 729 static int 730 findglobal(char *name, Symbol *s) 731 { 732 int32 i; 733 734 for(i = 0; i < nglob; i++) { 735 if(cdotstrcmp(globals[i]->name, name) == 0) { 736 fillsym(globals[i], s); 737 s->index = i; 738 return 1; 739 } 740 } 741 return 0; 742 } 743 744 /* 745 * find the local variable by name within a given function 746 */ 747 int 748 findlocal(Symbol *s1, char *name, Symbol *s2) 749 { 750 if(s1 == 0) 751 return 0; 752 if(buildtbls() == 0) 753 return 0; 754 return findlocvar(s1, name, s2); 755 } 756 757 /* 758 * find the local variable by name within a given function 759 * (internal function - does no parameter validation) 760 */ 761 static int 762 findlocvar(Symbol *s1, char *name, Symbol *s2) 763 { 764 Txtsym *tp; 765 int i; 766 767 tp = (Txtsym *)s1->handle; 768 if(tp && tp->locals) { 769 for(i = 0; i < tp->n; i++) 770 if (cdotstrcmp(tp->locals[i]->name, name) == 0) { 771 fillsym(tp->locals[i], s2); 772 s2->handle = (void *)tp; 773 s2->index = tp->n-1 - i; 774 return 1; 775 } 776 } 777 return 0; 778 } 779 780 /* 781 * Get ith text symbol 782 */ 783 int 784 textsym(Symbol *s, int index) 785 { 786 787 if(buildtbls() == 0) 788 return 0; 789 if(index < 0 || index >= ntxt) 790 return 0; 791 fillsym(txt[index].sym, s); 792 s->handle = (void *)&txt[index]; 793 s->index = index; 794 return 1; 795 } 796 797 /* 798 * Get ith file name 799 */ 800 int 801 filesym(int index, char *buf, int n) 802 { 803 Hist *hp; 804 805 if(buildtbls() == 0) 806 return 0; 807 if(index < 0 || index >= nfiles) 808 return 0; 809 hp = files[index].hist; 810 if(!hp || !hp->name) 811 return 0; 812 return fileelem(fnames, (uchar*)hp->name, buf, n); 813 } 814 815 /* 816 * Lookup name of local variable located at an offset into the frame. 817 * The type selects either a parameter or automatic. 818 */ 819 int 820 getauto(Symbol *s1, int off, int type, Symbol *s2) 821 { 822 Txtsym *tp; 823 Sym *p; 824 int i, t; 825 826 if(s1 == 0) 827 return 0; 828 if(type == CPARAM) 829 t = 'p'; 830 else if(type == CAUTO) 831 t = 'a'; 832 else 833 return 0; 834 if(buildtbls() == 0) 835 return 0; 836 tp = (Txtsym *)s1->handle; 837 if(tp == 0) 838 return 0; 839 for(i = 0; i < tp->n; i++) { 840 p = tp->locals[i]; 841 if(p->type == t && p->value == off) { 842 fillsym(p, s2); 843 s2->handle = s1->handle; 844 s2->index = tp->n-1 - i; 845 return 1; 846 } 847 } 848 return 0; 849 } 850 851 /* 852 * Find text symbol containing addr; binary search assumes text array is sorted by addr 853 */ 854 static int 855 srchtext(uvlong addr) 856 { 857 uvlong val; 858 int top, bot, mid; 859 Sym *sp; 860 861 val = addr; 862 bot = 0; 863 top = ntxt; 864 for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) { 865 sp = txt[mid].sym; 866 if(val < sp->value) 867 top = mid; 868 else if(mid != ntxt-1 && val >= txt[mid+1].sym->value) 869 bot = mid; 870 else 871 return mid; 872 } 873 return -1; 874 } 875 876 /* 877 * Find data symbol containing addr; binary search assumes data array is sorted by addr 878 */ 879 static int 880 srchdata(uvlong addr) 881 { 882 uvlong val; 883 int top, bot, mid; 884 Sym *sp; 885 886 bot = 0; 887 top = nglob; 888 val = addr; 889 for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) { 890 sp = globals[mid]; 891 if(val < sp->value) 892 top = mid; 893 else if(mid < nglob-1 && val >= globals[mid+1]->value) 894 bot = mid; 895 else 896 return mid; 897 } 898 return -1; 899 } 900 901 /* 902 * Find symbol containing val in specified search space 903 * There is a special case when a value falls beyond the end 904 * of the text segment; if the search space is CTEXT, that value 905 * (usually etext) is returned. If the search space is CANY, symbols in the 906 * data space are searched for a match. 907 */ 908 int 909 findsym(uvlong val, int type, Symbol *s) 910 { 911 int i; 912 913 if(buildtbls() == 0) 914 return 0; 915 916 if(type == CTEXT || type == CANY) { 917 i = srchtext(val); 918 if(i >= 0) { 919 if(type == CTEXT || i != ntxt-1) { 920 fillsym(txt[i].sym, s); 921 s->handle = (void *) &txt[i]; 922 s->index = i; 923 return 1; 924 } 925 } 926 } 927 if(type == CDATA || type == CANY) { 928 i = srchdata(val); 929 if(i >= 0) { 930 fillsym(globals[i], s); 931 s->index = i; 932 return 1; 933 } 934 } 935 return 0; 936 } 937 938 /* 939 * Find the start and end address of the function containing addr 940 */ 941 int 942 fnbound(uvlong addr, uvlong *bounds) 943 { 944 int i; 945 946 if(buildtbls() == 0) 947 return 0; 948 949 i = srchtext(addr); 950 if(0 <= i && i < ntxt-1) { 951 bounds[0] = txt[i].sym->value; 952 bounds[1] = txt[i+1].sym->value; 953 return 1; 954 } 955 return 0; 956 } 957 958 /* 959 * get the ith local symbol for a function 960 * the input symbol table is reverse ordered, so we reverse 961 * accesses here to maintain approx. parameter ordering in a stack trace. 962 */ 963 int 964 localsym(Symbol *s, int index) 965 { 966 Txtsym *tp; 967 968 if(s == 0 || index < 0) 969 return 0; 970 if(buildtbls() == 0) 971 return 0; 972 973 tp = (Txtsym *)s->handle; 974 if(tp && tp->locals && index < tp->n) { 975 fillsym(tp->locals[tp->n-index-1], s); /* reverse */ 976 s->handle = (void *)tp; 977 s->index = index; 978 return 1; 979 } 980 return 0; 981 } 982 983 /* 984 * get the ith global symbol 985 */ 986 int 987 globalsym(Symbol *s, int index) 988 { 989 if(s == 0) 990 return 0; 991 if(buildtbls() == 0) 992 return 0; 993 994 if(index >=0 && index < nglob) { 995 fillsym(globals[index], s); 996 s->index = index; 997 return 1; 998 } 999 return 0; 1000 } 1001 1002 /* 1003 * find the pc given a file name and line offset into it. 1004 */ 1005 uvlong 1006 file2pc(char *file, int32 line) 1007 { 1008 File *fp; 1009 int32 i; 1010 uvlong pc, start, end; 1011 short *name; 1012 1013 if(isgo12pcline()) 1014 return go12file2pc(file, line); 1015 if(buildtbls() == 0 || files == 0) 1016 return ~(uvlong)0; 1017 name = encfname(file); 1018 if(name == 0) { /* encode the file name */ 1019 werrstr("file %s not found", file); 1020 return ~(uvlong)0; 1021 } 1022 /* find this history stack */ 1023 for(i = 0, fp = files; i < nfiles; i++, fp++) 1024 if (hline(fp, name, &line)) 1025 break; 1026 free(name); 1027 if(i >= nfiles) { 1028 werrstr("line %d in file %s not found", line, file); 1029 return ~(uvlong)0; 1030 } 1031 start = fp->addr; /* first text addr this file */ 1032 if(i < nfiles-1) 1033 end = (fp+1)->addr; /* first text addr next file */ 1034 else 1035 end = 0; /* last file in load module */ 1036 /* 1037 * At this point, line contains the offset into the file. 1038 * run the state machine to locate the pc closest to that value. 1039 */ 1040 if(debug) 1041 print("find pc for %d - between: %llux and %llux\n", line, start, end); 1042 pc = line2addr(line, start, end); 1043 if(pc == ~(uvlong)0) { 1044 werrstr("line %d not in file %s", line, file); 1045 return ~(uvlong)0; 1046 } 1047 return pc; 1048 } 1049 1050 /* 1051 * search for a path component index 1052 */ 1053 static int 1054 pathcomp(char *s, int n) 1055 { 1056 int i; 1057 1058 for(i = 0; i <= fmaxi; i++) 1059 if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0) 1060 return i; 1061 return -1; 1062 } 1063 1064 /* 1065 * Encode a char file name as a sequence of short indices 1066 * into the file name dictionary. 1067 */ 1068 static short* 1069 encfname(char *file) 1070 { 1071 int i, j; 1072 char *cp, *cp2; 1073 short *dest; 1074 1075 if(*file == '/') /* always check first '/' */ 1076 cp2 = file+1; 1077 else { 1078 cp2 = strchr(file, '/'); 1079 if(!cp2) 1080 cp2 = strchr(file, 0); 1081 } 1082 cp = file; 1083 dest = 0; 1084 for(i = 0; *cp; i++) { 1085 j = pathcomp(cp, cp2-cp); 1086 if(j < 0) 1087 return 0; /* not found */ 1088 dest = realloc(dest, (i+1)*sizeof(short)); 1089 dest[i] = j; 1090 cp = cp2; 1091 while(*cp == '/') /* skip embedded '/'s */ 1092 cp++; 1093 cp2 = strchr(cp, '/'); 1094 if(!cp2) 1095 cp2 = strchr(cp, 0); 1096 } 1097 dest = realloc(dest, (i+1)*sizeof(short)); 1098 dest[i] = 0; 1099 return dest; 1100 } 1101 1102 /* 1103 * Search a history stack for a matching file name accumulating 1104 * the size of intervening files in the stack. 1105 */ 1106 static int 1107 hline(File *fp, short *name, int32 *line) 1108 { 1109 Hist *hp; 1110 int offset, depth; 1111 int32 ln; 1112 1113 for(hp = fp->hist; hp->name; hp++) /* find name in stack */ 1114 if(hp->name[1] || hp->name[2]) { 1115 if(hcomp(hp, name)) 1116 break; 1117 } 1118 if(!hp->name) /* match not found */ 1119 return 0; 1120 if(debug) 1121 printhist("hline found ... ", hp, 1); 1122 /* 1123 * unwind the stack until empty or we hit an entry beyond our line 1124 */ 1125 ln = *line; 1126 offset = hp->line-1; 1127 depth = 1; 1128 for(hp++; depth && hp->name; hp++) { 1129 if(debug) 1130 printhist("hline inspect ... ", hp, 1); 1131 if(hp->name[1] || hp->name[2]) { 1132 if(hp->offset){ /* Z record */ 1133 offset = 0; 1134 if(hcomp(hp, name)) { 1135 if(*line <= hp->offset) 1136 break; 1137 ln = *line+hp->line-hp->offset; 1138 depth = 1; /* implicit pop */ 1139 } else 1140 depth = 2; /* implicit push */ 1141 } else if(depth == 1 && ln < hp->line-offset) 1142 break; /* Beyond our line */ 1143 else if(depth++ == 1) /* push */ 1144 offset -= hp->line; 1145 } else if(--depth == 1) /* pop */ 1146 offset += hp->line; 1147 } 1148 *line = ln+offset; 1149 return 1; 1150 } 1151 1152 /* 1153 * compare two encoded file names 1154 */ 1155 static int 1156 hcomp(Hist *hp, short *sp) 1157 { 1158 uchar *cp; 1159 int i, j; 1160 short *s; 1161 1162 cp = (uchar *)hp->name; 1163 s = sp; 1164 if (*s == 0) 1165 return 0; 1166 for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) { 1167 if(j == 0) 1168 break; 1169 if(*s == j) 1170 s++; 1171 else 1172 s = sp; 1173 } 1174 return *s == 0; 1175 } 1176 1177 /* 1178 * Convert a pc to a "file:line {file:line}" string. 1179 */ 1180 int32 1181 fileline(char *str, int n, uvlong dot) 1182 { 1183 int32 line, top, bot, mid; 1184 File *f; 1185 1186 if(isgo12pcline()) 1187 return go12fileline(str, n, dot); 1188 1189 *str = 0; 1190 if(buildtbls() == 0) 1191 return 0; 1192 /* binary search assumes file list is sorted by addr */ 1193 bot = 0; 1194 top = nfiles; 1195 for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) { 1196 f = &files[mid]; 1197 if(dot < f->addr) 1198 top = mid; 1199 else if(mid < nfiles-1 && dot >= (f+1)->addr) 1200 bot = mid; 1201 else { 1202 line = pc2line(dot); 1203 if(line > 0 && fline(str, n, line, f->hist, 0) >= 0) 1204 return 1; 1205 break; 1206 } 1207 } 1208 return 0; 1209 } 1210 1211 /* 1212 * Convert a line number within a composite file to relative line 1213 * number in a source file. A composite file is the source 1214 * file with included files inserted in line. 1215 */ 1216 static int 1217 fline(char *str, int n, int32 line, Hist *base, Hist **ret) 1218 { 1219 Hist *start; /* start of current level */ 1220 Hist *h; /* current entry */ 1221 int32 delta; /* sum of size of files this level */ 1222 int k; 1223 1224 start = base; 1225 h = base; 1226 delta = h->line; 1227 while(h && h->name && line > h->line) { 1228 if(h->name[1] || h->name[2]) { 1229 if(h->offset != 0) { /* #line Directive */ 1230 delta = h->line-h->offset+1; 1231 start = h; 1232 base = h++; 1233 } else { /* beginning of File */ 1234 if(start == base) 1235 start = h++; 1236 else { 1237 k = fline(str, n, line, start, &h); 1238 if(k <= 0) 1239 return k; 1240 } 1241 } 1242 } else { 1243 if(start == base && ret) { /* end of recursion level */ 1244 *ret = h; 1245 return 1; 1246 } else { /* end of included file */ 1247 delta += h->line-start->line; 1248 h++; 1249 start = base; 1250 } 1251 } 1252 } 1253 if(!h) 1254 return -1; 1255 if(start != base) 1256 line = line-start->line+1; 1257 else 1258 line = line-delta+1; 1259 if(!h->name) 1260 strncpy(str, "<eof>", n); 1261 else { 1262 k = fileelem(fnames, (uchar*)start->name, str, n); 1263 if(k+8 < n) 1264 sprint(str+k, ":%d", line); 1265 } 1266 /**********Remove comments for complete back-trace of include sequence 1267 * if(start != base) { 1268 * k = strlen(str); 1269 * if(k+2 < n) { 1270 * str[k++] = ' '; 1271 * str[k++] = '{'; 1272 * } 1273 * k += fileelem(fnames, (uchar*) base->name, str+k, n-k); 1274 * if(k+10 < n) 1275 * sprint(str+k, ":%ld}", start->line-delta); 1276 * } 1277 ********************/ 1278 return 0; 1279 } 1280 1281 /* 1282 * convert an encoded file name to a string. 1283 */ 1284 int 1285 fileelem(Sym **fp, uchar *cp, char *buf, int n) 1286 { 1287 int i, j; 1288 char *c, *bp, *end; 1289 1290 bp = buf; 1291 end = buf+n-1; 1292 for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){ 1293 c = fp[j]->name; 1294 if(bp != buf && bp[-1] != '/' && bp < end) 1295 *bp++ = '/'; 1296 while(bp < end && *c) 1297 *bp++ = *c++; 1298 } 1299 *bp = 0; 1300 i = bp-buf; 1301 if(i > 1) { 1302 cleanname(buf); 1303 i = strlen(buf); 1304 } 1305 return i; 1306 } 1307 1308 /* 1309 * compare the values of two symbol table entries. 1310 */ 1311 static int 1312 symcomp(const void *a, const void *b) 1313 { 1314 int i; 1315 1316 i = (*(Sym**)a)->value - (*(Sym**)b)->value; 1317 if (i) 1318 return i; 1319 return strcmp((*(Sym**)a)->name, (*(Sym**)b)->name); 1320 } 1321 1322 /* 1323 * compare the values of the symbols referenced by two text table entries 1324 */ 1325 static int 1326 txtcomp(const void *a, const void *b) 1327 { 1328 return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value; 1329 } 1330 1331 /* 1332 * compare the values of the symbols referenced by two file table entries 1333 */ 1334 static int 1335 filecomp(const void *a, const void *b) 1336 { 1337 return ((File*)a)->addr - ((File*)b)->addr; 1338 } 1339 1340 /* 1341 * fill an interface Symbol structure from a symbol table entry 1342 */ 1343 static void 1344 fillsym(Sym *sp, Symbol *s) 1345 { 1346 s->type = sp->type; 1347 s->value = sp->value; 1348 s->name = sp->name; 1349 s->index = 0; 1350 switch(sp->type) { 1351 case 'b': 1352 case 'B': 1353 case 'D': 1354 case 'd': 1355 s->class = CDATA; 1356 break; 1357 case 't': 1358 case 'T': 1359 case 'l': 1360 case 'L': 1361 s->class = CTEXT; 1362 break; 1363 case 'a': 1364 s->class = CAUTO; 1365 break; 1366 case 'p': 1367 s->class = CPARAM; 1368 break; 1369 case 'm': 1370 s->class = CSTAB; 1371 break; 1372 default: 1373 s->class = CNONE; 1374 break; 1375 } 1376 s->handle = 0; 1377 } 1378 1379 /* 1380 * find the stack frame, given the pc 1381 */ 1382 uvlong 1383 pc2sp(uvlong pc) 1384 { 1385 uchar *c, u; 1386 uvlong currpc, currsp; 1387 1388 if(isgo12pcline()) 1389 return go12pc2sp(pc); 1390 1391 if(spoff == 0) 1392 return ~(uvlong)0; 1393 currsp = 0; 1394 currpc = txtstart - mach->pcquant; 1395 1396 if(pc<currpc || pc>txtend) 1397 return ~(uvlong)0; 1398 for(c = spoff; c < spoffend; c++) { 1399 if (currpc >= pc) 1400 return currsp; 1401 u = *c; 1402 if (u == 0) { 1403 currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4]; 1404 c += 4; 1405 } 1406 else if (u < 65) 1407 currsp += 4*u; 1408 else if (u < 129) 1409 currsp -= 4*(u-64); 1410 else 1411 currpc += mach->pcquant*(u-129); 1412 currpc += mach->pcquant; 1413 } 1414 return ~(uvlong)0; 1415 } 1416 1417 /* 1418 * find the source file line number for a given value of the pc 1419 */ 1420 int32 1421 pc2line(uvlong pc) 1422 { 1423 uchar *c, u; 1424 uvlong currpc; 1425 int32 currline; 1426 1427 if(pcline == 0) 1428 return -1; 1429 currline = 0; 1430 if (firstinstr != 0) 1431 currpc = firstinstr-mach->pcquant; 1432 else 1433 currpc = txtstart-mach->pcquant; 1434 if(pc<currpc || pc>txtend) 1435 return -1; 1436 1437 for(c = pcline; c < pclineend && currpc < pc; c++) { 1438 u = *c; 1439 if(u == 0) { 1440 currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4]; 1441 c += 4; 1442 } 1443 else if(u < 65) 1444 currline += u; 1445 else if(u < 129) 1446 currline -= (u-64); 1447 else 1448 currpc += mach->pcquant*(u-129); 1449 currpc += mach->pcquant; 1450 } 1451 return currline; 1452 } 1453 1454 /* 1455 * find the pc associated with a line number 1456 * basepc and endpc are text addresses bounding the search. 1457 * if endpc == 0, the end of the table is used (i.e., no upper bound). 1458 * usually, basepc and endpc contain the first text address in 1459 * a file and the first text address in the following file, respectively. 1460 */ 1461 uvlong 1462 line2addr(int32 line, uvlong basepc, uvlong endpc) 1463 { 1464 uchar *c, u; 1465 uvlong currpc, pc; 1466 int32 currline; 1467 int32 delta, d; 1468 int found; 1469 1470 if(pcline == 0 || line == 0) 1471 return ~(uvlong)0; 1472 1473 currline = 0; 1474 currpc = txtstart-mach->pcquant; 1475 pc = ~(uvlong)0; 1476 found = 0; 1477 delta = HUGEINT; 1478 1479 for(c = pcline; c < pclineend; c++) { 1480 if(endpc && currpc >= endpc) /* end of file of interest */ 1481 break; 1482 if(currpc >= basepc) { /* proper file */ 1483 if(currline >= line) { 1484 d = currline-line; 1485 found = 1; 1486 } else 1487 d = line-currline; 1488 if(d < delta) { 1489 delta = d; 1490 pc = currpc; 1491 } 1492 } 1493 u = *c; 1494 if(u == 0) { 1495 currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4]; 1496 c += 4; 1497 } 1498 else if(u < 65) 1499 currline += u; 1500 else if(u < 129) 1501 currline -= (u-64); 1502 else 1503 currpc += mach->pcquant*(u-129); 1504 currpc += mach->pcquant; 1505 } 1506 if(found) 1507 return pc; 1508 return ~(uvlong)0; 1509 } 1510 1511 /* 1512 * Print a history stack (debug). if count is 0, prints the whole stack 1513 */ 1514 static void 1515 printhist(char *msg, Hist *hp, int count) 1516 { 1517 int i; 1518 uchar *cp; 1519 char buf[128]; 1520 1521 i = 0; 1522 while(hp->name) { 1523 if(count && ++i > count) 1524 break; 1525 print("%s Line: %x (%d) Offset: %x (%d) Name: ", msg, 1526 hp->line, hp->line, hp->offset, hp->offset); 1527 for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) { 1528 if (cp != (uchar *)hp->name+1) 1529 print("/"); 1530 print("%x", (*cp<<8)|cp[1]); 1531 } 1532 fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf)); 1533 print(" (%s)\n", buf); 1534 hp++; 1535 } 1536 } 1537 1538 #ifdef DEBUG 1539 /* 1540 * print the history stack for a file. (debug only) 1541 * if (name == 0) => print all history stacks. 1542 */ 1543 void 1544 dumphist(char *name) 1545 { 1546 int i; 1547 File *f; 1548 short *fname; 1549 1550 if(buildtbls() == 0) 1551 return; 1552 if(name) 1553 fname = encfname(name); 1554 for(i = 0, f = files; i < nfiles; i++, f++) 1555 if(fname == 0 || hcomp(f->hist, fname)) 1556 printhist("> ", f->hist, f->n); 1557 1558 if(fname) 1559 free(fname); 1560 } 1561 #endif 1562 1563 // Go 1.2 pcln table 1564 // See golang.org/s/go12symtab. 1565 1566 // Func layout 1567 #define FuncEntry (0) 1568 #define FuncName (pcptrsize) 1569 #define FuncArgs (pcptrsize+4) 1570 #define FuncFrame (pcptrsize+2*4) 1571 #define FuncPCSP (pcptrsize+3*4) 1572 #define FuncPCFile (pcptrsize+4*4) 1573 #define FuncPCLine (pcptrsize+5*4) 1574 1575 static int32 pcquantum; 1576 static int32 pcptrsize; 1577 static uvlong (*pcswav)(uvlong); 1578 static uint32 (*pcswal)(uint32); 1579 static uvlong (*pcuintptr)(uchar*); 1580 static uchar *functab; 1581 static uint32 nfunctab; 1582 static uint32 *filetab; 1583 static uint32 nfiletab; 1584 1585 static uint32 1586 xswal(uint32 v) 1587 { 1588 return (v>>24) | ((v>>8)&0xFF00) | ((v<<8)&0xFF0000) | v<<24; 1589 } 1590 1591 static uvlong 1592 xswav(uvlong v) 1593 { 1594 return (uvlong)xswal(v)<<32 | xswal(v>>32); 1595 } 1596 1597 static uvlong 1598 noswav(uvlong v) 1599 { 1600 return v; 1601 } 1602 1603 static uint32 1604 noswal(uint32 v) 1605 { 1606 return v; 1607 } 1608 1609 static uvlong 1610 readuintptr64(uchar *p) 1611 { 1612 return pcswav(*(uvlong*)p); 1613 } 1614 1615 static uvlong 1616 readuintptr32(uchar *p) 1617 { 1618 return pcswal(*(uint32*)p); 1619 } 1620 1621 static void 1622 go12clean(void) 1623 { 1624 pcquantum = 0; 1625 pcswav = nil; 1626 pcswal = nil; 1627 functab = nil; 1628 nfunctab = 0; 1629 filetab = nil; 1630 nfiletab = 0; 1631 } 1632 1633 static void 1634 go12init(void) 1635 { 1636 uint32 m; 1637 uchar *p; 1638 1639 if(pcquantum != 0) 1640 return; 1641 pcquantum = -1; // not go 1.2 1642 if(pcline == nil || pclineend - pcline < 16 || 1643 pcline[4] != 0 || pcline[5] != 0 || 1644 (pcline[6] != 1 && pcline[6] != 4) || 1645 (pcline[7] != 4 && pcline[7] != 8)) 1646 return; 1647 1648 // header is magic, 00 00 pcquantum ptrsize 1649 m = *(uint32*)pcline; 1650 if(m == Go12PclnMagic) { 1651 pcswav = noswav; 1652 pcswal = noswal; 1653 } else { 1654 pcswav = xswav; 1655 pcswal = xswal; 1656 } 1657 pcptrsize = pcline[7]; 1658 1659 if(pcptrsize == 4) 1660 pcuintptr = readuintptr32; 1661 else 1662 pcuintptr = readuintptr64; 1663 1664 nfunctab = pcuintptr(pcline+8); 1665 functab = pcline + 8 + pcptrsize; 1666 1667 // functab is 2*nfunctab pointer-sized values. 1668 // The offset to the file table follows. 1669 p = functab + nfunctab*2*pcptrsize + pcptrsize; 1670 if(p+4 > pclineend) 1671 return; 1672 filetab = (uint32*)(pcline + pcswal(*(uint32*)p)); 1673 if((uchar*)filetab+4 > pclineend) 1674 return; 1675 1676 // File table begins with count. 1677 nfiletab = pcswal(filetab[0]); 1678 if((uchar*)(filetab + nfiletab) > pclineend) 1679 return; 1680 1681 // Committed. 1682 pcquantum = pcline[6]; 1683 } 1684 1685 static int 1686 isgo12pcline(void) 1687 { 1688 go12init(); 1689 return pcquantum > 0; 1690 } 1691 1692 static uchar* 1693 go12findfunc(uvlong pc) 1694 { 1695 uchar *f, *fm; 1696 int32 nf, m; 1697 1698 if(pc < pcuintptr(functab) || pc >= pcuintptr(functab+2*nfunctab*pcptrsize)) 1699 return nil; 1700 1701 // binary search to find func with entry <= addr. 1702 f = functab; 1703 nf = nfunctab; 1704 while(nf > 0) { 1705 m = nf/2; 1706 fm = f + 2*pcptrsize*m; 1707 if(pcuintptr(fm) <= pc && pc < pcuintptr(fm+2*pcptrsize)) { 1708 f = pcline + pcuintptr(fm+pcptrsize); 1709 if(f >= pclineend) 1710 return nil; 1711 return f; 1712 } else if(pc < pcuintptr(fm)) 1713 nf = m; 1714 else { 1715 f += (m+1)*2*pcptrsize; 1716 nf -= m+1; 1717 } 1718 } 1719 return nil; 1720 } 1721 1722 static uint32 1723 readvarint(uchar **pp) 1724 { 1725 uchar *p; 1726 uint32 v; 1727 int32 shift; 1728 1729 v = 0; 1730 p = *pp; 1731 for(shift = 0;; shift += 7) { 1732 v |= (*p & 0x7F) << shift; 1733 if(!(*p++ & 0x80)) 1734 break; 1735 } 1736 *pp = p; 1737 return v; 1738 } 1739 1740 static char* 1741 pcstring(uint32 off) 1742 { 1743 if(off == 0 || off >= pclineend - pcline || 1744 memchr(pcline + off, '\0', pclineend - (pcline + off)) == nil) 1745 return "?"; 1746 return (char*)pcline+off; 1747 } 1748 1749 1750 static int 1751 step(uchar **pp, uvlong *pc, int32 *value, int first) 1752 { 1753 uint32 uvdelta, pcdelta; 1754 int32 vdelta; 1755 1756 uvdelta = readvarint(pp); 1757 if(uvdelta == 0 && !first) 1758 return 0; 1759 if(uvdelta&1) 1760 uvdelta = ~(uvdelta>>1); 1761 else 1762 uvdelta >>= 1; 1763 vdelta = (int32)uvdelta; 1764 pcdelta = readvarint(pp) * pcquantum; 1765 *value += vdelta; 1766 *pc += pcdelta; 1767 return 1; 1768 } 1769 1770 static int32 1771 pcvalue(uint32 off, uvlong entry, uvlong targetpc) 1772 { 1773 uvlong pc; 1774 int32 val; 1775 uchar *p; 1776 1777 val = -1; 1778 pc = entry; 1779 if(off == 0 || off >= pclineend - pcline) 1780 return -1; 1781 p = pcline + off; 1782 while(step(&p, &pc, &val, pc == entry)) { 1783 if(targetpc < pc) 1784 return val; 1785 } 1786 return -1; 1787 } 1788 1789 static uvlong 1790 go12pc2sp(uvlong pc) 1791 { 1792 uchar *f; 1793 uint32 off; 1794 uvlong entry; 1795 int32 sp; 1796 1797 f = go12findfunc(pc); 1798 if(f == nil) 1799 return ~(uvlong)0; 1800 entry = pcuintptr(f+FuncEntry); 1801 off = pcswal(*(uint32*)(f+FuncPCSP)); 1802 sp = pcvalue(off, entry, pc); 1803 if(sp < 0) 1804 return ~(uvlong)0; 1805 return sp; 1806 } 1807 1808 static int32 1809 go12fileline(char *str, int n, uvlong pc) 1810 { 1811 uchar *f; 1812 uint32 fileoff, lineoff; 1813 uvlong entry; 1814 int lno, fno; 1815 1816 f = go12findfunc(pc); 1817 if(f == nil) 1818 return 0; 1819 entry = pcuintptr(f+FuncEntry); 1820 fileoff = pcswal(*(uint32*)(f+FuncPCFile)); 1821 lineoff = pcswal(*(uint32*)(f+FuncPCLine)); 1822 lno = pcvalue(lineoff, entry, pc); 1823 fno = pcvalue(fileoff, entry, pc); 1824 if(lno < 0 || fno <= 0 || fno >= nfiletab) { 1825 return 0; 1826 } 1827 snprint(str, n, "%s:%d", pcstring(pcswal(filetab[fno])), lno); 1828 return 1; 1829 } 1830 1831 static uvlong 1832 go12file2pc(char *file, int line) 1833 { 1834 int fno; 1835 int32 i, fval, lval; 1836 uchar *func, *fp, *lp; 1837 uvlong fpc, lpc, fstartpc, lstartpc, entry; 1838 1839 // Map file to file number. 1840 // NOTE(rsc): Could introduce a hash table for repeated 1841 // lookups if anyone ever calls this. 1842 for(fno=1; fno<nfiletab; fno++) 1843 if(strcmp(pcstring(pcswal(filetab[fno])), file) == 0) 1844 goto havefile; 1845 werrstr("cannot find file"); 1846 return ~(uvlong)0; 1847 1848 havefile: 1849 // Consider each func. 1850 // Run file number program to find file match, 1851 // then run line number program to find line match. 1852 // Most file number programs are tiny, and most will 1853 // not mention the file number, so this should be fairly 1854 // quick. 1855 for(i=0; i<nfunctab; i++) { 1856 func = pcline + pcuintptr(functab+i*2*pcptrsize+pcptrsize); 1857 entry = pcuintptr(func+FuncEntry); 1858 fp = pcline + pcswal(*(uint32*)(func+FuncPCFile)); 1859 lp = pcline + pcswal(*(uint32*)(func+FuncPCLine)); 1860 fval = lval = -1; 1861 fpc = lpc = entry; 1862 fstartpc = fpc; 1863 while(step(&fp, &fpc, &fval, fpc==entry)) { 1864 if(fval == fno && fstartpc < fpc) { 1865 lstartpc = lpc; 1866 while(lpc < fpc && step(&lp, &lpc, &lval, lpc==entry)) { 1867 if(lval == line) { 1868 if(fstartpc <= lstartpc) { 1869 return lstartpc; 1870 } 1871 if(fstartpc < lpc) { 1872 return fstartpc; 1873 } 1874 } 1875 lstartpc = lpc; 1876 } 1877 } 1878 fstartpc = fpc; 1879 } 1880 } 1881 werrstr("cannot find line in file"); 1882 return ~(uvlong)0; 1883 }