diff options
author | Keith Randall <keithr@alum.mit.edu> | 2019-01-05 14:31:23 -0800 |
---|---|---|
committer | Keith Randall <khr@golang.org> | 2019-01-08 21:54:04 +0000 |
commit | 956879dd0bf31b26d2425c2eadbeb19b90812187 (patch) | |
tree | 7d4bb468334d274917f03a783d7d3441e7478c1e /src/runtime/symtab.go | |
parent | 033b6501817aefebc6fc56b6212ff6abf14c8127 (diff) | |
download | go-956879dd0bf31b26d2425c2eadbeb19b90812187.tar.gz go-956879dd0bf31b26d2425c2eadbeb19b90812187.zip |
runtime: make FuncForPC return the innermost inlined frame
Returning the innermost frame instead of the outermost
makes code that walks the results of runtime.Caller{,s}
still work correctly in the presence of mid-stack inlining.
Fixes #29582
Change-Id: I2392e3dd5636eb8c6f58620a61cef2194fe660a7
Reviewed-on: https://go-review.googlesource.com/c/156364
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/runtime/symtab.go')
-rw-r--r-- | src/runtime/symtab.go | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 245a7e6b01..e7ce3de497 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -466,9 +466,28 @@ func moduledataverify1(datap *moduledata) { // given program counter address, or else nil. // // If pc represents multiple functions because of inlining, it returns -// the *Func describing the outermost function. +// the a *Func describing the innermost function, but with an entry +// of the outermost function. func FuncForPC(pc uintptr) *Func { - return findfunc(pc)._Func() + f := findfunc(pc) + if !f.valid() { + return nil + } + if inldata := funcdata(f, _FUNCDATA_InlTree); inldata != nil { + if ix := pcdatavalue(f, _PCDATA_InlTreeIndex, pc, nil); ix >= 0 { + inltree := (*[1 << 20]inlinedCall)(inldata) + name := funcnameFromNameoff(f, inltree[ix].func_) + file, line := funcline(f, pc) + fi := &funcinl{ + entry: f.entry, // entry of the real (the outermost) function. + name: name, + file: file, + line: int(line), + } + return (*Func)(unsafe.Pointer(fi)) + } + } + return f._Func() } // Name returns the name of the function. @@ -476,12 +495,22 @@ func (f *Func) Name() string { if f == nil { return "" } + fn := f.raw() + if fn.entry == 0 { // inlined version + fi := (*funcinl)(unsafe.Pointer(fn)) + return fi.name + } return funcname(f.funcInfo()) } // Entry returns the entry address of the function. func (f *Func) Entry() uintptr { - return f.raw().entry + fn := f.raw() + if fn.entry == 0 { // inlined version + fi := (*funcinl)(unsafe.Pointer(fn)) + return fi.entry + } + return fn.entry } // FileLine returns the file name and line number of the @@ -489,6 +518,11 @@ func (f *Func) Entry() uintptr { // The result will not be accurate if pc is not a program // counter within f. func (f *Func) FileLine(pc uintptr) (file string, line int) { + fn := f.raw() + if fn.entry == 0 { // inlined version + fi := (*funcinl)(unsafe.Pointer(fn)) + return fi.file, fi.line + } // Pass strict=false here, because anyone can call this function, // and they might just be wrong about targetpc belonging to f. file, line32 := funcline1(f.funcInfo(), pc, false) |