aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/symtab.go
diff options
context:
space:
mode:
authorKeith Randall <keithr@alum.mit.edu>2019-01-05 14:31:23 -0800
committerKeith Randall <khr@golang.org>2019-01-08 21:54:04 +0000
commit956879dd0bf31b26d2425c2eadbeb19b90812187 (patch)
tree7d4bb468334d274917f03a783d7d3441e7478c1e /src/runtime/symtab.go
parent033b6501817aefebc6fc56b6212ff6abf14c8127 (diff)
downloadgo-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.go40
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)