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