mirror of https://github.com/golang/go.git
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:
parent
5acd2d658e
commit
6f22d42c74
|
|
@ -202,11 +202,10 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||||
frame.fp += goarch.PtrSize
|
frame.fp += goarch.PtrSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var flr funcInfo
|
var lrPtr uintptr
|
||||||
if flag&funcFlag_TOPFRAME != 0 {
|
if flag&funcFlag_TOPFRAME != 0 {
|
||||||
// This function marks the top of the stack. Stop the traceback.
|
// This function marks the top of the stack. Stop the traceback.
|
||||||
frame.lr = 0
|
frame.lr = 0
|
||||||
flr = funcInfo{}
|
|
||||||
} else if flag&funcFlag_SPWRITE != 0 && (callback == nil || n > 0) {
|
} 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
|
// 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
|
// 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")
|
throw("traceback")
|
||||||
}
|
}
|
||||||
frame.lr = 0
|
frame.lr = 0
|
||||||
flr = funcInfo{}
|
|
||||||
} else {
|
} else {
|
||||||
var lrPtr uintptr
|
|
||||||
if usesLR {
|
if usesLR {
|
||||||
if n == 0 && frame.sp < frame.fp || frame.lr == 0 {
|
if n == 0 && frame.sp < frame.fp || frame.lr == 0 {
|
||||||
lrPtr = frame.sp
|
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)))
|
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
|
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
|
injectedCall := f.funcID == funcID_sigpanic || f.funcID == funcID_asyncPreempt || f.funcID == funcID_debugCallV2
|
||||||
|
|
||||||
// Do not unwind past the bottom of the stack.
|
// Do not unwind past the bottom of the stack.
|
||||||
|
if frame.lr == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
flr := findfunc(frame.lr)
|
||||||
if !flr.valid() {
|
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
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue