1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
13 debugCallSystemStack = "executing on Go runtime stack"
14 debugCallUnknownFunc = "call from unknown function"
15 debugCallRuntime = "call from within the Go runtime"
16 debugCallUnsafePoint = "call not at safe point"
20 func debugCallPanicked(val interface{})
22 // debugCallCheck checks whether it is safe to inject a debugger
23 // function call with return PC pc. If not, it returns a string
27 func debugCallCheck(pc uintptr) string {
28 // No user calls from the system stack.
29 if getg() != getg().m.curg {
30 return debugCallSystemStack
32 if sp := getcallersp(); !(getg().stack.lo < sp && sp <= getg().stack.hi) {
33 // Fast syscalls (nanotime) and racecall switch to the
34 // g0 stack without switching g. We can't safely make
35 // a call in this state. (We can't even safely
37 return debugCallSystemStack
40 // Switch to the system stack to avoid overflowing the user
46 ret = debugCallUnknownFunc
65 // These functions are allowed so that the debugger can initiate multiple function calls.
66 // See: https://golang.org/cl/161137/
70 // Disallow calls from the runtime. We could
71 // potentially make this condition tighter (e.g., not
72 // when locks are held), but there are enough tightly
73 // coded sequences (e.g., defer handling) that it's
74 // better to play it safe.
75 if pfx := "runtime."; len(name) > len(pfx) && name[:len(pfx)] == pfx {
76 ret = debugCallRuntime
80 // Check that this isn't an unsafe-point.
84 up := pcdatavalue(f, _PCDATA_UnsafePoint, pc, nil)
85 if up != _PCDATA_UnsafePointSafe {
86 // Not at a safe point.
87 ret = debugCallUnsafePoint
93 // debugCallWrap starts a new goroutine to run a debug call and blocks
94 // the calling goroutine. On the goroutine, it prepares to recover
95 // panics from the debug call, and then calls the call dispatching
96 // function at PC dispatch.
98 // This must be deeply nosplit because there are untyped values on the
99 // stack from debugCallV2.
102 func debugCallWrap(dispatch uintptr) {
105 callerpc := getcallerpc()
108 // Create a new goroutine to execute the call on. Run this on
109 // the system stack to avoid growing our stack.
111 // TODO(mknyszek): It would be nice to wrap these arguments in an allocated
112 // closure and start the goroutine with that closure, but the compiler disallows
113 // implicit closure allocation in the runtime.
115 newg := newproc1(*(**funcval)(unsafe.Pointer(&fn)), gp, callerpc)
116 args := &debugCallWrapArgs{
120 newg.param = unsafe.Pointer(args)
122 // If the current G is locked, then transfer that
123 // locked-ness to the new goroutine.
125 // Save lock state to restore later.
127 if mp != gp.lockedm.ptr() {
128 throw("inconsistent lockedm")
132 lockedExt = mp.lockedExt
134 // Transfer external lock count to internal so
135 // it can't be unlocked from the debug call.
144 // Mark the calling goroutine as being at an async
145 // safe-point, since it has a few conservative frames
146 // at the bottom of the stack. This also prevents
148 gp.asyncSafePoint = true
150 // Stash newg away so we can execute it below (mcall's
151 // closure can't capture anything).
152 gp.schedlink.set(newg)
155 // Switch to the new goroutine.
158 newg := gp.schedlink.ptr()
161 // Park the calling goroutine.
162 gp.waitreason = waitReasonDebugCall
164 traceGoPark(traceEvGoBlock, 1)
166 casgstatus(gp, _Grunning, _Gwaiting)
169 // Directly execute the new goroutine. The debug
170 // protocol will continue on the new goroutine, so
171 // it's important we not just let the scheduler do
172 // this or it may resume a different goroutine.
176 // We'll resume here when the call returns.
178 // Restore locked state.
181 mp.lockedExt = lockedExt
187 gp.asyncSafePoint = false
190 type debugCallWrapArgs struct {
195 // debugCallWrap1 is the continuation of debugCallWrap on the callee
197 func debugCallWrap1() {
199 args := (*debugCallWrapArgs)(gp.param)
200 dispatch, callingG := args.dispatch, args.callingG
203 // Dispatch call and trap panics.
204 debugCallWrap2(dispatch)
206 // Resume the caller goroutine.
207 getg().schedlink.set(callingG)
209 callingG := gp.schedlink.ptr()
212 // Unlock this goroutine from the M if necessary. The
213 // calling G will relock.
219 // Switch back to the calling goroutine. At some point
220 // the scheduler will schedule us again and we'll
225 casgstatus(gp, _Grunning, _Grunnable)
232 traceGoUnpark(callingG, 0)
234 casgstatus(callingG, _Gwaiting, _Grunnable)
235 execute(callingG, true)
239 func debugCallWrap2(dispatch uintptr) {
240 // Call the dispatch function and trap panics.
242 dispatchFV := funcval{dispatch}
243 *(*unsafe.Pointer)(unsafe.Pointer(&dispatchF)) = noescape(unsafe.Pointer(&dispatchFV))
249 debugCallPanicked(err)