traceback_x86.c 8.61 KB
Newer Older
1 2 3 4
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

Dave Cheney's avatar
Dave Cheney committed
5
// +build amd64 amd64p32 386
Russ Cox's avatar
Russ Cox committed
6

7
#include "runtime.h"
Russ Cox's avatar
Russ Cox committed
8
#include "arch_GOARCH.h"
Russ Cox's avatar
Russ Cox committed
9
#include "malloc.h"
10
#include "funcdata.h"
Russ Cox's avatar
Russ Cox committed
11 12 13
#ifdef GOOS_windows
#include "defs_GOOS_GOARCH.h"
#endif
14

15
void runtime·sigpanic(void);
16

Russ Cox's avatar
Russ Cox committed
17 18 19 20
#ifdef GOOS_windows
void runtime·sigtramp(void);
#endif

Russ Cox's avatar
Russ Cox committed
21 22 23
// This code is also used for the 386 tracebacks.
// Use uintptr for an appropriate word-sized integer.

24 25
// Generic traceback.  Handles runtime stack prints (pcbuf == nil),
// the runtime.Callers function (pcbuf != nil), as well as the garbage
26
// collector (callback != nil).  A little clunky to merge these, but avoids
27
// duplicating the code and all its subtlety.
Russ Cox's avatar
Russ Cox committed
28
int32
Keith Randall's avatar
Keith Randall committed
29
runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, bool (*callback)(Stkframe*, void*), void *v, bool printall)
30
{
31
	int32 i, n, nprint, line, gotraceback;
32 33
	uintptr tracepc;
	bool waspanic, printing;
34
	Func *f, *flr;
35
	Stkframe frame;
Russ Cox's avatar
Russ Cox committed
36
	Stktop *stk;
37
	String file;
38

Russ Cox's avatar
Russ Cox committed
39
	USED(lr0);
40
	
41 42
	gotraceback = runtime·gotraceback(nil);
	
43 44 45 46 47 48 49 50 51
	if(pc0 == ~(uintptr)0 && sp0 == ~(uintptr)0) { // Signal to fetch saved values from gp.
		if(gp->syscallstack != (uintptr)nil) {
			pc0 = gp->syscallpc;
			sp0 = gp->syscallsp;
		} else {
			pc0 = gp->sched.pc;
			sp0 = gp->sched.sp;
		}
	}
52

53
	nprint = 0;
54 55 56
	runtime·memclr((byte*)&frame, sizeof frame);
	frame.pc = pc0;
	frame.sp = sp0;
57
	waspanic = false;
58
	printing = pcbuf==nil && callback==nil;
59
	
Russ Cox's avatar
Russ Cox committed
60 61
	// If the PC is zero, it's likely a nil function call.
	// Start in the caller's frame.
62 63
	if(frame.pc == 0) {
		frame.pc = *(uintptr*)frame.sp;
Dave Cheney's avatar
Dave Cheney committed
64
		frame.sp += sizeof(uintreg);
65
	}
66 67 68 69 70 71 72 73 74 75
	
	f = runtime·findfunc(frame.pc);
	if(f == nil) {
		if(callback != nil) {
			runtime·printf("runtime: unknown pc %p\n", frame.pc);
			runtime·throw("unknown pc");
		}
		return 0;
	}
	frame.fn = f;
76

Russ Cox's avatar
Russ Cox committed
77
	n = 0;
78
	stk = (Stktop*)gp->stackbase;
79
	while(n < max) {
80 81 82 83 84 85 86
		// Typically:
		//	pc is the PC of the running function.
		//	sp is the stack pointer at that program counter.
		//	fp is the frame pointer (caller's stack pointer) at that program counter, or nil if unknown.
		//	stk is the stack containing sp.
		//	The caller's program counter is lr, unless lr is zero, in which case it is *(uintptr*)sp.
	
87
		if(frame.pc == (uintptr)runtime·lessstack) {
Russ Cox's avatar
Russ Cox committed
88
			// Hit top of stack segment.  Unwind to next segment.
89 90 91 92
			frame.pc = stk->gobuf.pc;
			frame.sp = stk->gobuf.sp;
			frame.lr = 0;
			frame.fp = 0;
93
			frame.fn = nil;
94
			if(printing && runtime·showframe(nil, gp))
95
				runtime·printf("----- stack segment boundary -----\n");
96
			stk = (Stktop*)stk->stackbase;
97 98 99 100

			f = runtime·findfunc(frame.pc);
			if(f == nil) {
				runtime·printf("runtime: unknown pc %p after stack split\n", frame.pc);
101 102
				if(callback != nil)
					runtime·throw("unknown pc");
103
			}
104 105
			frame.fn = f;
			continue;
106
		}
Russ Cox's avatar
Russ Cox committed
107
		
108
		f = frame.fn;
109

Russ Cox's avatar
Russ Cox committed
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
#ifdef GOOS_windows
		// Windows exception handlers run on the actual g stack (there is room
		// dedicated to this below the usual "bottom of stack"), not on a separate
		// stack. As a result, we have to be able to unwind past the exception
		// handler when called to unwind during stack growth inside the handler.
		// Recognize the frame at the call to sighandler in sigtramp and unwind
		// using the context argument passed to the call. This is awful.
		if(f != nil && f->entry == (uintptr)runtime·sigtramp && frame.pc > f->entry) {
			Context *r;
			
			// Invoke callback so that stack copier sees an uncopyable frame.
			if(callback != nil) {
				frame.argp = nil;
				frame.arglen = 0;
				if(!callback(&frame, v))
					return n;
			}
			r = (Context*)((uintptr*)frame.sp)[1];
#ifdef GOARCH_amd64
			frame.pc = r->Rip;
			frame.sp = r->Rsp;
#else
			frame.pc = r->Eip;
			frame.sp = r->Esp;
#endif
			frame.lr = 0;
			frame.fp = 0;
			frame.fn = nil;
			if(printing && runtime·showframe(nil, gp))
				runtime·printf("----- exception handler -----\n");
			f = runtime·findfunc(frame.pc);
			if(f == nil) {
				runtime·printf("runtime: unknown pc %p after exception handler\n", frame.pc);
				if(callback != nil)
					runtime·throw("unknown pc");
			}
			frame.fn = f;
			continue;
		}
#endif

151
		// Found an actual function.
152 153
		// Derive frame pointer and link register.
		if(frame.fp == 0) {
154
			frame.fp = frame.sp + runtime·funcspdelta(f, frame.pc);
Dave Cheney's avatar
Dave Cheney committed
155
			frame.fp += sizeof(uintreg); // caller PC
156
		}
157 158 159 160 161
		if(runtime·topofstack(f)) {
			frame.lr = 0;
			flr = nil;
		} else {
			if(frame.lr == 0)
Dave Cheney's avatar
Dave Cheney committed
162
				frame.lr = ((uintreg*)frame.fp)[-1];
163 164
			flr = runtime·findfunc(frame.lr);
			if(flr == nil) {
165 166 167
				runtime·printf("runtime: unexpected return pc for %s called from %p\n", runtime·funcname(f), frame.lr);
				if(callback != nil)
					runtime·throw("unknown caller pc");
168 169
			}
		}
170
		
Dave Cheney's avatar
Dave Cheney committed
171
		frame.varp = (byte*)frame.fp - sizeof(uintreg);
172 173

		// Derive size of arguments.
174 175 176
		// Most functions have a fixed-size argument block,
		// so we can use metadata about the function f.
		// Not all, though: there are some variadic functions
177
		// in package runtime and reflect, and for those we use call-specific
178 179 180 181 182 183 184 185 186 187 188 189
		// metadata recorded by f's caller.
		if(callback != nil || printing) {
			frame.argp = (byte*)frame.fp;
			if(f->args != ArgsSizeUnknown)
				frame.arglen = f->args;
			else if(flr == nil)
				frame.arglen = 0;
			else if(frame.lr == (uintptr)runtime·lessstack)
				frame.arglen = stk->argsize;
			else if((i = runtime·funcarglen(flr, frame.lr)) >= 0)
				frame.arglen = i;
			else {
190 191
				runtime·printf("runtime: unknown argument frame size for %s called from %p [%s]\n",
					runtime·funcname(f), frame.lr, flr ? runtime·funcname(flr) : "?");
192
				if(callback != nil)
193 194 195
					runtime·throw("invalid stack");
				frame.arglen = 0;
			}
196 197 198 199 200 201 202 203 204
		}

		if(skip > 0) {
			skip--;
			goto skipped;
		}

		if(pcbuf != nil)
			pcbuf[n] = frame.pc;
Keith Randall's avatar
Keith Randall committed
205 206 207 208
		if(callback != nil) {
			if(!callback(&frame, v))
				return n;
		}
209
		if(printing) {
210
			if(printall || runtime·showframe(f, gp)) {
Russ Cox's avatar
Russ Cox committed
211 212 213 214
				// Print during crash.
				//	main(0x1, 0x2, 0x3)
				//		/home/rsc/go/src/runtime/x.go:23 +0xf
				//		
215 216
				tracepc = frame.pc;	// back up to CALL instruction for funcline.
				if(n > 0 && frame.pc > f->entry && !waspanic)
Russ Cox's avatar
Russ Cox committed
217
					tracepc--;
218
				runtime·printf("%s(", runtime·funcname(f));
219
				for(i = 0; i < frame.arglen/sizeof(uintptr); i++) {
220
					if(i >= 10) {
Russ Cox's avatar
Russ Cox committed
221 222 223
						runtime·prints(", ...");
						break;
					}
224 225 226
					if(i != 0)
						runtime·prints(", ");
					runtime·printhex(((uintptr*)frame.argp)[i]);
Russ Cox's avatar
Russ Cox committed
227
				}
Russ Cox's avatar
Russ Cox committed
228
				runtime·prints(")\n");
229 230
				line = runtime·funcline(f, tracepc, &file);
				runtime·printf("\t%S:%d", file, line);
231 232
				if(frame.pc > f->entry)
					runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
233
				if(m->throwing > 0 && gp == m->curg || gotraceback >= 2)
234
					runtime·printf(" fp=%p", frame.fp);
Russ Cox's avatar
Russ Cox committed
235
				runtime·printf("\n");
236
				nprint++;
Russ Cox's avatar
Russ Cox committed
237
			}
238
		}
239 240 241
		n++;
	
	skipped:
242 243
		waspanic = f->entry == (uintptr)runtime·sigpanic;

244
		// Do not unwind past the bottom of the stack.
245
		if(flr == nil)
246 247
			break;

248
		// Unwind to next frame.
249
		frame.fn = flr;
250 251 252 253
		frame.pc = frame.lr;
		frame.lr = 0;
		frame.sp = frame.fp;
		frame.fp = 0;
254
	}
255
	
256 257 258 259 260 261
	if(pcbuf == nil && callback == nil)
		n = nprint;
	
	return n;
}

