Source file
src/runtime/debugcall.go
1
2
3
4
5
6
7 package runtime
8
9 import (
10 "internal/abi"
11 "unsafe"
12 )
13
14 const (
15 debugCallSystemStack = "executing on Go runtime stack"
16 debugCallUnknownFunc = "call from unknown function"
17 debugCallRuntime = "call from within the Go runtime"
18 debugCallUnsafePoint = "call not at safe point"
19 )
20
21 func debugCallV2()
22 func debugCallPanicked(val any)
23
24
25
26
27
28
29 func debugCallCheck(pc uintptr) string {
30
31 if getg() != getg().m.curg {
32 return debugCallSystemStack
33 }
34 if sp := getcallersp(); !(getg().stack.lo < sp && sp <= getg().stack.hi) {
35
36
37
38
39 return debugCallSystemStack
40 }
41
42
43
44 var ret string
45 systemstack(func() {
46 f := findfunc(pc)
47 if !f.valid() {
48 ret = debugCallUnknownFunc
49 return
50 }
51
52 name := funcname(f)
53
54 switch name {
55 case "debugCall32",
56 "debugCall64",
57 "debugCall128",
58 "debugCall256",
59 "debugCall512",
60 "debugCall1024",
61 "debugCall2048",
62 "debugCall4096",
63 "debugCall8192",
64 "debugCall16384",
65 "debugCall32768",
66 "debugCall65536":
67
68
69 return
70 }
71
72
73
74
75
76
77 if pfx := "runtime."; len(name) > len(pfx) && name[:len(pfx)] == pfx {
78 ret = debugCallRuntime
79 return
80 }
81
82
83 if pc != f.entry() {
84 pc--
85 }
86 up := pcdatavalue(f, abi.PCDATA_UnsafePoint, pc, nil)
87 if up != abi.UnsafePointSafe {
88
89 ret = debugCallUnsafePoint
90 }
91 })
92 return ret
93 }
94
95
96
97
98
99
100
101
102
103
104 func debugCallWrap(dispatch uintptr) {
105 var lockedExt uint32
106 callerpc := getcallerpc()
107 gp := getg()
108
109
110
111
112
113
114
115 lockOSThread()
116
117
118
119 systemstack(func() {
120
121
122
123 fn := debugCallWrap1
124 newg := newproc1(*(**funcval)(unsafe.Pointer(&fn)), gp, callerpc)
125 args := &debugCallWrapArgs{
126 dispatch: dispatch,
127 callingG: gp,
128 }
129 newg.param = unsafe.Pointer(args)
130
131
132
133 mp := gp.m
134 if mp != gp.lockedm.ptr() {
135 throw("inconsistent lockedm")
136 }
137
138
139
140
141 lockedExt = mp.lockedExt
142 mp.lockedExt = 0
143
144 mp.lockedg.set(newg)
145 newg.lockedm.set(mp)
146 gp.lockedm = 0
147
148
149
150
151
152 gp.asyncSafePoint = true
153
154
155
156 gp.schedlink.set(newg)
157 })
158
159
160 mcall(func(gp *g) {
161
162 newg := gp.schedlink.ptr()
163 gp.schedlink = 0
164
165
166 if traceEnabled() {
167 traceGoPark(traceBlockDebugCall, 1)
168 }
169 casGToWaiting(gp, _Grunning, waitReasonDebugCall)
170 dropg()
171
172
173
174
175
176 execute(newg, true)
177 })
178
179
180
181
182 mp := gp.m
183 mp.lockedExt = lockedExt
184 mp.lockedg.set(gp)
185 gp.lockedm.set(mp)
186
187
188 unlockOSThread()
189
190 gp.asyncSafePoint = false
191 }
192
193 type debugCallWrapArgs struct {
194 dispatch uintptr
195 callingG *g
196 }
197
198
199
200 func debugCallWrap1() {
201 gp := getg()
202 args := (*debugCallWrapArgs)(gp.param)
203 dispatch, callingG := args.dispatch, args.callingG
204 gp.param = nil
205
206
207 debugCallWrap2(dispatch)
208
209
210 getg().schedlink.set(callingG)
211 mcall(func(gp *g) {
212 callingG := gp.schedlink.ptr()
213 gp.schedlink = 0
214
215
216
217 if gp.lockedm != 0 {
218 gp.lockedm = 0
219 gp.m.lockedg = 0
220 }
221
222
223
224
225 if traceEnabled() {
226 traceGoSched()
227 }
228 casgstatus(gp, _Grunning, _Grunnable)
229 dropg()
230 lock(&sched.lock)
231 globrunqput(gp)
232 unlock(&sched.lock)
233
234 if traceEnabled() {
235 traceGoUnpark(callingG, 0)
236 }
237 casgstatus(callingG, _Gwaiting, _Grunnable)
238 execute(callingG, true)
239 })
240 }
241
242 func debugCallWrap2(dispatch uintptr) {
243
244 var dispatchF func()
245 dispatchFV := funcval{dispatch}
246 *(*unsafe.Pointer)(unsafe.Pointer(&dispatchF)) = noescape(unsafe.Pointer(&dispatchFV))
247
248 var ok bool
249 defer func() {
250 if !ok {
251 err := recover()
252 debugCallPanicked(err)
253 }
254 }()
255 dispatchF()
256 ok = true
257 }
258
View as plain text