aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/traceback.go
diff options
context:
space:
mode:
authorKeith Randall <khr@google.com>2019-06-03 10:03:44 -0700
committerKeith Randall <khr@golang.org>2019-06-03 18:50:30 +0000
commit38c129b4f0219fa26123fae42ef9a7b3683befde (patch)
treee25d84978bbe36053c9b37c0a5d34671ec5fd8b6 /src/runtime/traceback.go
parent2ce643d3b674c886d60c72246ec7cdd966f2e6cb (diff)
downloadgo-38c129b4f0219fa26123fae42ef9a7b3683befde.tar.gz
go-38c129b4f0219fa26123fae42ef9a7b3683befde.zip
runtime: get map of args of unstarted goroutines like we do for defers
Normally, reflect.makeFuncStub records the context value at a known point in the stack frame, so that the runtime can get the argument map for reflect.makeFuncStub from that known location. This doesn't work for defers or goroutines that haven't started yet, because they haven't allocated a frame or run an instruction yet. The argument map must be extracted from the context value. We already do this for defers (the non-nil ctxt arg to getArgInfo), we just need to do it for unstarted goroutines as well. When we traceback a goroutine, remember the context value from g.sched. Use it for the first frame we find. (We never need it for deeper frames, because we normally don't stop at the start of reflect.makeFuncStub, as it is nosplit. With this CL we could allow makeFuncStub to no longer be nosplit.) Fixes #25897 Change-Id: I427abf332a741a80728cdc0b8412aa8f37e7c418 Reviewed-on: https://go-review.googlesource.com/c/go/+/180258 Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/runtime/traceback.go')
-rw-r--r--src/runtime/traceback.go16
1 files changed, 10 insertions, 6 deletions
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 0bb7fc2831c..d8170185014 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -119,6 +119,8 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
}
level, _, _ := gotraceback()
+ var ctxt *funcval // Context pointer for unstarted goroutines. See issue #25897.
+
if pc0 == ^uintptr(0) && sp0 == ^uintptr(0) { // Signal to fetch saved values from gp.
if gp.syscallsp != 0 {
pc0 = gp.syscallpc
@@ -132,6 +134,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
if usesLR {
lr0 = gp.sched.lr
}
+ ctxt = (*funcval)(gp.sched.ctxt)
}
}
@@ -300,9 +303,10 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
var ok bool
frame.arglen, frame.argmap, ok = getArgInfoFast(f, callback != nil)
if !ok {
- frame.arglen, frame.argmap = getArgInfo(&frame, f, callback != nil, nil)
+ frame.arglen, frame.argmap = getArgInfo(&frame, f, callback != nil, ctxt)
}
}
+ ctxt = nil // ctxt is only needed to get arg maps for the topmost frame
// Determine frame's 'continuation PC', where it can continue.
// Normally this is the return address on the stack, but if sigpanic
@@ -593,10 +597,10 @@ func getArgInfoFast(f funcInfo, needArgMap bool) (arglen uintptr, argmap *bitvec
// with call frame frame.
//
// This is used for both actual calls with active stack frames and for
-// deferred calls that are not yet executing. If this is an actual
+// deferred calls or goroutines that are not yet executing. If this is an actual
// call, ctxt must be nil (getArgInfo will retrieve what it needs from
-// the active stack frame). If this is a deferred call, ctxt must be
-// the function object that was deferred.
+// the active stack frame). If this is a deferred call or unstarted goroutine,
+// ctxt must be the function object that was deferred or go'd.
func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (arglen uintptr, argmap *bitvector) {
arglen = uintptr(f.args)
if needArgMap && f.args == _ArgsSizeUnknown {
@@ -609,8 +613,8 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar
var retValid bool
if ctxt != nil {
// This is not an actual call, but a
- // deferred call. The function value
- // is itself the *reflect.methodValue.
+ // deferred call or an unstarted goroutine.
+ // The function value is itself the *reflect.methodValue.
mv = (*reflectMethodValue)(unsafe.Pointer(ctxt))
} else {
// This is a real call that took the