OLD | NEW |
| (Empty) |
1 // Copyright 2009 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 #include "runtime.h" | |
6 #include "arch_GOARCH.h" | |
7 #include "malloc.h" | |
8 #include "funcdata.h" | |
9 | |
10 void runtime·sigpanic(void); | |
11 void runtime·newproc(void); | |
12 void runtime·deferproc(void); | |
13 | |
14 int32 | |
15 runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, u
intptr *pcbuf, int32 max, bool (*callback)(Stkframe*, void*), void *v, bool prin
tall) | |
16 { | |
17 int32 i, n, nprint, line, gotraceback; | |
18 uintptr x, tracepc, sparg; | |
19 bool waspanic, wasnewproc, printing; | |
20 Func *f, *flr; | |
21 Stkframe frame; | |
22 Stktop *stk; | |
23 String file; | |
24 Panic *panic; | |
25 Defer *defer; | |
26 | |
27 gotraceback = runtime·gotraceback(nil); | |
28 | |
29 if(pc0 == ~(uintptr)0 && sp0 == ~(uintptr)0) { // Signal to fetch saved
values from gp. | |
30 if(gp->syscallstack != (uintptr)nil) { | |
31 pc0 = gp->syscallpc; | |
32 sp0 = gp->syscallsp; | |
33 lr0 = 0; | |
34 } else { | |
35 pc0 = gp->sched.pc; | |
36 sp0 = gp->sched.sp; | |
37 lr0 = gp->sched.lr; | |
38 } | |
39 } | |
40 | |
41 nprint = 0; | |
42 runtime·memclr((byte*)&frame, sizeof frame); | |
43 frame.pc = pc0; | |
44 frame.lr = lr0; | |
45 frame.sp = sp0; | |
46 waspanic = false; | |
47 wasnewproc = false; | |
48 printing = pcbuf==nil && callback==nil; | |
49 | |
50 panic = gp->panic; | |
51 defer = gp->defer; | |
52 | |
53 while(defer != nil && defer->argp == NoArgs) | |
54 defer = defer->link;···· | |
55 while(panic != nil && panic->defer == nil) | |
56 panic = panic->link; | |
57 | |
58 // If the PC is zero, it's likely a nil function call. | |
59 // Start in the caller's frame. | |
60 if(frame.pc == 0) { | |
61 frame.pc = frame.lr; | |
62 frame.lr = 0; | |
63 } | |
64 ········ | |
65 f = runtime·findfunc(frame.pc); | |
66 if(f == nil) { | |
67 if(callback != nil) { | |
68 runtime·printf("runtime: unknown pc %p\n", frame.pc); | |
69 runtime·throw("unknown pc"); | |
70 } | |
71 return 0; | |
72 } | |
73 frame.fn = f; | |
74 | |
75 n = 0; | |
76 stk = (Stktop*)gp->stackbase; | |
77 while(n < max) { | |
78 // Typically: | |
79 // pc is the PC of the running function. | |
80 // sp is the stack pointer at that program counter. | |
81 // fp is the frame pointer (caller's stack pointer) at that
program counter, or nil if unknown. | |
82 // stk is the stack containing sp. | |
83 // The caller's program counter is lr, unless lr is zero, i
n which case it is *(uintptr*)sp. | |
84 ················ | |
85 if(frame.pc == (uintptr)runtime·lessstack) { | |
86 // Hit top of stack segment. Unwind to next segment. | |
87 frame.pc = stk->gobuf.pc; | |
88 frame.sp = stk->gobuf.sp; | |
89 frame.lr = 0; | |
90 frame.fp = 0; | |
91 if(printing && runtime·showframe(nil, gp)) | |
92 runtime·printf("----- stack segment boundary ---
--\n"); | |
93 stk = (Stktop*)stk->stackbase; | |
94 ························ | |
95 f = runtime·findfunc(frame.pc); | |
96 if(f == nil) { | |
97 runtime·printf("runtime: unknown pc %p after sta
ck split\n", frame.pc); | |
98 if(callback != nil) | |
99 runtime·throw("unknown pc"); | |
100 } | |
101 frame.fn = f; | |
102 continue; | |
103 } | |
104 f = frame.fn; | |
105 ················ | |
106 // Found an actual function. | |
107 // Derive frame pointer and link register. | |
108 if(frame.fp == 0) | |
109 frame.fp = frame.sp + runtime·funcspdelta(f, frame.pc); | |
110 if(runtime·topofstack(f)) { | |
111 frame.lr = 0; | |
112 flr = nil; | |
113 } else if(f->entry == (uintptr)runtime·jmpdefer) { | |
114 // jmpdefer modifies SP/LR/PC non-atomically. | |
115 // If a profiling interrupt arrives during jmpdefer, | |
116 // the stack unwind may see a mismatched register set | |
117 // and get confused. Stop if we see PC within jmpdefer | |
118 // to avoid that confusion. | |
119 // See golang.org/issue/8153. | |
120 // This check can be deleted if jmpdefer is changed | |
121 // to restore all three atomically using pop. | |
122 if(callback != nil) | |
123 runtime·throw("traceback_arm: found jmpdefer whe
n tracing with callback"); | |
124 frame.lr = 0; | |
125 flr = nil; | |
126 } else { | |
127 if((n == 0 && frame.sp < frame.fp) || frame.lr == 0) | |
128 frame.lr = *(uintptr*)frame.sp; | |
129 flr = runtime·findfunc(frame.lr); | |
130 if(flr == nil) { | |
131 // This happens if you get a profiling interrupt
at just the wrong time. | |
132 // In that context it is okay to stop early. | |
133 // But if callback is set, we're doing a garbage
collection and must | |
134 // get everything, so crash loudly. | |
135 if(callback != nil) { | |
136 runtime·printf("runtime: unexpected retu
rn pc for %s called from %p\n", runtime·funcname(f), frame.lr); | |
137 runtime·throw("unknown caller pc"); | |
138 } | |
139 } | |
140 } | |
141 | |
142 frame.varp = frame.fp; | |
143 | |
144 // Derive size of arguments. | |
145 // Most functions have a fixed-size argument block, | |
146 // so we can use metadata about the function f. | |
147 // Not all, though: there are some variadic functions | |
148 // in package runtime and reflect, and for those we use call-spe
cific | |
149 // metadata recorded by f's caller. | |
150 if(callback != nil || printing) { | |
151 frame.argp = frame.fp + sizeof(uintptr); | |
152 if(f->args != ArgsSizeUnknown) | |
153 frame.arglen = f->args; | |
154 else if(flr == nil) | |
155 frame.arglen = 0; | |
156 else if(frame.lr == (uintptr)runtime·lessstack) | |
157 frame.arglen = stk->argsize; | |
158 else if((i = runtime·funcarglen(flr, frame.lr)) >= 0) | |
159 frame.arglen = i; | |
160 else { | |
161 runtime·printf("runtime: unknown argument frame
size for %s called from %p [%s]\n", | |
162 runtime·funcname(f), frame.lr, flr ? run
time·funcname(flr) : "?"); | |
163 if(callback != nil) | |
164 runtime·throw("invalid stack"); | |
165 frame.arglen = 0; | |
166 } | |
167 } | |
168 | |
169 // Determine function SP where deferproc would find its argument
s. | |
170 // On ARM that's just the standard bottom-of-stack plus 1 word f
or | |
171 // the saved LR. If the previous frame was a direct call to newp
roc/deferproc, | |
172 // however, the SP is three words lower than normal. | |
173 // If the function has no frame at all - perhaps it just started
, or perhaps | |
174 // it is a leaf with no local variables - then we cannot possibl
y find its | |
175 // SP in a defer, and we might confuse its SP for its caller's S
P, so | |
176 // set sparg=0 in that case. | |
177 sparg = 0; | |
178 if(frame.fp != frame.sp) { | |
179 sparg = frame.sp + sizeof(uintreg); | |
180 if(wasnewproc) | |
181 sparg += 3*sizeof(uintreg); | |
182 } | |
183 | |
184 // Determine frame's 'continuation PC', where it can continue. | |
185 // Normally this is the return address on the stack, but if sigp
anic | |
186 // is immediately below this function on the stack, then the fra
me | |
187 // stopped executing due to a trap, and frame.pc is probably not | |
188 // a safe point for looking up liveness information. In this pan
icking case, | |
189 // the function either doesn't return at all (if it has no defer
s or if the | |
190 // defers do not recover) or it returns from one of the calls to······· | |
191 // deferproc a second time (if the corresponding deferred func r
ecovers). | |
192 // It suffices to assume that the most recent deferproc is the o
ne that | |
193 // returns; everything live at earlier deferprocs is still live
at that one. | |
194 frame.continpc = frame.pc; | |
195 if(waspanic) { | |
196 if(panic != nil && panic->defer->argp == sparg) | |
197 frame.continpc = (uintptr)panic->defer->pc; | |
198 else if(defer != nil && defer->argp == sparg) | |
199 frame.continpc = (uintptr)defer->pc; | |
200 else | |
201 frame.continpc = 0; | |
202 } | |
203 | |
204 // Unwind our local panic & defer stacks past this frame. | |
205 while(panic != nil && (panic->defer == nil || panic->defer->argp
== sparg || panic->defer->argp == NoArgs)) | |
206 panic = panic->link; | |
207 while(defer != nil && (defer->argp == sparg || defer->argp == No
Args)) | |
208 defer = defer->link;···· | |
209 | |
210 if(skip > 0) { | |
211 skip--; | |
212 goto skipped; | |
213 } | |
214 | |
215 if(pcbuf != nil) | |
216 pcbuf[n] = frame.pc; | |
217 if(callback != nil) { | |
218 if(!callback(&frame, v)) | |
219 return n; | |
220 } | |
221 if(printing) { | |
222 if(printall || runtime·showframe(f, gp)) { | |
223 // Print during crash. | |
224 // main(0x1, 0x2, 0x3) | |
225 // /home/rsc/go/src/runtime/x.go:23
+0xf | |
226 tracepc = frame.pc; // back up to CALL instr
uction for funcline. | |
227 if(n > 0 && frame.pc > f->entry && !waspanic) | |
228 tracepc -= sizeof(uintptr); | |
229 runtime·printf("%s(", runtime·funcname(f)); | |
230 for(i = 0; i < frame.arglen/sizeof(uintptr); i++
) { | |
231 if(i >= 10) { | |
232 runtime·prints(", ..."); | |
233 break; | |
234 } | |
235 if(i != 0) | |
236 runtime·prints(", "); | |
237 runtime·printhex(((uintptr*)frame.argp)[
i]); | |
238 } | |
239 runtime·prints(")\n"); | |
240 line = runtime·funcline(f, tracepc, &file); | |
241 runtime·printf("\t%S:%d", file, line); | |
242 if(frame.pc > f->entry) | |
243 runtime·printf(" +%p", (uintptr)(frame.p
c - f->entry)); | |
244 if(g->m->throwing > 0 && gp == g->m->curg || got
raceback >= 2) | |
245 runtime·printf(" fp=%p sp=%p", frame.fp,
frame.sp); | |
246 runtime·printf("\n"); | |
247 nprint++; | |
248 } | |
249 } | |
250 n++; | |
251 ················ | |
252 skipped: | |
253 waspanic = f->entry == (uintptr)runtime·sigpanic; | |
254 wasnewproc = f->entry == (uintptr)runtime·newproc || f->entry ==
(uintptr)runtime·deferproc; | |
255 | |
256 // Do not unwind past the bottom of the stack. | |
257 if(flr == nil) | |
258 break; | |
259 | |
260 // Unwind to next frame. | |
261 frame.pc = frame.lr; | |
262 frame.fn = flr; | |
263 frame.lr = 0; | |
264 frame.sp = frame.fp; | |
265 frame.fp = 0; | |
266 ········ | |
267 // sighandler saves the lr on stack before faking a call to sigp
anic | |
268 if(waspanic) { | |
269 x = *(uintptr*)frame.sp; | |
270 frame.sp += 4; | |
271 frame.fn = f = runtime·findfunc(frame.pc); | |
272 if(f == nil) | |
273 frame.pc = x; | |
274 else if(f->frame == 0) | |
275 frame.lr = x; | |
276 } | |
277 } | |
278 ········ | |
279 if(pcbuf == nil && callback == nil) | |
280 n = nprint; | |
281 | |
282 // For rationale, see long comment in traceback_x86.c. | |
283 if(callback != nil && n < max && defer != nil) { | |
284 if(defer != nil) | |
285 runtime·printf("runtime: g%D: leftover defer argp=%p pc=
%p\n", gp->goid, defer->argp, defer->pc); | |
286 if(panic != nil) | |
287 runtime·printf("runtime: g%D: leftover panic argp=%p pc=
%p\n", gp->goid, panic->defer->argp, panic->defer->pc); | |
288 for(defer = gp->defer; defer != nil; defer = defer->link) | |
289 runtime·printf("\tdefer %p argp=%p pc=%p\n", defer, defe
r->argp, defer->pc); | |
290 for(panic = gp->panic; panic != nil; panic = panic->link) { | |
291 runtime·printf("\tpanic %p defer %p", panic, panic->defe
r); | |
292 if(panic->defer != nil) | |
293 runtime·printf(" argp=%p pc=%p", panic->defer->a
rgp, panic->defer->pc); | |
294 runtime·printf("\n"); | |
295 } | |
296 runtime·throw("traceback has leftover defers or panics"); | |
297 } | |
298 | |
299 return n;··············· | |
300 } | |
301 | |
302 void | |
303 runtime·printcreatedby(G *gp) | |
304 { | |
305 int32 line; | |
306 uintptr pc, tracepc; | |
307 Func *f; | |
308 String file; | |
309 | |
310 // Show what created goroutine, except main goroutine (goid 1). | |
311 if((pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil && | |
312 runtime·showframe(f, gp) && gp->goid != 1) { | |
313 runtime·printf("created by %s\n", runtime·funcname(f)); | |
314 tracepc = pc; // back up to CALL instruction for funcline. | |
315 if(pc > f->entry) | |
316 tracepc -= PCQuantum; | |
317 line = runtime·funcline(f, tracepc, &file); | |
318 runtime·printf("\t%S:%d", file, line); | |
319 if(pc > f->entry) | |
320 runtime·printf(" +%p", (uintptr)(pc - f->entry)); | |
321 runtime·printf("\n"); | |
322 } | |
323 } | |
324 | |
325 void | |
326 runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp) | |
327 { | |
328 int32 n; | |
329 | |
330 if((runtime·readgstatus(gp)&~Gscan) == Gsyscall){ | |
331 // Override signal registers if blocked in system call. | |
332 pc = gp->syscallpc; | |
333 sp = gp->syscallsp; | |
334 lr = 0; | |
335 } | |
336 | |
337 // Print traceback. By default, omits runtime frames. | |
338 // If that means we print nothing at all, repeat forcing all frames prin
ted. | |
339 n = runtime·gentraceback(pc, sp, lr, gp, 0, nil, TracebackMaxFrames, nil
, nil, false); | |
340 if(n == 0) | |
341 runtime·gentraceback(pc, sp, lr, gp, 0, nil, TracebackMaxFrames,
nil, nil, true); | |
342 if(n == TracebackMaxFrames) | |
343 runtime·printf("...additional frames elided...\n"); | |
344 runtime·printcreatedby(gp); | |
345 } | |
346 | |
347 // func caller(n int) (pc uintptr, file string, line int, ok bool) | |
348 int32 | |
349 runtime·callers(int32 skip, uintptr *pcbuf, int32 m) | |
350 { | |
351 uintptr pc, sp; | |
352 ········ | |
353 sp = runtime·getcallersp(&skip); | |
354 pc = (uintptr)runtime·getcallerpc(&skip); | |
355 | |
356 return runtime·gentraceback(pc, sp, 0, g, skip, pcbuf, m, nil, nil, fals
e); | |
357 } | |
358 | |
359 int32 | |
360 runtime·gcallers(G *gp, int32 skip, uintptr *pcbuf, int32 m) | |
361 { | |
362 return runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, skip, pcbuf
, m, nil, nil, false); | |
363 } | |
OLD | NEW |