github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/symtab.c (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Runtime symbol table parsing. 6 // 7 // The Go tools use a symbol table derived from the Plan 9 symbol table 8 // format. The symbol table is kept in its own section treated as 9 // read-only memory when the binary is running: the binary consults the 10 // table. 11 // 12 // The format used by Go 1.0 was basically the Plan 9 format. Each entry 13 // is variable sized but had this format: 14 // 15 // 4-byte value, big endian 16 // 1-byte type ([A-Za-z] + 0x80) 17 // name, NUL terminated (or for 'z' and 'Z' entries, double-NUL terminated) 18 // 4-byte Go type address, big endian (new in Go) 19 // 20 // In order to support greater interoperation with standard toolchains, 21 // Go 1.1 uses a more flexible yet smaller encoding of the entries. 22 // The overall structure is unchanged from Go 1.0 and, for that matter, 23 // from Plan 9. 24 // 25 // The Go 1.1 table is a re-encoding of the data in a Go 1.0 table. 26 // To identify a new table as new, it begins one of two eight-byte 27 // sequences: 28 // 29 // FF FF FF FD 00 00 00 xx - big endian new table 30 // FD FF FF FF 00 00 00 xx - little endian new table 31 // 32 // This sequence was chosen because old tables stop at an entry with type 33 // 0, so old code reading a new table will see only an empty table. The 34 // first four bytes are the target-endian encoding of 0xfffffffd. The 35 // final xx gives AddrSize, the width of a full-width address. 36 // 37 // After that header, each entry is encoded as follows. 38 // 39 // 1-byte type (0-51 + two flag bits) 40 // AddrSize-byte value, host-endian OR varint-encoded value 41 // AddrSize-byte Go type address OR nothing 42 // [n] name, terminated as before 43 // 44 // The type byte comes first, but 'A' encodes as 0 and 'a' as 26, so that 45 // the type itself is only in the low 6 bits. The upper two bits specify 46 // the format of the next two fields. If the 0x40 bit is set, the value 47 // is encoded as an full-width 4- or 8-byte target-endian word. Otherwise 48 // the value is a varint-encoded number. If the 0x80 bit is set, the Go 49 // type is present, again as a 4- or 8-byte target-endian word. If not, 50 // there is no Go type in this entry. The NUL-terminated name ends the 51 // entry. 52 53 #include "runtime.h" 54 #include "defs_GOOS_GOARCH.h" 55 #include "os_GOOS.h" 56 #include "arch_GOARCH.h" 57 #include "malloc.h" 58 59 extern byte pclntab[], epclntab[], symtab[], esymtab[]; 60 61 typedef struct Sym Sym; 62 struct Sym 63 { 64 uintptr value; 65 byte symtype; 66 byte *name; 67 // byte *gotype; 68 }; 69 70 static uintptr mainoffset; 71 72 // A dynamically allocated string containing multiple substrings. 73 // Individual strings are slices of hugestring. 74 static String hugestring; 75 static int32 hugestring_len; 76 77 extern void main·main(void); 78 79 static uintptr 80 readword(byte **pp, byte *ep) 81 { 82 byte *p; 83 84 p = *pp; 85 if(ep - p < sizeof(void*)) { 86 *pp = ep; 87 return 0; 88 } 89 *pp = p + sizeof(void*); 90 91 // Hairy, but only one of these four cases gets compiled. 92 if(sizeof(void*) == 8) { 93 if(BigEndian) { 94 return ((uint64)p[0]<<56) | ((uint64)p[1]<<48) | ((uint64)p[2]<<40) | ((uint64)p[3]<<32) | 95 ((uint64)p[4]<<24) | ((uint64)p[5]<<16) | ((uint64)p[6]<<8) | ((uint64)p[7]); 96 } 97 return ((uint64)p[7]<<56) | ((uint64)p[6]<<48) | ((uint64)p[5]<<40) | ((uint64)p[4]<<32) | 98 ((uint64)p[3]<<24) | ((uint64)p[2]<<16) | ((uint64)p[1]<<8) | ((uint64)p[0]); 99 } 100 if(BigEndian) { 101 return ((uint32)p[0]<<24) | ((uint32)p[1]<<16) | ((uint32)p[2]<<8) | ((uint32)p[3]); 102 } 103 return ((uint32)p[3]<<24) | ((uint32)p[2]<<16) | ((uint32)p[1]<<8) | ((uint32)p[0]); 104 } 105 106 // Walk over symtab, calling fn(&s) for each symbol. 107 static void 108 walksymtab(void (*fn)(Sym*)) 109 { 110 byte *p, *ep, *q; 111 Sym s; 112 int32 widevalue, havetype, shift; 113 114 p = symtab; 115 ep = esymtab; 116 117 // Table must begin with correct magic number. 118 if(ep - p < 8 || p[4] != 0x00 || p[5] != 0x00 || p[6] != 0x00 || p[7] != sizeof(void*)) 119 return; 120 if(BigEndian) { 121 if(p[0] != 0xff || p[1] != 0xff || p[2] != 0xff || p[3] != 0xfd) 122 return; 123 } else { 124 if(p[0] != 0xfd || p[1] != 0xff || p[2] != 0xff || p[3] != 0xff) 125 return; 126 } 127 p += 8; 128 129 while(p < ep) { 130 s.symtype = p[0]&0x3F; 131 widevalue = p[0]&0x40; 132 havetype = p[0]&0x80; 133 if(s.symtype < 26) 134 s.symtype += 'A'; 135 else 136 s.symtype += 'a' - 26; 137 p++; 138 139 // Value, either full-width or varint-encoded. 140 if(widevalue) { 141 s.value = readword(&p, ep); 142 } else { 143 s.value = 0; 144 shift = 0; 145 while(p < ep && (p[0]&0x80) != 0) { 146 s.value |= (uintptr)(p[0]&0x7F)<<shift; 147 shift += 7; 148 p++; 149 } 150 if(p >= ep) 151 break; 152 s.value |= (uintptr)p[0]<<shift; 153 p++; 154 } 155 156 // Go type, if present. Ignored but must skip over. 157 if(havetype) 158 readword(&p, ep); 159 160 // Name. 161 if(ep - p < 2) 162 break; 163 164 s.name = p; 165 if(s.symtype == 'z' || s.symtype == 'Z') { 166 // path reference string - skip first byte, 167 // then 2-byte pairs ending at two zeros. 168 q = p+1; 169 for(;;) { 170 if(q+2 > ep) 171 return; 172 if(q[0] == '\0' && q[1] == '\0') 173 break; 174 q += 2; 175 } 176 p = q+2; 177 }else{ 178 q = runtime·mchr(p, '\0', ep); 179 if(q == nil) 180 break; 181 p = q+1; 182 } 183 184 fn(&s); 185 } 186 } 187 188 // Symtab walker; accumulates info about functions. 189 190 static Func *func; 191 static int32 nfunc; 192 193 static byte **fname; 194 static int32 nfname; 195 196 static uint32 funcinit; 197 static Lock funclock; 198 static uintptr lastvalue; 199 200 static void 201 dofunc(Sym *sym) 202 { 203 Func *f; 204 205 switch(sym->symtype) { 206 case 't': 207 case 'T': 208 case 'l': 209 case 'L': 210 if(runtime·strcmp(sym->name, (byte*)"etext") == 0) 211 break; 212 if(sym->value < lastvalue) { 213 runtime·printf("symbols out of order: %p before %p\n", lastvalue, sym->value); 214 runtime·throw("malformed symbol table"); 215 } 216 lastvalue = sym->value; 217 if(func == nil) { 218 nfunc++; 219 break; 220 } 221 f = &func[nfunc++]; 222 f->name = runtime·gostringnocopy(sym->name); 223 f->entry = sym->value; 224 if(sym->symtype == 'L' || sym->symtype == 'l') 225 f->frame = -sizeof(uintptr); 226 break; 227 case 'm': 228 if(nfunc <= 0 || func == nil) 229 break; 230 if(runtime·strcmp(sym->name, (byte*)".frame") == 0) 231 func[nfunc-1].frame = sym->value; 232 else if(runtime·strcmp(sym->name, (byte*)".locals") == 0) 233 func[nfunc-1].locals = sym->value; 234 else if(runtime·strcmp(sym->name, (byte*)".args") == 0) 235 func[nfunc-1].args = sym->value; 236 else { 237 runtime·printf("invalid 'm' symbol named '%s'\n", sym->name); 238 runtime·throw("mangled symbol table"); 239 } 240 break; 241 case 'f': 242 if(fname == nil) { 243 if(sym->value >= nfname) { 244 if(sym->value >= 0x10000) { 245 runtime·printf("runtime: invalid symbol file index %p\n", sym->value); 246 runtime·throw("mangled symbol table"); 247 } 248 nfname = sym->value+1; 249 } 250 break; 251 } 252 fname[sym->value] = sym->name; 253 break; 254 } 255 } 256 257 // put together the path name for a z entry. 258 // the f entries have been accumulated into fname already. 259 // returns the length of the path name. 260 static int32 261 makepath(byte *buf, int32 nbuf, byte *path) 262 { 263 int32 n, len; 264 byte *p, *ep, *q; 265 266 if(nbuf <= 0) 267 return 0; 268 269 p = buf; 270 ep = buf + nbuf; 271 *p = '\0'; 272 for(;;) { 273 if(path[0] == 0 && path[1] == 0) 274 break; 275 n = (path[0]<<8) | path[1]; 276 path += 2; 277 if(n >= nfname) 278 break; 279 q = fname[n]; 280 len = runtime·findnull(q); 281 if(p+1+len >= ep) 282 break; 283 if(p > buf && p[-1] != '/') 284 *p++ = '/'; 285 runtime·memmove(p, q, len+1); 286 p += len; 287 } 288 return p - buf; 289 } 290 291 // appends p to hugestring 292 static String 293 gostringn(byte *p, int32 l) 294 { 295 String s; 296 297 if(l == 0) 298 return runtime·emptystring; 299 if(hugestring.str == nil) { 300 hugestring_len += l; 301 return runtime·emptystring; 302 } 303 s.str = hugestring.str + hugestring.len; 304 s.len = l; 305 hugestring.len += s.len; 306 runtime·memmove(s.str, p, l); 307 return s; 308 } 309 310 // walk symtab accumulating path names for use by pc/ln table. 311 // don't need the full generality of the z entry history stack because 312 // there are no includes in go (and only sensible includes in our c); 313 // assume code only appear in top-level files. 314 static void 315 dosrcline(Sym *sym) 316 { 317 static byte srcbuf[1000]; 318 static struct { 319 String srcstring; 320 int32 aline; 321 int32 delta; 322 } files[200]; 323 static int32 incstart; 324 static int32 nfunc, nfile, nhist; 325 Func *f; 326 int32 i, l; 327 328 switch(sym->symtype) { 329 case 't': 330 case 'T': 331 if(hugestring.str == nil) 332 break; 333 if(runtime·strcmp(sym->name, (byte*)"etext") == 0) 334 break; 335 f = &func[nfunc++]; 336 // find source file 337 for(i = 0; i < nfile - 1; i++) { 338 if (files[i+1].aline > f->ln0) 339 break; 340 } 341 f->src = files[i].srcstring; 342 f->ln0 -= files[i].delta; 343 break; 344 case 'z': 345 if(sym->value == 1) { 346 // entry for main source file for a new object. 347 l = makepath(srcbuf, sizeof srcbuf, sym->name+1); 348 nhist = 0; 349 nfile = 0; 350 if(nfile == nelem(files)) 351 return; 352 files[nfile].srcstring = gostringn(srcbuf, l); 353 files[nfile].aline = 0; 354 files[nfile++].delta = 0; 355 } else { 356 // push or pop of included file. 357 l = makepath(srcbuf, sizeof srcbuf, sym->name+1); 358 if(srcbuf[0] != '\0') { 359 if(nhist++ == 0) 360 incstart = sym->value; 361 if(nhist == 0 && nfile < nelem(files)) { 362 // new top-level file 363 files[nfile].srcstring = gostringn(srcbuf, l); 364 files[nfile].aline = sym->value; 365 // this is "line 0" 366 files[nfile++].delta = sym->value - 1; 367 } 368 }else{ 369 if(--nhist == 0) 370 files[nfile-1].delta += sym->value - incstart; 371 } 372 } 373 } 374 } 375 376 // Interpret pc/ln table, saving the subpiece for each func. 377 static void 378 splitpcln(void) 379 { 380 int32 line; 381 uintptr pc; 382 byte *p, *ep; 383 Func *f, *ef; 384 int32 pcquant; 385 386 if(pclntab == epclntab || nfunc == 0) 387 return; 388 389 switch(thechar) { 390 case '5': 391 pcquant = 4; 392 break; 393 default: // 6, 8 394 pcquant = 1; 395 break; 396 } 397 398 // pc/ln table bounds 399 p = pclntab; 400 ep = epclntab; 401 402 f = func; 403 ef = func + nfunc; 404 pc = func[0].entry; // text base 405 f->pcln.array = p; 406 f->pc0 = pc; 407 line = 0; 408 for(;;) { 409 while(p < ep && *p > 128) 410 pc += pcquant * (*p++ - 128); 411 // runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line); 412 if(*p == 0) { 413 if(p+5 > ep) 414 break; 415 // 4 byte add to line 416 line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4]; 417 p += 5; 418 } else if(*p <= 64) 419 line += *p++; 420 else 421 line -= *p++ - 64; 422 423 // pc, line now match. 424 // Because the state machine begins at pc==entry and line==0, 425 // it can happen - just at the beginning! - that the update may 426 // have updated line but left pc alone, to tell us the true line 427 // number for pc==entry. In that case, update f->ln0. 428 // Having the correct initial line number is important for choosing 429 // the correct file in dosrcline above. 430 if(f == func && pc == f->pc0) { 431 f->pcln.array = p; 432 f->pc0 = pc + pcquant; 433 f->ln0 = line; 434 } 435 436 if(f < ef && pc >= (f+1)->entry) { 437 f->pcln.len = p - f->pcln.array; 438 f->pcln.cap = f->pcln.len; 439 do 440 f++; 441 while(f < ef && pc >= (f+1)->entry); 442 f->pcln.array = p; 443 // pc0 and ln0 are the starting values for 444 // the loop over f->pcln, so pc must be 445 // adjusted by the same pcquant update 446 // that we're going to do as we continue our loop. 447 f->pc0 = pc + pcquant; 448 f->ln0 = line; 449 } 450 451 pc += pcquant; 452 } 453 if(f < ef) { 454 f->pcln.len = p - f->pcln.array; 455 f->pcln.cap = f->pcln.len; 456 } 457 } 458 459 460 // Return actual file line number for targetpc in func f. 461 // (Source file is f->src.) 462 // NOTE(rsc): If you edit this function, also edit extern.go:/FileLine 463 int32 464 runtime·funcline(Func *f, uintptr targetpc) 465 { 466 byte *p, *ep; 467 uintptr pc; 468 int32 line; 469 int32 pcquant; 470 471 enum { 472 debug = 0 473 }; 474 475 switch(thechar) { 476 case '5': 477 pcquant = 4; 478 break; 479 default: // 6, 8 480 pcquant = 1; 481 break; 482 } 483 484 p = f->pcln.array; 485 ep = p + f->pcln.len; 486 pc = f->pc0; 487 line = f->ln0; 488 if(debug && !runtime·panicking) 489 runtime·printf("funcline start pc=%p targetpc=%p line=%d tab=%p+%d\n", 490 pc, targetpc, line, p, (int32)f->pcln.len); 491 for(;;) { 492 // Table is a sequence of updates. 493 494 // Each update says first how to adjust the pc, 495 // in possibly multiple instructions... 496 while(p < ep && *p > 128) 497 pc += pcquant * (*p++ - 128); 498 499 if(debug && !runtime·panicking) 500 runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line); 501 502 // If the pc has advanced too far or we're out of data, 503 // stop and the last known line number. 504 if(pc > targetpc || p >= ep) 505 break; 506 507 // ... and then how to adjust the line number, 508 // in a single instruction. 509 if(*p == 0) { 510 if(p+5 > ep) 511 break; 512 line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4]; 513 p += 5; 514 } else if(*p <= 64) 515 line += *p++; 516 else 517 line -= *p++ - 64; 518 // Now pc, line pair is consistent. 519 if(debug && !runtime·panicking) 520 runtime·printf("pc=%p targetpc=%p line=%d\n", pc, targetpc, line); 521 522 // PC increments implicitly on each iteration. 523 pc += pcquant; 524 } 525 return line; 526 } 527 528 void 529 runtime·funcline_go(Func *f, uintptr targetpc, String retfile, intgo retline) 530 { 531 retfile = f->src; 532 retline = runtime·funcline(f, targetpc); 533 FLUSH(&retfile); 534 FLUSH(&retline); 535 } 536 537 static void 538 buildfuncs(void) 539 { 540 extern byte etext[]; 541 542 if(func != nil) 543 return; 544 545 // Memory profiling uses this code; 546 // can deadlock if the profiler ends 547 // up back here. 548 m->nomemprof++; 549 550 // count funcs, fnames 551 nfunc = 0; 552 nfname = 0; 553 lastvalue = 0; 554 walksymtab(dofunc); 555 556 // Initialize tables. 557 // Can use FlagNoPointers - all pointers either point into sections of the executable 558 // or point into hugestring. 559 func = runtime·mallocgc((nfunc+1)*sizeof func[0], FlagNoPointers, 0, 1); 560 func[nfunc].entry = (uint64)etext; 561 fname = runtime·mallocgc(nfname*sizeof fname[0], FlagNoPointers, 0, 1); 562 nfunc = 0; 563 lastvalue = 0; 564 walksymtab(dofunc); 565 566 // split pc/ln table by func 567 splitpcln(); 568 569 // record src file and line info for each func 570 walksymtab(dosrcline); // pass 1: determine hugestring_len 571 hugestring.str = runtime·mallocgc(hugestring_len, FlagNoPointers, 0, 0); 572 hugestring.len = 0; 573 walksymtab(dosrcline); // pass 2: fill and use hugestring 574 575 if(hugestring.len != hugestring_len) 576 runtime·throw("buildfunc: problem in initialization procedure"); 577 578 m->nomemprof--; 579 } 580 581 Func* 582 runtime·findfunc(uintptr addr) 583 { 584 Func *f; 585 int32 nf, n; 586 587 // Use atomic double-checked locking, 588 // because when called from pprof signal 589 // handler, findfunc must run without 590 // grabbing any locks. 591 // (Before enabling the signal handler, 592 // SetCPUProfileRate calls findfunc to trigger 593 // the initialization outside the handler.) 594 // Avoid deadlock on fault during malloc 595 // by not calling buildfuncs if we're already in malloc. 596 if(!m->mallocing && !m->gcing) { 597 if(runtime·atomicload(&funcinit) == 0) { 598 runtime·lock(&funclock); 599 if(funcinit == 0) { 600 buildfuncs(); 601 runtime·atomicstore(&funcinit, 1); 602 } 603 runtime·unlock(&funclock); 604 } 605 } 606 607 if(nfunc == 0) 608 return nil; 609 if(addr < func[0].entry || addr >= func[nfunc].entry) 610 return nil; 611 612 // binary search to find func with entry <= addr. 613 f = func; 614 nf = nfunc; 615 while(nf > 0) { 616 n = nf/2; 617 if(f[n].entry <= addr && addr < f[n+1].entry) 618 return &f[n]; 619 else if(addr < f[n].entry) 620 nf = n; 621 else { 622 f += n+1; 623 nf -= n+1; 624 } 625 } 626 627 // can't get here -- we already checked above 628 // that the address was in the table bounds. 629 // this can only happen if the table isn't sorted 630 // by address or if the binary search above is buggy. 631 runtime·prints("findfunc unreachable\n"); 632 return nil; 633 } 634 635 static bool 636 hasprefix(String s, int8 *p) 637 { 638 int32 i; 639 640 for(i=0; i<s.len; i++) { 641 if(p[i] == 0) 642 return 1; 643 if(p[i] != s.str[i]) 644 return 0; 645 } 646 return p[i] == 0; 647 } 648 649 static bool 650 contains(String s, int8 *p) 651 { 652 int32 i; 653 654 if(p[0] == 0) 655 return 1; 656 for(i=0; i<s.len; i++) { 657 if(s.str[i] != p[0]) 658 continue; 659 if(hasprefix((String){s.str + i, s.len - i}, p)) 660 return 1; 661 } 662 return 0; 663 } 664 665 bool 666 runtime·showframe(Func *f, bool current) 667 { 668 static int32 traceback = -1; 669 670 if(current && m->throwing > 0) 671 return 1; 672 if(traceback < 0) 673 traceback = runtime·gotraceback(nil); 674 return traceback > 1 || f != nil && contains(f->name, ".") && !hasprefix(f->name, "runtime."); 675 }