github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/traceback_x86.c (about)

     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  // +build amd64 386
     6  
     7  #include "runtime.h"
     8  #include "arch_GOARCH.h"
     9  #include "malloc.h"
    10  
    11  void runtime·deferproc(void);
    12  void runtime·newproc(void);
    13  void runtime·newstack(void);
    14  void runtime·morestack(void);
    15  void runtime·sigpanic(void);
    16  
    17  // This code is also used for the 386 tracebacks.
    18  // Use uintptr for an appropriate word-sized integer.
    19  
    20  // Generic traceback.  Handles runtime stack prints (pcbuf == nil),
    21  // the runtime.Callers function (pcbuf != nil), as well as the garbage
    22  // collector (fn != nil).  A little clunky to merge the two but avoids
    23  // duplicating the code and all its subtlety.
    24  int32
    25  runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*fn)(Func*, byte*, byte*, void*), void *arg)
    26  {
    27  	int32 i, n, sawnewstack;
    28  	uintptr pc, lr, tracepc;
    29  	byte *fp;
    30  	Stktop *stk;
    31  	Func *f;
    32  	bool waspanic;
    33  
    34  	USED(lr0);
    35  	pc = (uintptr)pc0;
    36  	lr = 0;
    37  	fp = nil;
    38  	waspanic = false;
    39  	
    40  	// If the PC is goexit, the goroutine hasn't started yet.
    41  	if(pc0 == gp->sched.pc && sp == (byte*)gp->sched.sp && pc0 == (byte*)runtime·goexit && gp->fnstart != nil) {
    42  		fp = sp;
    43  		lr = pc;
    44  		pc = (uintptr)gp->fnstart->fn;
    45  	}
    46  	
    47  	// If the PC is zero, it's likely a nil function call.
    48  	// Start in the caller's frame.
    49  	if(pc == 0) {
    50  		pc = *(uintptr*)sp;
    51  		sp += sizeof(uintptr);
    52  	}
    53  
    54  	n = 0;
    55  	sawnewstack = 0;
    56  	stk = (Stktop*)gp->stackbase;
    57  	while(n < max) {
    58  		// Typically:
    59  		//	pc is the PC of the running function.
    60  		//	sp is the stack pointer at that program counter.
    61  		//	fp is the frame pointer (caller's stack pointer) at that program counter, or nil if unknown.
    62  		//	stk is the stack containing sp.
    63  		//	The caller's program counter is lr, unless lr is zero, in which case it is *(uintptr*)sp.
    64  	
    65  		if(pc == (uintptr)runtime·lessstack) {
    66  			// Hit top of stack segment.  Unwind to next segment.
    67  			pc = (uintptr)stk->gobuf.pc;
    68  			sp = (byte*)stk->gobuf.sp;
    69  			lr = 0;
    70  			fp = nil;
    71  			if(pcbuf == nil && fn == nil && runtime·showframe(nil, gp == m->curg))
    72  				runtime·printf("----- stack segment boundary -----\n");
    73  			stk = (Stktop*)stk->stackbase;
    74  			continue;
    75  		}
    76  		if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil) {
    77  			if(fn != nil)
    78  				runtime·throw("unknown pc");
    79  			break;
    80  		}
    81  
    82  		// Found an actual function.
    83  		if(fp == nil) {
    84  			fp = sp;
    85  			if(pc > f->entry && f->frame >= sizeof(uintptr))
    86  				fp += f->frame - sizeof(uintptr);
    87  			if(lr == 0)
    88  				lr = *(uintptr*)fp;
    89  			fp += sizeof(uintptr);
    90  		} else if(lr == 0)
    91  			lr = *(uintptr*)fp;
    92  
    93  		if(skip > 0)
    94  			skip--;
    95  		else if(pcbuf != nil)
    96  			pcbuf[n++] = pc;
    97  		else if(fn != nil)
    98  			(*fn)(f, (byte*)pc, sp, arg);
    99  		else {
   100  			if(runtime·showframe(f, gp == m->curg)) {
   101  				// Print during crash.
   102  				//	main(0x1, 0x2, 0x3)
   103  				//		/home/rsc/go/src/runtime/x.go:23 +0xf
   104  				//		
   105  				tracepc = pc;	// back up to CALL instruction for funcline.
   106  				if(n > 0 && pc > f->entry && !waspanic)
   107  					tracepc--;
   108  				if(m->throwing && gp == m->curg)
   109  					runtime·printf("[fp=%p] ", fp);
   110  				runtime·printf("%S(", f->name);
   111  				for(i = 0; i < f->args/sizeof(uintptr); i++) {
   112  					if(i != 0)
   113  						runtime·prints(", ");
   114  					runtime·printhex(((uintptr*)fp)[i]);
   115  					if(i >= 4) {
   116  						runtime·prints(", ...");
   117  						break;
   118  					}
   119  				}
   120  				runtime·prints(")\n");
   121  				runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
   122  				if(pc > f->entry)
   123  					runtime·printf(" +%p", (uintptr)(pc - f->entry));
   124  				runtime·printf("\n");
   125  			}
   126  			n++;
   127  		}
   128  		
   129  		waspanic = f->entry == (uintptr)runtime·sigpanic;
   130  
   131  		if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc)
   132  			fp += 2*sizeof(uintptr);
   133  
   134  		if(f->entry == (uintptr)runtime·newstack)
   135  			sawnewstack = 1;
   136  
   137  		if(pcbuf == nil && fn == nil && f->entry == (uintptr)runtime·morestack && gp == m->g0 && sawnewstack) {
   138  			// The fact that we saw newstack means that morestack
   139  			// has managed to record its information in m, so we can
   140  			// use it to keep unwinding the stack.
   141  			runtime·printf("----- morestack called from goroutine %D -----\n", m->curg->goid);
   142  			pc = (uintptr)m->morepc;
   143  			sp = (byte*)m->morebuf.sp - sizeof(void*);
   144  			lr = (uintptr)m->morebuf.pc;
   145  			fp = (byte*)m->morebuf.sp;
   146  			sawnewstack = 0;
   147  			gp = m->curg;
   148  			stk = (Stktop*)gp->stackbase;
   149  			continue;
   150  		}
   151  
   152  		if(pcbuf == nil && fn == nil && f->entry == (uintptr)runtime·lessstack && gp == m->g0) {
   153  			// Lessstack is running on scheduler stack.  Switch to original goroutine.
   154  			runtime·printf("----- lessstack called from goroutine %D -----\n", m->curg->goid);
   155  			gp = m->curg;
   156  			stk = (Stktop*)gp->stackbase;
   157  			sp = (byte*)stk->gobuf.sp;
   158  			pc = (uintptr)stk->gobuf.pc;
   159  			fp = nil;
   160  			lr = 0;
   161  			continue;
   162  		}
   163  
   164  		// Do not unwind past the bottom of the stack.
   165  		if(pc == (uintptr)runtime·goexit)
   166  			break;
   167  
   168  		// Unwind to next frame.
   169  		pc = lr;
   170  		lr = 0;
   171  		sp = fp;
   172  		fp = nil;
   173  	}
   174  	
   175  	// Show what created goroutine, except main goroutine (goid 1).
   176  	if(pcbuf == nil && fn == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil
   177  			&& runtime·showframe(f, gp == m->curg) && gp->goid != 1) {
   178  		runtime·printf("created by %S\n", f->name);
   179  		tracepc = pc;	// back up to CALL instruction for funcline.
   180  		if(n > 0 && pc > f->entry)
   181  			tracepc--;
   182  		runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
   183  		if(pc > f->entry)
   184  			runtime·printf(" +%p", (uintptr)(pc - f->entry));
   185  		runtime·printf("\n");
   186  	}
   187  		
   188  	return n;
   189  }
   190  
   191  void
   192  runtime·traceback(byte *pc0, byte *sp, byte*, G *gp)
   193  {
   194  	if(gp->status == Gsyscall) {
   195  		// Override signal registers if blocked in system call.
   196  		pc0 = gp->sched.pc;
   197  		sp = (byte*)gp->sched.sp;
   198  	}
   199  	runtime·gentraceback(pc0, sp, nil, gp, 0, nil, 100, nil, nil);
   200  }
   201  
   202  int32
   203  runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
   204  {
   205  	byte *pc, *sp;
   206  
   207  	// our caller's pc, sp.
   208  	sp = (byte*)&skip;
   209  	pc = runtime·getcallerpc(&skip);
   210  
   211  	return runtime·gentraceback(pc, sp, nil, g, skip, pcbuf, m, nil, nil);
   212  }