262 263
void
runtime·printcreatedby(G *gp)
264
{
265
	int32 line;
266 267
	uintptr pc, tracepc;
	Func *f;
268
	String file;
269

Russ Cox's avatar
Russ Cox committed
270
	// Show what created goroutine, except main goroutine (goid 1).
271 272
	if((pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil &&
		runtime·showframe(f, gp) && gp->goid != 1) {
273
		runtime·printf("created by %s\n", runtime·funcname(f));
274 275
		tracepc = pc;	// back up to CALL instruction for funcline.
		if(pc > f->entry)
276 277
			tracepc -= PCQuantum;
		line = runtime·funcline(f, tracepc, &file);
278
		runtime·printf("\t%S:%d", file, line);
279 280
		if(pc > f->entry)
			runtime·printf(" +%p", (uintptr)(pc - f->entry));
Russ Cox's avatar
Russ Cox committed
281
		runtime·printf("\n");
282
	}
283
}
Russ Cox's avatar
Russ Cox committed
284 285

void
286
runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
Russ Cox's avatar
Russ Cox committed
287
{
288 289
	int32 n;

290 291
	USED(lr);

Russ Cox's avatar
Russ Cox committed
292 293
	if(gp->status == Gsyscall) {
		// Override signal registers if blocked in system call.
294 295
		pc = gp->syscallpc;
		sp = gp->syscallsp;
Russ Cox's avatar
Russ Cox committed
296
	}
297 298 299
	
	// Print traceback. By default, omits runtime frames.
	// If that means we print nothing at all, repeat forcing all frames printed.
300 301 302 303 304
	n = runtime·gentraceback(pc, sp, 0, gp, 0, nil, TracebackMaxFrames, nil, nil, false);
	if(n == 0)
		n = runtime·gentraceback(pc, sp, 0, gp, 0, nil, TracebackMaxFrames, nil, nil, true);
	if(n == TracebackMaxFrames)
		runtime·printf("...additional frames elided...\n");
305
	runtime·printcreatedby(gp);
Russ Cox's avatar
Russ Cox committed
306
}
Russ Cox's avatar
Russ Cox committed
307

Russ Cox's avatar
Russ Cox committed
308
int32
309
runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
Russ Cox's avatar
Russ Cox committed
310
{
311
	uintptr pc, sp;
Russ Cox's avatar
Russ Cox committed
312

313 314
	sp = runtime·getcallersp(&skip);
	pc = (uintptr)runtime·getcallerpc(&skip);
Russ Cox's avatar
Russ Cox committed
315

316
	return runtime·gentraceback(pc, sp, 0, g, skip, pcbuf, m, nil, nil, false);
Russ Cox's avatar
Russ Cox committed
317
}