github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/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 // SPARC64's PC holds the address of the *current* instruction. 89 if xpc > entry && !ci.wasPanic && sys.GoarchSparc64 == 0 { 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 typelinks []int32 // offsets from types 200 itablinks []*itab 201 202 modulename string 203 modulehashes []modulehash 204 205 gcdatamask, gcbssmask bitvector 206 207 typemap map[typeOff]*_type // offset to *_rtype in previous module 208 209 next *moduledata 210 } 211 212 // For each shared library a module links against, the linker creates an entry in the 213 // moduledata.modulehashes slice containing the name of the module, the abi hash seen 214 // at link time and a pointer to the runtime abi hash. These are checked in 215 // moduledataverify1 below. 216 type modulehash struct { 217 modulename string 218 linktimehash string 219 runtimehash *string 220 } 221 222 var firstmoduledata moduledata // linker symbol 223 var lastmoduledatap *moduledata // linker symbol 224 225 type functab struct { 226 entry uintptr 227 funcoff uintptr 228 } 229 230 const minfunc = 16 // minimum function size 231 const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table 232 233 // findfunctab is an array of these structures. 234 // Each bucket represents 4096 bytes of the text segment. 235 // Each subbucket represents 256 bytes of the text segment. 236 // To find a function given a pc, locate the bucket and subbucket for 237 // that pc. Add together the idx and subbucket value to obtain a 238 // function index. Then scan the functab array starting at that 239 // index to find the target function. 240 // This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead. 241 type findfuncbucket struct { 242 idx uint32 243 subbuckets [16]byte 244 } 245 246 func moduledataverify() { 247 for datap := &firstmoduledata; datap != nil; datap = datap.next { 248 moduledataverify1(datap) 249 } 250 } 251 252 const debugPcln = false 253 254 func moduledataverify1(datap *moduledata) { 255 // See golang.org/s/go12symtab for header: 0xfffffffb, 256 // two zero bytes, a byte giving the PC quantum, 257 // and a byte giving the pointer width in bytes. 258 pcln := *(**[8]byte)(unsafe.Pointer(&datap.pclntable)) 259 pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable)) 260 if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != sys.PCQuantum || pcln[7] != sys.PtrSize { 261 println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7])) 262 throw("invalid function symbol table\n") 263 } 264 265 // ftab is lookup table for function by program counter. 266 nftab := len(datap.ftab) - 1 267 var pcCache pcvalueCache 268 for i := 0; i < nftab; i++ { 269 // NOTE: ftab[nftab].entry is legal; it is the address beyond the final function. 270 if datap.ftab[i].entry > datap.ftab[i+1].entry { 271 f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])) 272 f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])) 273 f2name := "end" 274 if i+1 < nftab { 275 f2name = funcname(f2) 276 } 277 println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name) 278 for j := 0; j <= i; j++ { 279 print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n") 280 } 281 throw("invalid runtime symbol table") 282 } 283 284 if debugPcln || nftab-i < 5 { 285 // Check a PC near but not at the very end. 286 // The very end might be just padding that is not covered by the tables. 287 // No architecture rounds function entries to more than 16 bytes, 288 // but if one came along we'd need to subtract more here. 289 // But don't use the next PC if it corresponds to a foreign object chunk 290 // (no pcln table, f2.pcln == 0). That chunk might have an alignment 291 // more than 16 bytes. 292 f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])) 293 end := f.entry 294 if i+1 < nftab { 295 f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])) 296 if f2.pcln != 0 { 297 end = f2.entry - 16 298 if end < f.entry { 299 end = f.entry 300 } 301 } 302 } 303 pcvalue(f, f.pcfile, end, &pcCache, true) 304 pcvalue(f, f.pcln, end, &pcCache, true) 305 pcvalue(f, f.pcsp, end, &pcCache, true) 306 } 307 } 308 309 if datap.minpc != datap.ftab[0].entry || 310 datap.maxpc != datap.ftab[nftab].entry { 311 throw("minpc or maxpc invalid") 312 } 313 314 for _, modulehash := range datap.modulehashes { 315 if modulehash.linktimehash != *modulehash.runtimehash { 316 println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename) 317 throw("abi mismatch") 318 } 319 } 320 } 321 322 // FuncForPC returns a *Func describing the function that contains the 323 // given program counter address, or else nil. 324 func FuncForPC(pc uintptr) *Func { 325 return (*Func)(unsafe.Pointer(findfunc(pc))) 326 } 327 328 // Name returns the name of the function. 329 func (f *Func) Name() string { 330 return funcname(f.raw()) 331 } 332 333 // Entry returns the entry address of the function. 334 func (f *Func) Entry() uintptr { 335 return f.raw().entry 336 } 337 338 // FileLine returns the file name and line number of the 339 // source code corresponding to the program counter pc. 340 // The result will not be accurate if pc is not a program 341 // counter within f. 342 func (f *Func) FileLine(pc uintptr) (file string, line int) { 343 // Pass strict=false here, because anyone can call this function, 344 // and they might just be wrong about targetpc belonging to f. 345 file, line32 := funcline1(f.raw(), pc, false) 346 return file, int(line32) 347 } 348 349 func findmoduledatap(pc uintptr) *moduledata { 350 for datap := &firstmoduledata; datap != nil; datap = datap.next { 351 if datap.minpc <= pc && pc < datap.maxpc { 352 return datap 353 } 354 } 355 return nil 356 } 357 358 func funcNameForPc(pc uintptr) string { 359 f := findfunc(pc) 360 if f == nil { 361 return "nil" 362 } 363 s := funcname(f) 364 if pc != f.entry { 365 s += "+" + itox(uint64(pc-f.entry)) 366 } 367 return s 368 } 369 370 func itox(v uint64) string { 371 const dig = "0123456789abcdef" 372 buf := rawbyteslice(100) 373 i := len(buf) 374 for i--; i > 0; i-- { 375 buf[i] = dig[v%16] 376 if v < 16 { 377 break 378 } 379 v /= 16 380 } 381 i-- 382 buf[i] = 'x' 383 i-- 384 buf[i] = '0' 385 return slicebytetostringtmp(buf[i:]) 386 } 387 388 func findfunc(pc uintptr) *_func { 389 datap := findmoduledatap(pc) 390 if datap == nil { 391 return nil 392 } 393 const nsub = uintptr(len(findfuncbucket{}.subbuckets)) 394 395 x := pc - datap.minpc 396 b := x / pcbucketsize 397 i := x % pcbucketsize / (pcbucketsize / nsub) 398 399 ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{}))) 400 idx := ffb.idx + uint32(ffb.subbuckets[i]) 401 if pc < datap.ftab[idx].entry { 402 throw("findfunc: bad findfunctab entry") 403 } 404 405 // linear search to find func with pc >= entry. 406 for datap.ftab[idx+1].entry <= pc { 407 idx++ 408 } 409 return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff])) 410 } 411 412 type pcvalueCache struct { 413 entries [16]pcvalueCacheEnt 414 } 415 416 type pcvalueCacheEnt struct { 417 // targetpc and off together are the key of this cache entry. 418 targetpc uintptr 419 off int32 420 // val is the value of this cached pcvalue entry. 421 val int32 422 } 423 424 func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 { 425 if off == 0 { 426 return -1 427 } 428 429 // Check the cache. This speeds up walks of deep stacks, which 430 // tend to have the same recursive functions over and over. 431 // 432 // This cache is small enough that full associativity is 433 // cheaper than doing the hashing for a less associative 434 // cache. 435 if cache != nil { 436 for _, ent := range cache.entries { 437 // We check off first because we're more 438 // likely to have multiple entries with 439 // different offsets for the same targetpc 440 // than the other way around, so we'll usually 441 // fail in the first clause. 442 if ent.off == off && ent.targetpc == targetpc { 443 return ent.val 444 } 445 } 446 } 447 448 datap := findmoduledatap(f.entry) // inefficient 449 if datap == nil { 450 if strict && panicking == 0 { 451 print("runtime: no module data for ", hex(f.entry), "\n") 452 throw("no module data") 453 } 454 return -1 455 } 456 p := datap.pclntable[off:] 457 pc := f.entry 458 val := int32(-1) 459 for { 460 var ok bool 461 p, ok = step(p, &pc, &val, pc == f.entry) 462 if !ok { 463 break 464 } 465 if targetpc < pc { 466 // Replace a random entry in the cache. Random 467 // replacement prevents a performance cliff if 468 // a recursive stack's cycle is slightly 469 // larger than the cache. 470 if cache != nil { 471 ci := fastrand1() % uint32(len(cache.entries)) 472 cache.entries[ci] = pcvalueCacheEnt{ 473 targetpc: targetpc, 474 off: off, 475 val: val, 476 } 477 } 478 479 return val 480 } 481 } 482 483 // If there was a table, it should have covered all program counters. 484 // If not, something is wrong. 485 if panicking != 0 || !strict { 486 return -1 487 } 488 489 print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n") 490 491 p = datap.pclntable[off:] 492 pc = f.entry 493 val = -1 494 for { 495 var ok bool 496 p, ok = step(p, &pc, &val, pc == f.entry) 497 if !ok { 498 break 499 } 500 print("\tvalue=", val, " until pc=", hex(pc), "\n") 501 } 502 503 throw("invalid runtime symbol table") 504 return -1 505 } 506 507 func cfuncname(f *_func) *byte { 508 if f == nil || f.nameoff == 0 { 509 return nil 510 } 511 datap := findmoduledatap(f.entry) // inefficient 512 if datap == nil { 513 return nil 514 } 515 return &datap.pclntable[f.nameoff] 516 } 517 518 func funcname(f *_func) string { 519 return gostringnocopy(cfuncname(f)) 520 } 521 522 func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) { 523 datap := findmoduledatap(f.entry) // inefficient 524 if datap == nil { 525 return "?", 0 526 } 527 fileno := int(pcvalue(f, f.pcfile, targetpc, nil, strict)) 528 line = pcvalue(f, f.pcln, targetpc, nil, strict) 529 if fileno == -1 || line == -1 || fileno >= len(datap.filetab) { 530 // print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n") 531 return "?", 0 532 } 533 file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]]) 534 return 535 } 536 537 func funcline(f *_func, targetpc uintptr) (file string, line int32) { 538 return funcline1(f, targetpc, true) 539 } 540 541 func funcspdelta(f *_func, targetpc uintptr, cache *pcvalueCache) int32 { 542 x := pcvalue(f, f.pcsp, targetpc, cache, true) 543 if x&(sys.PtrSize-1) != 0 { 544 print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n") 545 } 546 return x 547 } 548 549 func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) int32 { 550 if table < 0 || table >= f.npcdata { 551 return -1 552 } 553 off := *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4)) 554 return pcvalue(f, off, targetpc, cache, true) 555 } 556 557 func funcdata(f *_func, i int32) unsafe.Pointer { 558 if i < 0 || i >= f.nfuncdata { 559 return nil 560 } 561 p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4) 562 if sys.PtrSize == 8 && uintptr(p)&4 != 0 { 563 if uintptr(unsafe.Pointer(f))&4 != 0 { 564 println("runtime: misaligned func", f) 565 } 566 p = add(p, 4) 567 } 568 return *(*unsafe.Pointer)(add(p, uintptr(i)*sys.PtrSize)) 569 } 570 571 // step advances to the next pc, value pair in the encoded table. 572 func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) { 573 p, uvdelta := readvarint(p) 574 if uvdelta == 0 && !first { 575 return nil, false 576 } 577 if uvdelta&1 != 0 { 578 uvdelta = ^(uvdelta >> 1) 579 } else { 580 uvdelta >>= 1 581 } 582 vdelta := int32(uvdelta) 583 p, pcdelta := readvarint(p) 584 *pc += uintptr(pcdelta * sys.PCQuantum) 585 *val += vdelta 586 return p, true 587 } 588 589 // readvarint reads a varint from p. 590 func readvarint(p []byte) (newp []byte, val uint32) { 591 var v, shift uint32 592 for { 593 b := p[0] 594 p = p[1:] 595 v |= (uint32(b) & 0x7F) << shift 596 if b&0x80 == 0 { 597 break 598 } 599 shift += 7 600 } 601 return p, v 602 } 603 604 type stackmap struct { 605 n int32 // number of bitmaps 606 nbit int32 // number of bits in each bitmap 607 bytedata [1]byte // bitmaps, each starting on a 32-bit boundary 608 } 609 610 //go:nowritebarrier 611 func stackmapdata(stkmap *stackmap, n int32) bitvector { 612 if n < 0 || n >= stkmap.n { 613 throw("stackmapdata: index out of range") 614 } 615 return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+31)/32*4))))} 616 }