github.com/fenixara/go@v0.0.0-20170127160404-96ea0918e670/src/runtime/symtab.go (about) 1 // Copyright 2014 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 package runtime 6 7 import ( 8 "runtime/internal/atomic" 9 "runtime/internal/sys" 10 "unsafe" 11 ) 12 13 // Frames may be used to get function/file/line information for a 14 // slice of PC values returned by Callers. 15 type Frames struct { 16 callers []uintptr 17 18 // If previous caller in iteration was a panic, then 19 // ci.callers[0] is the address of the faulting instruction 20 // instead of the return address of the call. 21 wasPanic bool 22 23 // Frames to return for subsequent calls to the Next method. 24 // Used for non-Go frames. 25 frames *[]Frame 26 } 27 28 // Frame is the information returned by Frames for each call frame. 29 type Frame struct { 30 // Program counter for this frame; multiple frames may have 31 // the same PC value. 32 PC uintptr 33 34 // Func for this frame; may be nil for non-Go code or fully 35 // inlined functions. 36 Func *Func 37 38 // Function name, file name, and line number for this call frame. 39 // May be the empty string or zero if not known. 40 // If Func is not nil then Function == Func.Name(). 41 Function string 42 File string 43 Line int 44 45 // Entry point for the function; may be zero if not known. 46 // If Func is not nil then Entry == Func.Entry(). 47 Entry uintptr 48 } 49 50 // CallersFrames takes a slice of PC values returned by Callers and 51 // prepares to return function/file/line information. 52 // Do not change the slice until you are done with the Frames. 53 func CallersFrames(callers []uintptr) *Frames { 54 return &Frames{callers: callers} 55 } 56 57 // Next returns frame information for the next caller. 58 // If more is false, there are no more callers (the Frame value is valid). 59 func (ci *Frames) Next() (frame Frame, more bool) { 60 if ci.frames != nil { 61 // We have saved up frames to return. 62 f := (*ci.frames)[0] 63 if len(*ci.frames) == 1 { 64 ci.frames = nil 65 } else { 66 *ci.frames = (*ci.frames)[1:] 67 } 68 return f, ci.frames != nil || len(ci.callers) > 0 69 } 70 71 if len(ci.callers) == 0 { 72 ci.wasPanic = false 73 return Frame{}, false 74 } 75 pc := ci.callers[0] 76 ci.callers = ci.callers[1:] 77 more = len(ci.callers) > 0 78 f := FuncForPC(pc) 79 if f == nil { 80 ci.wasPanic = false 81 if cgoSymbolizer != nil { 82 return ci.cgoNext(pc, more) 83 } 84 return Frame{}, more 85 } 86 87 entry := f.Entry() 88 xpc := pc 89 if xpc > entry && !ci.wasPanic { 90 xpc-- 91 } 92 file, line := f.FileLine(xpc) 93 94 function := f.Name() 95 ci.wasPanic = entry == sigpanicPC 96 97 frame = Frame{ 98 PC: xpc, 99 Func: f, 100 Function: function, 101 File: file, 102 Line: line, 103 Entry: entry, 104 } 105 106 return frame, more 107 } 108 109 // cgoNext returns frame information for pc, known to be a non-Go function, 110 // using the cgoSymbolizer hook. 111 func (ci *Frames) cgoNext(pc uintptr, more bool) (Frame, bool) { 112 arg := cgoSymbolizerArg{pc: pc} 113 callCgoSymbolizer(&arg) 114 115 if arg.file == nil && arg.funcName == nil { 116 // No useful information from symbolizer. 117 return Frame{}, more 118 } 119 120 var frames []Frame 121 for { 122 frames = append(frames, Frame{ 123 PC: pc, 124 Func: nil, 125 Function: gostring(arg.funcName), 126 File: gostring(arg.file), 127 Line: int(arg.lineno), 128 Entry: arg.entry, 129 }) 130 if arg.more == 0 { 131 break 132 } 133 callCgoSymbolizer(&arg) 134 } 135 136 // No more frames for this PC. Tell the symbolizer we are done. 137 // We don't try to maintain a single cgoSymbolizerArg for the 138 // whole use of Frames, because there would be no good way to tell 139 // the symbolizer when we are done. 140 arg.pc = 0 141 callCgoSymbolizer(&arg) 142 143 if len(frames) == 1 { 144 // Return a single frame. 145 return frames[0], more 146 } 147 148 // Return the first frame we saw and store the rest to be 149 // returned by later calls to Next. 150 rf := frames[0] 151 frames = frames[1:] 152 ci.frames = new([]Frame) 153 *ci.frames = frames 154 return rf, true 155 } 156 157 // NOTE: Func does not expose the actual unexported fields, because we return *Func 158 // values to users, and we want to keep them from being able to overwrite the data 159 // with (say) *f = Func{}. 160 // All code operating on a *Func must call raw to get the *_func instead. 161 162 // A Func represents a Go function in the running binary. 163 type Func struct { 164 opaque struct{} // unexported field to disallow conversions 165 } 166 167 func (f *Func) raw() *_func { 168 return (*_func)(unsafe.Pointer(f)) 169 } 170 171 // funcdata.h 172 const ( 173 _PCDATA_StackMapIndex = 0 174 _FUNCDATA_ArgsPointerMaps = 0 175 _FUNCDATA_LocalsPointerMaps = 1 176 _ArgsSizeUnknown = -0x80000000 177 ) 178 179 // moduledata records information about the layout of the executable 180 // image. It is written by the linker. Any changes here must be 181 // matched changes to the code in cmd/internal/ld/symtab.go:symtab. 182 // moduledata is stored in read-only memory; none of the pointers here 183 // are visible to the garbage collector. 184 type moduledata struct { 185 pclntable []byte 186 ftab []functab 187 filetab []uint32 188 findfunctab uintptr 189 minpc, maxpc uintptr 190 191 text, etext uintptr 192 noptrdata, enoptrdata uintptr 193 data, edata uintptr 194 bss, ebss uintptr 195 noptrbss, enoptrbss uintptr 196 end, gcdata, gcbss uintptr 197 types, etypes uintptr 198 199 textsectmap []textsect 200 typelinks []int32 // offsets from types 201 itablinks []*itab 202 203 ptab []ptabEntry 204 205 pluginpath string 206 pkghashes []modulehash 207 208 modulename string 209 modulehashes []modulehash 210 211 gcdatamask, gcbssmask bitvector 212 213 typemap map[typeOff]*_type // offset to *_rtype in previous module 214 215 next *moduledata 216 } 217 218 // A modulehash is used to compare the ABI of a new module or a 219 // package in a new module with the loaded program. 220 // 221 // For each shared library a module links against, the linker creates an entry in the 222 // moduledata.modulehashes slice containing the name of the module, the abi hash seen 223 // at link time and a pointer to the runtime abi hash. These are checked in 224 // moduledataverify1 below. 225 // 226 // For each loaded plugin, the the pkghashes slice has a modulehash of the 227 // newly loaded package that can be used to check the plugin's version of 228 // a package against any previously loaded version of the package. 229 // This is done in plugin.lastmoduleinit. 230 type modulehash struct { 231 modulename string 232 linktimehash string 233 runtimehash *string 234 } 235 236 // pinnedTypemaps are the map[typeOff]*_type from the moduledata objects. 237 // 238 // These typemap objects are allocated at run time on the heap, but the 239 // only direct reference to them is in the moduledata, created by the 240 // linker and marked SNOPTRDATA so it is ignored by the GC. 241 // 242 // To make sure the map isn't collected, we keep a second reference here. 243 var pinnedTypemaps []map[typeOff]*_type 244 245 var firstmoduledata moduledata // linker symbol 246 var lastmoduledatap *moduledata // linker symbol 247 var modulesSlice unsafe.Pointer // see activeModules 248 249 // activeModules returns a slice of active modules. 250 // 251 // A module is active once its gcdatamask and gcbssmask have been 252 // assembled and it is usable by the GC. 253 func activeModules() []*moduledata { 254 p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice))) 255 if p == nil { 256 return nil 257 } 258 return *p 259 } 260 261 // modulesinit creates the active modules slice out of all loaded modules. 262 // 263 // When a module is first loaded by the dynamic linker, an .init_array 264 // function (written by cmd/link) is invoked to call addmoduledata, 265 // appending to the module to the linked list that starts with 266 // firstmoduledata. 267 // 268 // There are two times this can happen in the lifecycle of a Go 269 // program. First, if compiled with -linkshared, a number of modules 270 // built with -buildmode=shared can be loaded at program initialization. 271 // Second, a Go program can load a module while running that was built 272 // with -buildmode=plugin. 273 // 274 // After loading, this function is called which initializes the 275 // moduledata so it is usable by the GC and creates a new activeModules 276 // list. 277 // 278 // Only one goroutine may call modulesinit at a time. 279 func modulesinit() { 280 modules := new([]*moduledata) 281 for md := &firstmoduledata; md != nil; md = md.next { 282 *modules = append(*modules, md) 283 if md.gcdatamask == (bitvector{}) { 284 md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), md.edata-md.data) 285 md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), md.ebss-md.bss) 286 } 287 } 288 289 // Modules appear in the moduledata linked list in the order they are 290 // loaded by the dynamic loader, with one exception: the 291 // firstmoduledata itself the module that contains the runtime. This 292 // is not always the first module (when using -buildmode=shared, it 293 // is typically libstd.so, the second module). The order matters for 294 // typelinksinit, so we swap the first module with whatever module 295 // contains the main function. 296 // 297 // See Issue #18729. 298 mainText := funcPC(main_main) 299 for i, md := range *modules { 300 if md.text <= mainText && mainText <= md.etext { 301 (*modules)[0] = md 302 (*modules)[i] = &firstmoduledata 303 break 304 } 305 } 306 307 atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules)) 308 } 309 310 type functab struct { 311 entry uintptr 312 funcoff uintptr 313 } 314 315 // Mapping information for secondary text sections 316 317 type textsect struct { 318 vaddr uintptr // prelinked section vaddr 319 length uintptr // section length 320 baseaddr uintptr // relocated section address 321 } 322 323 const minfunc = 16 // minimum function size 324 const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table 325 326 // findfunctab is an array of these structures. 327 // Each bucket represents 4096 bytes of the text segment. 328 // Each subbucket represents 256 bytes of the text segment. 329 // To find a function given a pc, locate the bucket and subbucket for 330 // that pc. Add together the idx and subbucket value to obtain a 331 // function index. Then scan the functab array starting at that 332 // index to find the target function. 333 // This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead. 334 type findfuncbucket struct { 335 idx uint32 336 subbuckets [16]byte 337 } 338 339 func moduledataverify() { 340 for datap := &firstmoduledata; datap != nil; datap = datap.next { 341 moduledataverify1(datap) 342 } 343 } 344 345 const debugPcln = false 346 347 func moduledataverify1(datap *moduledata) { 348 // See golang.org/s/go12symtab for header: 0xfffffffb, 349 // two zero bytes, a byte giving the PC quantum, 350 // and a byte giving the pointer width in bytes. 351 pcln := *(**[8]byte)(unsafe.Pointer(&datap.pclntable)) 352 pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable)) 353 if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != sys.PCQuantum || pcln[7] != sys.PtrSize { 354 println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7])) 355 throw("invalid function symbol table\n") 356 } 357 358 // ftab is lookup table for function by program counter. 359 nftab := len(datap.ftab) - 1 360 var pcCache pcvalueCache 361 for i := 0; i < nftab; i++ { 362 // NOTE: ftab[nftab].entry is legal; it is the address beyond the final function. 363 if datap.ftab[i].entry > datap.ftab[i+1].entry { 364 f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])) 365 f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])) 366 f2name := "end" 367 if i+1 < nftab { 368 f2name = funcname(f2) 369 } 370 println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name) 371 for j := 0; j <= i; j++ { 372 print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n") 373 } 374 throw("invalid runtime symbol table") 375 } 376 377 if debugPcln || nftab-i < 5 { 378 // Check a PC near but not at the very end. 379 // The very end might be just padding that is not covered by the tables. 380 // No architecture rounds function entries to more than 16 bytes, 381 // but if one came along we'd need to subtract more here. 382 // But don't use the next PC if it corresponds to a foreign object chunk 383 // (no pcln table, f2.pcln == 0). That chunk might have an alignment 384 // more than 16 bytes. 385 f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])) 386 end := f.entry 387 if i+1 < nftab { 388 f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])) 389 if f2.pcln != 0 { 390 end = f2.entry - 16 391 if end < f.entry { 392 end = f.entry 393 } 394 } 395 } 396 pcvalue(f, f.pcfile, end, &pcCache, true) 397 pcvalue(f, f.pcln, end, &pcCache, true) 398 pcvalue(f, f.pcsp, end, &pcCache, true) 399 } 400 } 401 402 if datap.minpc != datap.ftab[0].entry || 403 datap.maxpc != datap.ftab[nftab].entry { 404 throw("minpc or maxpc invalid") 405 } 406 407 for _, modulehash := range datap.modulehashes { 408 if modulehash.linktimehash != *modulehash.runtimehash { 409 println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename) 410 throw("abi mismatch") 411 } 412 } 413 } 414 415 // FuncForPC returns a *Func describing the function that contains the 416 // given program counter address, or else nil. 417 func FuncForPC(pc uintptr) *Func { 418 return (*Func)(unsafe.Pointer(findfunc(pc))) 419 } 420 421 // Name returns the name of the function. 422 func (f *Func) Name() string { 423 return funcname(f.raw()) 424 } 425 426 // Entry returns the entry address of the function. 427 func (f *Func) Entry() uintptr { 428 return f.raw().entry 429 } 430 431 // FileLine returns the file name and line number of the 432 // source code corresponding to the program counter pc. 433 // The result will not be accurate if pc is not a program 434 // counter within f. 435 func (f *Func) FileLine(pc uintptr) (file string, line int) { 436 // Pass strict=false here, because anyone can call this function, 437 // and they might just be wrong about targetpc belonging to f. 438 file, line32 := funcline1(f.raw(), pc, false) 439 return file, int(line32) 440 } 441 442 func findmoduledatap(pc uintptr) *moduledata { 443 for datap := &firstmoduledata; datap != nil; datap = datap.next { 444 if datap.minpc <= pc && pc < datap.maxpc { 445 return datap 446 } 447 } 448 return nil 449 } 450 451 func findfunc(pc uintptr) *_func { 452 datap := findmoduledatap(pc) 453 if datap == nil { 454 return nil 455 } 456 const nsub = uintptr(len(findfuncbucket{}.subbuckets)) 457 458 x := pc - datap.minpc 459 b := x / pcbucketsize 460 i := x % pcbucketsize / (pcbucketsize / nsub) 461 462 ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{}))) 463 idx := ffb.idx + uint32(ffb.subbuckets[i]) 464 465 // If the idx is beyond the end of the ftab, set it to the end of the table and search backward. 466 // This situation can occur if multiple text sections are generated to handle large text sections 467 // and the linker has inserted jump tables between them. 468 469 if idx >= uint32(len(datap.ftab)) { 470 idx = uint32(len(datap.ftab) - 1) 471 } 472 if pc < datap.ftab[idx].entry { 473 474 // With multiple text sections, the idx might reference a function address that 475 // is higher than the pc being searched, so search backward until the matching address is found. 476 477 for datap.ftab[idx].entry > pc && idx > 0 { 478 idx-- 479 } 480 if idx == 0 { 481 throw("findfunc: bad findfunctab entry idx") 482 } 483 } else { 484 485 // linear search to find func with pc >= entry. 486 for datap.ftab[idx+1].entry <= pc { 487 idx++ 488 } 489 } 490 return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff])) 491 } 492 493 type pcvalueCache struct { 494 entries [16]pcvalueCacheEnt 495 } 496 497 type pcvalueCacheEnt struct { 498 // targetpc and off together are the key of this cache entry. 499 targetpc uintptr 500 off int32 501 // val is the value of this cached pcvalue entry. 502 val int32 503 } 504 505 func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 { 506 if off == 0 { 507 return -1 508 } 509 510 // Check the cache. This speeds up walks of deep stacks, which 511 // tend to have the same recursive functions over and over. 512 // 513 // This cache is small enough that full associativity is 514 // cheaper than doing the hashing for a less associative 515 // cache. 516 if cache != nil { 517 for _, ent := range cache.entries { 518 // We check off first because we're more 519 // likely to have multiple entries with 520 // different offsets for the same targetpc 521 // than the other way around, so we'll usually 522 // fail in the first clause. 523 if ent.off == off && ent.targetpc == targetpc { 524 return ent.val 525 } 526 } 527 } 528 529 datap := findmoduledatap(f.entry) // inefficient 530 if datap == nil { 531 if strict && panicking == 0 { 532 print("runtime: no module data for ", hex(f.entry), "\n") 533 throw("no module data") 534 } 535 return -1 536 } 537 p := datap.pclntable[off:] 538 pc := f.entry 539 val := int32(-1) 540 for { 541 var ok bool 542 p, ok = step(p, &pc, &val, pc == f.entry) 543 if !ok { 544 break 545 } 546 if targetpc < pc { 547 // Replace a random entry in the cache. Random 548 // replacement prevents a performance cliff if 549 // a recursive stack's cycle is slightly 550 // larger than the cache. 551 if cache != nil { 552 ci := fastrand() % uint32(len(cache.entries)) 553 cache.entries[ci] = pcvalueCacheEnt{ 554 targetpc: targetpc, 555 off: off, 556 val: val, 557 } 558 } 559 560 return val 561 } 562 } 563 564 // If there was a table, it should have covered all program counters. 565 // If not, something is wrong. 566 if panicking != 0 || !strict { 567 return -1 568 } 569 570 print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n") 571 572 p = datap.pclntable[off:] 573 pc = f.entry 574 val = -1 575 for { 576 var ok bool 577 p, ok = step(p, &pc, &val, pc == f.entry) 578 if !ok { 579 break 580 } 581 print("\tvalue=", val, " until pc=", hex(pc), "\n") 582 } 583 584 throw("invalid runtime symbol table") 585 return -1 586 } 587 588 func cfuncname(f *_func) *byte { 589 if f == nil || f.nameoff == 0 { 590 return nil 591 } 592 datap := findmoduledatap(f.entry) // inefficient 593 if datap == nil { 594 return nil 595 } 596 return &datap.pclntable[f.nameoff] 597 } 598 599 func funcname(f *_func) string { 600 return gostringnocopy(cfuncname(f)) 601 } 602 603 func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) { 604 datap := findmoduledatap(f.entry) // inefficient 605 if datap == nil { 606 return "?", 0 607 } 608 fileno := int(pcvalue(f, f.pcfile, targetpc, nil, strict)) 609 line = pcvalue(f, f.pcln, targetpc, nil, strict) 610 if fileno == -1 || line == -1 || fileno >= len(datap.filetab) { 611 // print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n") 612 return "?", 0 613 } 614 file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]]) 615 return 616 } 617 618 func funcline(f *_func, targetpc uintptr) (file string, line int32) { 619 return funcline1(f, targetpc, true) 620 } 621 622 func funcspdelta(f *_func, targetpc uintptr, cache *pcvalueCache) int32 { 623 x := pcvalue(f, f.pcsp, targetpc, cache, true) 624 if x&(sys.PtrSize-1) != 0 { 625 print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n") 626 } 627 return x 628 } 629 630 func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) int32 { 631 if table < 0 || table >= f.npcdata { 632 return -1 633 } 634 off := *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4)) 635 return pcvalue(f, off, targetpc, cache, true) 636 } 637 638 func funcdata(f *_func, i int32) unsafe.Pointer { 639 if i < 0 || i >= f.nfuncdata { 640 return nil 641 } 642 p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4) 643 if sys.PtrSize == 8 && uintptr(p)&4 != 0 { 644 if uintptr(unsafe.Pointer(f))&4 != 0 { 645 println("runtime: misaligned func", f) 646 } 647 p = add(p, 4) 648 } 649 return *(*unsafe.Pointer)(add(p, uintptr(i)*sys.PtrSize)) 650 } 651 652 // step advances to the next pc, value pair in the encoded table. 653 func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) { 654 p, uvdelta := readvarint(p) 655 if uvdelta == 0 && !first { 656 return nil, false 657 } 658 if uvdelta&1 != 0 { 659 uvdelta = ^(uvdelta >> 1) 660 } else { 661 uvdelta >>= 1 662 } 663 vdelta := int32(uvdelta) 664 p, pcdelta := readvarint(p) 665 *pc += uintptr(pcdelta * sys.PCQuantum) 666 *val += vdelta 667 return p, true 668 } 669 670 // readvarint reads a varint from p. 671 func readvarint(p []byte) (newp []byte, val uint32) { 672 var v, shift uint32 673 for { 674 b := p[0] 675 p = p[1:] 676 v |= (uint32(b) & 0x7F) << shift 677 if b&0x80 == 0 { 678 break 679 } 680 shift += 7 681 } 682 return p, v 683 } 684 685 type stackmap struct { 686 n int32 // number of bitmaps 687 nbit int32 // number of bits in each bitmap 688 bytedata [1]byte // bitmaps, each starting on a byte boundary 689 } 690 691 //go:nowritebarrier 692 func stackmapdata(stkmap *stackmap, n int32) bitvector { 693 if n < 0 || n >= stkmap.n { 694 throw("stackmapdata: index out of range") 695 } 696 return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+7)/8))))} 697 }