traceback_x86.c 14.1 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 17
void runtime·newproc(void);
void runtime·deferproc(void);
18

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

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

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

Russ Cox's avatar
Russ Cox committed
43
	USED(lr0);
44
	
45 46
	gotraceback = runtime·gotraceback(nil);
	
47 48 49 50 51 52 53 54 55
	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;
		}
	}
56

57
	nprint = 0;
58 59 60
	runtime·memclr((byte*)&frame, sizeof frame);
	frame.pc = pc0;
	frame.sp = sp0;
61
	waspanic = false;
62
	wasnewproc = false;
63
	printing = pcbuf==nil && callback==nil;
64 65 66 67 68 69 70 71
	panic = gp->panic;
	defer = gp->defer;

	while(defer != nil && defer->argp == NoArgs)
		defer = defer->link;	
	while(panic != nil && panic->defer == nil)
		panic = panic->link;

Russ Cox's avatar
Russ Cox committed
72 73
	// If the PC is zero, it's likely a nil function call.
	// Start in the caller's frame.
74 75
	if(frame.pc == 0) {
		frame.pc = *(uintptr*)frame.sp;
Dave Cheney's avatar
Dave Cheney committed
76
		frame.sp += sizeof(uintreg);
77
	}
78 79 80 81 82 83 84 85 86 87
	
	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;
88

Russ Cox's avatar
Russ Cox committed
89
	n = 0;
90
	stk = (Stktop*)gp->stackbase;
91
	while(n < max) {
92 93 94 95 96 97 98
		// 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.
	
99
		if(frame.pc == (uintptr)runtime·lessstack) {
Russ Cox's avatar
Russ Cox committed
100
			// Hit top of stack segment.  Unwind to next segment.
101 102 103 104
			frame.pc = stk->gobuf.pc;
			frame.sp = stk->gobuf.sp;
			frame.lr = 0;
			frame.fp = 0;
105
			frame.fn = nil;
106
			if(printing && runtime·showframe(nil, gp))
107
				runtime·printf("----- stack segment boundary -----\n");
108
			stk = (Stktop*)stk->stackbase;
109 110 111 112

			f = runtime·findfunc(frame.pc);
			if(f == nil) {
				runtime·printf("runtime: unknown pc %p after stack split\n", frame.pc);
113 114
				if(callback != nil)
					runtime·throw("unknown pc");
115
			}
116 117
			frame.fn = f;
			continue;
118
		}
Russ Cox's avatar
Russ Cox committed
119
		
120
		f = frame.fn;
121

Russ Cox's avatar
Russ Cox committed
122 123 124 125 126 127 128 129 130 131 132 133
#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) {
134
				frame.continpc = frame.pc;
Russ Cox's avatar
Russ Cox committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
				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

164
		// Found an actual function.
165 166
		// Derive frame pointer and link register.
		if(frame.fp == 0) {
167
			frame.fp = frame.sp + runtime·funcspdelta(f, frame.pc);
Dave Cheney's avatar
Dave Cheney committed
168
			frame.fp += sizeof(uintreg); // caller PC
169
		}
170 171 172 173 174
		if(runtime·topofstack(f)) {
			frame.lr = 0;
			flr = nil;
		} else {
			if(frame.lr == 0)
Dave Cheney's avatar
Dave Cheney committed
175
				frame.lr = ((uintreg*)frame.fp)[-1];
176 177
			flr = runtime·findfunc(frame.lr);
			if(flr == nil) {
178 179 180
				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");
181 182
			}
		}
183
		
Dave Cheney's avatar
Dave Cheney committed
184
		frame.varp = (byte*)frame.fp - sizeof(uintreg);
185 186

		// Derive size of arguments.
187 188 189
		// 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
190
		// in package runtime and reflect, and for those we use call-specific
191 192 193 194 195 196 197 198 199 200 201 202
		// 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 {
203 204
				runtime·printf("runtime: unknown argument frame size for %s called from %p [%s]\n",
					runtime·funcname(f), frame.lr, flr ? runtime·funcname(flr) : "?");
205
				if(callback != nil)
206 207 208
					runtime·throw("invalid stack");
				frame.arglen = 0;
			}
209
		}
210 211 212 213 214 215 216
		
		// Determine function SP where deferproc would find its arguments.
		// On x86 that's just the standard bottom-of-stack, so SP exactly.
		// If the previous frame was a direct call to newproc/deferproc, however,
		// the SP is two words lower than normal.
		sparg = frame.sp;
		if(wasnewproc)
