Source file
src/runtime/tracestack.go
1
2
3
4
5
6
7 package runtime
8
9 import (
10 "internal/abi"
11 "internal/goarch"
12 "internal/trace/tracev2"
13 "unsafe"
14 )
15
16 const (
17
18
19
20
21 logicalStackSentinel = ^uintptr(0)
22 )
23
24
25
26
27
28
29
30
31
32 func traceStack(skip int, gp *g, tab *traceStackTable) uint64 {
33 var pcBuf [tracev2.MaxFramesPerStack]uintptr
34
35
36 var mp *m
37 if gp == nil {
38 mp = getg().m
39 gp = mp.curg
40 }
41
42
43 if debug.traceCheckStackOwnership != 0 && gp != nil {
44 status := readgstatus(gp)
45
46 if status&_Gscan == 0 {
47
48
49
50
51 switch goStatusToTraceGoStatus(status, gp.waitreason) {
52 case tracev2.GoRunning, tracev2.GoSyscall:
53 if getg() == gp || mp.curg == gp {
54 break
55 }
56 fallthrough
57 default:
58 print("runtime: gp=", unsafe.Pointer(gp), " gp.goid=", gp.goid, " status=", gStatusStrings[status], "\n")
59 throw("attempted to trace stack of a goroutine this thread does not own")
60 }
61 }
62 }
63
64 if gp != nil && mp == nil {
65
66
67 mp = gp.lockedm.ptr()
68 }
69 nstk := 1
70 if tracefpunwindoff() || (mp != nil && mp.hasCgoOnStack()) {
71
72
73
74
75
76
77 pcBuf[0] = logicalStackSentinel
78 if getg() == gp {
79 nstk += callers(skip+1, pcBuf[1:])
80 } else if gp != nil {
81 nstk += gcallers(gp, skip, pcBuf[1:])
82 }
83 } else {
84
85 pcBuf[0] = uintptr(skip)
86 if getg() == gp {
87 nstk += fpTracebackPCs(unsafe.Pointer(getfp()), pcBuf[1:])
88 } else if gp != nil {
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 if gp.syscallsp != 0 {
106 pcBuf[1] = gp.syscallpc
107 nstk += 1 + fpTracebackPCs(unsafe.Pointer(gp.syscallbp), pcBuf[2:])
108 } else {
109 pcBuf[1] = gp.sched.pc
110 if gp.syncSafePoint {
111
112
113
114
115
116
117 if usesLR {
118 pcBuf[2] = gp.sched.lr
119 } else {
120 pcBuf[2] = *(*uintptr)(unsafe.Pointer(gp.sched.sp))
121 }
122 nstk += 2 + fpTracebackPCs(unsafe.Pointer(gp.sched.bp), pcBuf[3:])
123 } else {
124 nstk += 1 + fpTracebackPCs(unsafe.Pointer(gp.sched.bp), pcBuf[2:])
125 }
126 }
127 }
128 }
129 if nstk > 0 {
130 nstk--
131 }
132 if nstk > 0 && gp.goid == 1 {
133 nstk--
134 }
135 id := tab.put(pcBuf[:nstk])
136 return id
137 }
138
139
140
141 type traceStackTable struct {
142 tab traceMap
143 }
144
145
146
147 func (t *traceStackTable) put(pcs []uintptr) uint64 {
148 if len(pcs) == 0 {
149 return 0
150 }
151 id, _ := t.tab.put(noescape(unsafe.Pointer(&pcs[0])), uintptr(len(pcs))*unsafe.Sizeof(uintptr(0)))
152 return id
153 }
154
155
156
157
158 func (t *traceStackTable) dump(gen uintptr) {
159 stackBuf := make([]uintptr, tracev2.MaxFramesPerStack)
160 w := unsafeTraceWriter(gen, nil)
161 if root := (*traceMapNode)(t.tab.root.Load()); root != nil {
162 w = dumpStacksRec(root, w, stackBuf)
163 }
164 w.flush().end()
165 t.tab.reset()
166 }
167
168 func dumpStacksRec(node *traceMapNode, w traceWriter, stackBuf []uintptr) traceWriter {
169 stack := unsafe.Slice((*uintptr)(unsafe.Pointer(&node.data[0])), uintptr(len(node.data))/unsafe.Sizeof(uintptr(0)))
170
171
172
173 n := fpunwindExpand(stackBuf, stack)
174 frames := makeTraceFrames(w.gen, stackBuf[:n])
175
176
177
178 maxBytes := 1 + (2+4*len(frames))*traceBytesPerNumber
179
180
181
182
183
184
185 var flushed bool
186 w, flushed = w.ensure(1 + maxBytes)
187 if flushed {
188 w.byte(byte(tracev2.EvStacks))
189 }
190
191
192 w.byte(byte(tracev2.EvStack))
193 w.varint(uint64(node.id))
194 w.varint(uint64(len(frames)))
195 for _, frame := range frames {
196 w.varint(uint64(frame.PC))
197 w.varint(frame.funcID)
198 w.varint(frame.fileID)
199 w.varint(frame.line)
200 }
201
202
203 for i := range node.children {
204 child := node.children[i].Load()
205 if child == nil {
206 continue
207 }
208 w = dumpStacksRec((*traceMapNode)(child), w, stackBuf)
209 }
210 return w
211 }
212
213
214
215 func makeTraceFrames(gen uintptr, pcs []uintptr) []traceFrame {
216 frames := make([]traceFrame, 0, len(pcs))
217 ci := CallersFrames(pcs)
218 for {
219 f, more := ci.Next()
220 frames = append(frames, makeTraceFrame(gen, f))
221 if !more {
222 return frames
223 }
224 }
225 }
226
227 type traceFrame struct {
228 PC uintptr
229 funcID uint64
230 fileID uint64
231 line uint64
232 }
233
234
235 func makeTraceFrame(gen uintptr, f Frame) traceFrame {
236 var frame traceFrame
237 frame.PC = f.PC
238
239 fn := f.Function
240 const maxLen = 1 << 10
241 if len(fn) > maxLen {
242 fn = fn[len(fn)-maxLen:]
243 }
244 frame.funcID = trace.stringTab[gen%2].put(gen, fn)
245 frame.line = uint64(f.Line)
246 file := f.File
247 if len(file) > maxLen {
248 file = file[len(file)-maxLen:]
249 }
250 frame.fileID = trace.stringTab[gen%2].put(gen, file)
251 return frame
252 }
253
254
255
256 func tracefpunwindoff() bool {
257 return debug.tracefpunwindoff != 0 || (goarch.ArchFamily != goarch.AMD64 && goarch.ArchFamily != goarch.ARM64)
258 }
259
260
261
262
263
264 func fpTracebackPCs(fp unsafe.Pointer, pcBuf []uintptr) (i int) {
265 for i = 0; i < len(pcBuf) && fp != nil; i++ {
266
267 pcBuf[i] = *(*uintptr)(unsafe.Pointer(uintptr(fp) + goarch.PtrSize))
268
269 fp = unsafe.Pointer(*(*uintptr)(fp))
270 }
271 return i
272 }
273
274
275 func pprof_fpunwindExpand(dst, src []uintptr) int {
276 return fpunwindExpand(dst, src)
277 }
278
279
280
281
282
283
284
285
286
287
288 func fpunwindExpand(dst, pcBuf []uintptr) int {
289 if len(pcBuf) == 0 {
290 return 0
291 } else if len(pcBuf) > 0 && pcBuf[0] == logicalStackSentinel {
292
293
294 return copy(dst, pcBuf[1:])
295 }
296
297 var (
298 n int
299 lastFuncID = abi.FuncIDNormal
300 skip = pcBuf[0]
301
302
303 skipOrAdd = func(retPC uintptr) bool {
304 if skip > 0 {
305 skip--
306 } else if n < len(dst) {
307 dst[n] = retPC
308 n++
309 }
310 return n < len(dst)
311 }
312 )
313
314 outer:
315 for _, retPC := range pcBuf[1:] {
316 callPC := retPC - 1
317 fi := findfunc(callPC)
318 if !fi.valid() {
319
320
321 if more := skipOrAdd(retPC); !more {
322 break outer
323 }
324 continue
325 }
326
327 u, uf := newInlineUnwinder(fi, callPC)
328 for ; uf.valid(); uf = u.next(uf) {
329 sf := u.srcFunc(uf)
330 if sf.funcID == abi.FuncIDWrapper && elideWrapperCalling(lastFuncID) {
331
332 } else if more := skipOrAdd(uf.pc + 1); !more {
333 break outer
334 }
335 lastFuncID = sf.funcID
336 }
337 }
338 return n
339 }
340
341
342
343
344 func startPCForTrace(pc uintptr) uintptr {
345 f := findfunc(pc)
346 if !f.valid() {
347 return pc
348 }
349 w := funcdata(f, abi.FUNCDATA_WrapInfo)
350 if w == nil {
351 return pc
352 }
353 return f.datap.textAddr(*(*uint32)(w))
354 }
355
View as plain text