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