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