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