diff options
author | Austin Clements <austin@google.com> | 2020-11-20 17:32:46 -0500 |
---|---|---|
committer | Austin Clements <austin@google.com> | 2020-11-24 21:47:44 +0000 |
commit | e8de596f04d0ea7fb6fb68b036760bf088a9c6c2 (patch) | |
tree | ac9399d5206140e2a46ef66b41715e42b3ab198a /src/runtime/traceback.go | |
parent | ba2adc21e8c416c47dec5fbce76286758f15b177 (diff) | |
download | go-e8de596f04d0ea7fb6fb68b036760bf088a9c6c2.tar.gz go-e8de596f04d0ea7fb6fb68b036760bf088a9c6c2.zip |
runtime: use inlined function name for traceback elision
Currently, gentraceback decides which frames to print or elide when
unwinding inlined frames using only the name of the outermost
function. If the outermost function should be elided, then inlined
functions will also be elided, even if they shouldn't be.
This happens in practice in at least one situation. As of CL 258938,
exported Go functions (and functions they call) can now be inlined
into the generated _cgoexp_HASH_FN function. The runtime elides
_cgoexp_HASH_FN from tracebacks because it doesn't contain a ".".
Because of this bug, it also elides anything that was inlined into it.
This CL fixes this by synthesizing a funcInfo for the inlined
functions to pass to showframe.
Fixes #42754.
Change-Id: Ie6c663a4a1ac7f0d4beb1aa60bc26fc8cddd0f9d
Reviewed-on: https://go-review.googlesource.com/c/go/+/272131
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/runtime/traceback.go')
-rw-r--r-- | src/runtime/traceback.go | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index f3df152535..0825e9e707 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -396,13 +396,21 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in // If there is inlining info, print the inner frames. if inldata := funcdata(f, _FUNCDATA_InlTree); inldata != nil { inltree := (*[1 << 20]inlinedCall)(inldata) + var inlFunc _func + inlFuncInfo := funcInfo{&inlFunc, f.datap} for { ix := pcdatavalue(f, _PCDATA_InlTreeIndex, tracepc, nil) if ix < 0 { break } - if (flags&_TraceRuntimeFrames) != 0 || showframe(f, gp, nprint == 0, inltree[ix].funcID, lastFuncID) { - name := funcnameFromNameoff(f, inltree[ix].func_) + + // Create a fake _func for the + // inlined function. + inlFunc.nameoff = inltree[ix].func_ + inlFunc.funcID = inltree[ix].funcID + + if (flags&_TraceRuntimeFrames) != 0 || showframe(inlFuncInfo, gp, nprint == 0, inlFuncInfo.funcID, lastFuncID) { + name := funcname(inlFuncInfo) file, line := funcline(f, tracepc) print(name, "(...)\n") print("\t", file, ":", line, "\n") @@ -811,6 +819,9 @@ func showframe(f funcInfo, gp *g, firstFrame bool, funcID, childID funcID) bool // showfuncinfo reports whether a function with the given characteristics should // be printed during a traceback. func showfuncinfo(f funcInfo, firstFrame bool, funcID, childID funcID) bool { + // Note that f may be a synthesized funcInfo for an inlined + // function, in which case only nameoff and funcID are set. + level, _, _ := gotraceback() if level > 1 { // Show all frames. |