]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/debugcall.go
runtime: enable allocheaders by default
[gostls13.git] / src / runtime / debugcall.go
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.
4
5 // Though the debug call function feature is not enabled on
6 // ppc64, inserted ppc64 to avoid missing Go declaration error
7 // for debugCallPanicked while building runtime.test
8 //go:build amd64 || arm64 || ppc64le || ppc64
9
10 package runtime
11
12 import (
13         "internal/abi"
14         "unsafe"
15 )
16
17 const (
18         debugCallSystemStack = "executing on Go runtime stack"
19         debugCallUnknownFunc = "call from unknown function"
20         debugCallRuntime     = "call from within the Go runtime"
21         debugCallUnsafePoint = "call not at safe point"
22 )
23
24 func debugCallV2()
25 func debugCallPanicked(val any)
26
27 // debugCallCheck checks whether it is safe to inject a debugger
28 // function call with return PC pc. If not, it returns a string
29 // explaining why.
30 //
31 //go:nosplit
32 func debugCallCheck(pc uintptr) string {
33         // No user calls from the system stack.
34         if getg() != getg().m.curg {
35                 return debugCallSystemStack
36         }
37         if sp := getcallersp(); !(getg().stack.lo < sp && sp <= getg().stack.hi) {
38                 // Fast syscalls (nanotime) and racecall switch to the
39                 // g0 stack without switching g. We can't safely make
40                 // a call in this state. (We can't even safely
41                 // systemstack.)
42                 return debugCallSystemStack
43         }
44
45         // Switch to the system stack to avoid overflowing the user
46         // stack.
47         var ret string
48         systemstack(func() {
49                 f := findfunc(pc)
50                 if !f.valid() {
51                         ret = debugCallUnknownFunc
52                         return
53                 }
54
55                 name := funcname(f)
56
57                 switch name {
58                 case "debugCall32",
59                         "debugCall64",
60                         "debugCall128",
61                         "debugCall256",
62                         "debugCall512",
63                         "debugCall1024",
64                         "debugCall2048",
65                         "debugCall4096",
66                         "debugCall8192",
67                         "debugCall16384",
68                         "debugCall32768",
69                         "debugCall65536":
70                         // These functions are allowed so that the debugger can initiate multiple function calls.
71                         // See: https://golang.org/cl/161137/
72                         return
73                 }
74
75                 // Disallow calls from the runtime. We could
76                 // potentially make this condition tighter (e.g., not
77                 // when locks are held), but there are enough tightly
78                 // coded sequences (e.g., defer handling) that it's
79                 // better to play it safe.
80                 if pfx := "runtime."; len(name) > len(pfx) && name[:len(pfx)] == pfx {
81                         ret = debugCallRuntime
82                         return
83                 }
84
85                 // Check that this isn't an unsafe-point.
86                 if pc != f.entry() {
87                         pc--
88                 }
89                 up := pcdatavalue(f, abi.PCDATA_UnsafePoint, pc)
90                 if up != abi.UnsafePointSafe {
91                         // Not at a safe point.
92                         ret = debugCallUnsafePoint
93                 }
94         })
95         return ret
96 }
97
98 // debugCallWrap starts a new goroutine to run a debug call and blocks
99 // the calling goroutine. On the goroutine, it prepares to recover
100 // panics from the debug call, and then calls the call dispatching
101 // function at PC dispatch.
102 //
103 // This must be deeply nosplit because there are untyped values on the
104 // stack from debugCallV2.
105 //
106 //go:nosplit
107 func debugCallWrap(dispatch uintptr) {
108         var lockedExt uint32
109         callerpc := getcallerpc()
110         gp := getg()
111
112         // Lock ourselves to the OS thread.
113         //
114         // Debuggers rely on us running on the same thread until we get to
115         // dispatch the function they asked as to.
116         //
117         // We're going to transfer this to the new G we just created.
118         lockOSThread()
119
120         // Create a new goroutine to execute the call on. Run this on
121         // the system stack to avoid growing our stack.
122         systemstack(func() {
123                 // TODO(mknyszek): It would be nice to wrap these arguments in an allocated
124                 // closure and start the goroutine with that closure, but the compiler disallows
125                 // implicit closure allocation in the runtime.
126                 fn := debugCallWrap1
127                 newg := newproc1(*(**funcval)(unsafe.Pointer(&fn)), gp, callerpc)
128                 args := &debugCallWrapArgs{
129                         dispatch: dispatch,
130                         callingG: gp,
131                 }
132                 newg.param = unsafe.Pointer(args)
133
134                 // Transfer locked-ness to the new goroutine.
135                 // Save lock state to restore later.
136                 mp := gp.m
137                 if mp != gp.lockedm.ptr() {
138                         throw("inconsistent lockedm")
139                 }
140                 // Save the external lock count and clear it so
141                 // that it can't be unlocked from the debug call.
142                 // Note: we already locked internally to the thread,
143                 // so if we were locked before we're still locked now.
144                 lockedExt = mp.lockedExt
145                 mp.lockedExt = 0
146
147                 mp.lockedg.set(newg)
148                 newg.lockedm.set(mp)
149                 gp.lockedm = 0
150
151                 // Mark the calling goroutine as being at an async
152                 // safe-point, since it has a few conservative frames
153                 // at the bottom of the stack. This also prevents
154                 // stack shrinks.
155                 gp.asyncSafePoint = true
156
157                 // Stash newg away so we can execute it below (mcall's
158                 // closure can't capture anything).
159                 gp.schedlink.set(newg)
160         })
161
162         // Switch to the new goroutine.
163         mcall(func(gp *g) {
164                 // Get newg.
165                 newg := gp.schedlink.ptr()
166                 gp.schedlink = 0
167
168                 // Park the calling goroutine.
169                 if traceEnabled() {
170                         traceGoPark(traceBlockDebugCall, 1)
171                 }
172                 casGToWaiting(gp, _Grunning, waitReasonDebugCall)
173                 dropg()
174
175                 // Directly execute the new goroutine. The debug
176                 // protocol will continue on the new goroutine, so
177                 // it's important we not just let the scheduler do
178                 // this or it may resume a different goroutine.
179                 execute(newg, true)
180         })
181
182         // We'll resume here when the call returns.
183
184         // Restore locked state.
185         mp := gp.m
186         mp.lockedExt = lockedExt
187         mp.lockedg.set(gp)
188         gp.lockedm.set(mp)
189
190         // Undo the lockOSThread we did earlier.
191         unlockOSThread()
192
193         gp.asyncSafePoint = false
194 }
195
196 type debugCallWrapArgs struct {
197         dispatch uintptr
198         callingG *g
199 }
200
201 // debugCallWrap1 is the continuation of debugCallWrap on the callee
202 // goroutine.
203 func debugCallWrap1() {
204         gp := getg()
205         args := (*debugCallWrapArgs)(gp.param)
206         dispatch, callingG := args.dispatch, args.callingG
207         gp.param = nil
208
209         // Dispatch call and trap panics.
210         debugCallWrap2(dispatch)
211
212         // Resume the caller goroutine.
213         getg().schedlink.set(callingG)
214         mcall(func(gp *g) {
215                 callingG := gp.schedlink.ptr()
216                 gp.schedlink = 0
217
218                 // Unlock this goroutine from the M if necessary. The
219                 // calling G will relock.
220                 if gp.lockedm != 0 {
221                         gp.lockedm = 0
222                         gp.m.lockedg = 0
223                 }
224
225                 // Switch back to the calling goroutine. At some point
226                 // the scheduler will schedule us again and we'll
227                 // finish exiting.
228                 if traceEnabled() {
229                         traceGoSched()
230                 }
231                 casgstatus(gp, _Grunning, _Grunnable)
232                 dropg()
233                 lock(&sched.lock)
234                 globrunqput(gp)
235                 unlock(&sched.lock)
236
237                 if traceEnabled() {
238                         traceGoUnpark(callingG, 0)
239                 }
240                 casgstatus(callingG, _Gwaiting, _Grunnable)
241                 execute(callingG, true)
242         })
243 }
244
245 func debugCallWrap2(dispatch uintptr) {
246         // Call the dispatch function and trap panics.
247         var dispatchF func()
248         dispatchFV := funcval{dispatch}
249         *(*unsafe.Pointer)(unsafe.Pointer(&dispatchF)) = noescape(unsafe.Pointer(&dispatchFV))
250
251         var ok bool
252         defer func() {
253                 if !ok {
254                         err := recover()
255                         debugCallPanicked(err)
256                 }
257         }()
258         dispatchF()
259         ok = true
260 }