217
			sparg += 2*sizeof(uintptr);
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243

		// Determine frame's 'continuation PC', where it can continue.
		// Normally this is the return address on the stack, but if sigpanic
		// is immediately below this function on the stack, then the frame
		// stopped executing due to a trap, and frame.pc is probably not
		// a safe point for looking up liveness information. In this panicking case,
		// the function either doesn't return at all (if it has no defers or if the
		// defers do not recover) or it returns from one of the calls to 
		// deferproc a second time (if the corresponding deferred func recovers).
		// It suffices to assume that the most recent deferproc is the one that
		// returns; everything live at earlier deferprocs is still live at that one.
		frame.continpc = frame.pc;
		if(waspanic) {
			if(panic != nil && panic->defer->argp == (byte*)sparg)
				frame.continpc = (uintptr)panic->defer->pc;
			else if(defer != nil && defer->argp == (byte*)sparg)
				frame.continpc = (uintptr)defer->pc;
			else
				frame.continpc = 0;
		}

		// Unwind our local panic & defer stacks past this frame.
		while(panic != nil && (panic->defer == nil || panic->defer->argp == (byte*)sparg || panic->defer->argp == NoArgs))
			panic = panic->link;
		while(defer != nil && (defer->argp == (byte*)sparg || defer->argp == NoArgs))
			defer = defer->link;	
244 245 246 247 248 249 250 251

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

		if(pcbuf != nil)
			pcbuf[n] = frame.pc;
Keith Randall's avatar
Keith Randall committed
252 253 254 255
		if(callback != nil) {
			if(!callback(&frame, v))
				return n;
		}
256
		if(printing) {
257
			if(printall || runtime·showframe(f, gp)) {
Russ Cox's avatar
Russ Cox committed
258 259 260 261
				// Print during crash.
				//	main(0x1, 0x2, 0x3)
				//		/home/rsc/go/src/runtime/x.go:23 +0xf
				//		
262 263
				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
264
					tracepc--;
265
				runtime·printf("%s(", runtime·funcname(f));
266
				for(i = 0; i < frame.arglen/sizeof(uintptr); i++) {
267
					if(i >= 10) {
Russ Cox's avatar
Russ Cox committed
268 269 270
						runtime·prints(", ...");
						break;
					}
271 272 273
					if(i != 0)
						runtime·prints(", ");
					runtime·printhex(((uintptr*)frame.argp)[i]);
Russ Cox's avatar
Russ Cox committed
274
				}
Russ Cox's avatar
Russ Cox committed
275
				runtime·prints(")\n");
276 277
				line = runtime·funcline(f, tracepc, &file);
				runtime·printf("\t%S:%d", file, line);
278 279
				if(frame.pc > f->entry)
					runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
280
				if(g->m->throwing > 0 && gp == g->m->curg || gotraceback >= 2)
281
					runtime·printf(" fp=%p sp=%p", frame.fp, frame.sp);
Russ Cox's avatar
Russ Cox committed
282
				runtime·printf("\n");
283
				nprint++;
Russ Cox's avatar
Russ Cox committed
284
			}
285
		}
286 287 288
		n++;
	
	skipped:
289
		waspanic = f->entry == (uintptr)runtime·sigpanic;
290
		wasnewproc = f->entry == (uintptr)runtime·newproc || f->entry == (uintptr)runtime·deferproc;
291

292
		// Do not unwind past the bottom of the stack.
293
		if(flr == nil)
294 295
			break;

296
		// Unwind to next frame.
297
		frame.fn = flr;
298 299 300 301
		frame.pc = frame.lr;
		frame.lr = 0;
		frame.sp = frame.fp;
		frame.fp = 0;
302
	}
303
	
304 305
	if(pcbuf == nil && callback == nil)
		n = nprint;
306

