1
0
mirror of https://github.com/golang/go synced 2024-09-29 21:24:30 -06:00

runtime: resolve caller funcInfo after processing current frame

Currently, gentraceback resolves the funcInfo of the caller prior to
processing the current frame (calling the callback, printing it, etc).
As a result, if this lookup fails in a verbose context, it will print
the failure before printing the frame that it's already resolved.

To fix this, move the resolution of LR to a funcInfo to after current
frame processing.

This also has the advantage that we can reduce the scope of "flr" (the
caller's funcInfo) to only the post-frame part of the loop, which will
make it easier to stack-rip gentraceback into an iterator.

For #54466.

Change-Id: I8be44d4eac598a686c32936ab37018b8aa97c00b
Reviewed-on: https://go-review.googlesource.com/c/go/+/458217
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Felix Geisendörfer <felix.geisendoerfer@datadoghq.com>
This commit is contained in:
Austin Clements 2022-07-17 15:57:09 -04:00
parent 5acd2d658e
commit 6f22d42c74

View File

@ -202,11 +202,10 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
frame.fp += goarch.PtrSize
}
}
var flr funcInfo
var lrPtr uintptr
if flag&funcFlag_TOPFRAME != 0 {
// This function marks the top of the stack. Stop the traceback.
frame.lr = 0
flr = funcInfo{}
} else if flag&funcFlag_SPWRITE != 0 && (callback == nil || n > 0) {
// The function we are in does a write to SP that we don't know
// how to encode in the spdelta table. Examples include context
@ -230,9 +229,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
throw("traceback")
}
frame.lr = 0
flr = funcInfo{}
} else {
var lrPtr uintptr
if usesLR {
if n == 0 && frame.sp < frame.fp || frame.lr == 0 {
lrPtr = frame.sp
@ -244,28 +241,6 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
frame.lr = uintptr(*(*uintptr)(unsafe.Pointer(lrPtr)))
}
}
flr = findfunc(frame.lr)
if !flr.valid() {
// This happens if you get a profiling interrupt at just the wrong time.
// In that context it is okay to stop early.
// But if callback is set, we're doing a garbage collection and must
// get everything, so crash loudly.
doPrint := printing
if doPrint && gp.m.incgo && f.funcID == funcID_sigpanic {
// We can inject sigpanic
// calls directly into C code,
// in which case we'll see a C
// return PC. Don't complain.
doPrint = false
}
if callback != nil || doPrint {
print("runtime: g ", gp.goid, ": unexpected return pc for ", funcname(f), " called from ", hex(frame.lr), "\n")
tracebackHexdump(gp.stack, &frame, lrPtr)
}
if callback != nil {
throw("unknown caller pc")
}
}
}
frame.varp = frame.fp
@ -469,7 +444,30 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
injectedCall := f.funcID == funcID_sigpanic || f.funcID == funcID_asyncPreempt || f.funcID == funcID_debugCallV2
// Do not unwind past the bottom of the stack.
if frame.lr == 0 {
break
}
flr := findfunc(frame.lr)
if !flr.valid() {
// This happens if you get a profiling interrupt at just the wrong time.
// In that context it is okay to stop early.
// But if callback is set, we're doing a garbage collection and must
// get everything, so crash loudly.
doPrint := printing
if doPrint && gp.m.incgo && f.funcID == funcID_sigpanic {
// We can inject sigpanic
// calls directly into C code,
// in which case we'll see a C
// return PC. Don't complain.
doPrint = false
}
if callback != nil || doPrint {
print("runtime: g ", gp.goid, ": unexpected return pc for ", funcname(f), " called from ", hex(frame.lr), "\n")
tracebackHexdump(gp.stack, &frame, lrPtr)
}
if callback != nil {
throw("unknown caller pc")
}
break
}