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