307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
	// If callback != nil, we're being called to gather stack information during
	// garbage collection or stack growth. In that context, require that we used
	// up the entire defer stack. If not, then there is a bug somewhere and the
	// garbage collection or stack growth may not have seen the correct picture
	// of the stack. Crash now instead of silently executing the garbage collection
	// or stack copy incorrectly and setting up for a mysterious crash later.
	//
	// Note that panic != nil is okay here: there can be leftover panics,
	// because the defers on the panic stack do not nest in frame order as
	// they do on the defer stack. If you have:
	//
	//	frame 1 defers d1
	//	frame 2 defers d2
	//	frame 3 defers d3
	//	frame 4 panics
	//	frame 4's panic starts running defers
	//	frame 5, running d3, defers d4
	//	frame 5 panics
	//	frame 5's panic starts running defers
	//	frame 6, running d4, garbage collects
	//	frame 6, running d2, garbage collects
	//
	// During the execution of d4, the panic stack is d4 -> d3, which
	// is nested properly, and we'll treat frame 3 as resumable, because we
	// can find d3. (And in fact frame 3 is resumable. If d4 recovers
	// and frame 5 continues running, d3, d3 can recover and we'll
	// resume execution in (returning from) frame 3.)
	//
	// During the execution of d2, however, the panic stack is d2 -> d3,
	// which is inverted. The scan will match d2 to frame 2 but having
	// d2 on the stack until then means it will not match d3 to frame 3.
	// This is okay: if we're running d2, then all the defers after d2 have
	// completed and their corresponding frames are dead. Not finding d3
	// for frame 3 means we'll set frame 3's continpc == 0, which is correct
	// (frame 3 is dead). At the end of the walk the panic stack can thus
	// contain defers (d3 in this case) for dead frames. The inversion here
	// always indicates a dead frame, and the effect of the inversion on the
	// scan is to hide those dead frames, so the scan is still okay:
	// what's left on the panic stack are exactly (and only) the dead frames.
	//
	// We require callback != nil here because only when callback != nil
	// do we know that gentraceback is being called in a "must be correct"
	// context as opposed to a "best effort" context. The tracebacks with
	// callbacks only happen when everything is stopped nicely.
	// At other times, such as when gathering a stack for a profiling signal
	// or when printing a traceback during a crash, everything may not be
	// stopped nicely, and the stack walk may not be able to complete.
	// It's okay in those situations not to use up the entire defer stack:
	// incomplete information then is still better than nothing.
	if(callback != nil && n < max && defer != nil) {
357 358 359 360
		if(defer != nil)
			runtime·printf("runtime: g%D: leftover defer argp=%p pc=%p\n", gp->goid, defer->argp, defer->pc);
		if(panic != nil)
			runtime·printf("runtime: g%D: leftover panic argp=%p pc=%p\n", gp->goid, panic->defer->argp, panic->defer->pc);
361 362 363 364 365 366 367 368
		for(defer = gp->defer; defer != nil; defer = defer->link)
			runtime·printf("\tdefer %p argp=%p pc=%p\n", defer, defer->argp, defer->pc);
		for(panic = gp->panic; panic != nil; panic = panic->link) {
			runtime·printf("\tpanic %p defer %p", panic, panic->defer);
			if(panic->defer != nil)
				runtime·printf(" argp=%p pc=%p", panic->defer->argp, panic->defer->pc);
			runtime·printf("\n");
		}
369 370 371
		runtime·throw("traceback has leftover defers or panics");
	}

372 373 374
	return n;
}

375 376
void
runtime·printcreatedby(G *gp)
377
{
378
	int32 line;
379 380
	uintptr pc, tracepc;
	Func *f;
381
	String file;
382

Russ Cox's avatar
Russ Cox committed
383
	// Show what created goroutine, except main goroutine (goid 1).
384 385
	if((pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil &&
		runtime·showframe(f, gp) && gp->goid != 1) {
386
		runtime·printf("created by %s\n", runtime·funcname(f));
387 388
		tracepc = pc;	// back up to CALL instruction for funcline.
		if(pc > f->entry)
389 390
			tracepc -= PCQuantum;
		line = runtime·funcline(f, tracepc, &file);
391
		runtime·printf("\t%S:%d", file, line);
392 393
		if(pc > f->entry)
			runtime·printf(" +%p", (uintptr)(pc - f->entry));
Russ Cox's avatar
Russ Cox committed
394
		runtime·printf("\n");
395
	}
396
}
Russ Cox's avatar
Russ Cox committed
397 398

void
399
runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
Russ Cox's avatar
Russ Cox committed
400
{
401 402
	int32 n;

403 404
	USED(lr);

Russ Cox's avatar
Russ Cox committed
405 406
	if(gp->status == Gsyscall) {
		// Override signal registers if blocked in system call.
407 408
		pc = gp->syscallpc;
		sp = gp->syscallsp;
Russ Cox's avatar
Russ Cox committed
409
	}
410 411 412
	
	// Print traceback. By default, omits runtime frames.
	// If that means we print nothing at all, repeat forcing all frames printed.
413 414 415 416 417
	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");
418
	runtime·printcreatedby(gp);
Russ Cox's avatar
Russ Cox committed
419
}
Russ Cox's avatar
Russ Cox committed
420

Russ Cox's avatar
Russ Cox committed
421
int32
422
runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
Russ Cox's avatar
Russ Cox committed
423
{
424
	uintptr pc, sp;
Russ Cox's avatar
Russ Cox committed
425

426 427
	sp = runtime·getcallersp(&skip);
	pc = (uintptr)runtime·getcallerpc(&skip);
Russ Cox's avatar
Russ Cox committed
428

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