diff options
Diffstat (limited to 'src/pkg/runtime/386/traceback.c')
-rw-r--r-- | src/pkg/runtime/386/traceback.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/src/pkg/runtime/386/traceback.c b/src/pkg/runtime/386/traceback.c new file mode 100644 index 000000000..05724d9ac --- /dev/null +++ b/src/pkg/runtime/386/traceback.c @@ -0,0 +1,148 @@ +// 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. + +#include "runtime.h" + +// TODO(rsc): Move this into portable code, with calls to a +// machine-dependent isclosure() function. + +void +traceback(byte *pc0, byte *sp, G *g) +{ + Stktop *stk; + uintptr pc; + int32 i, n; + Func *f; + byte *p; + + pc = (uintptr)pc0; + + // If the PC is zero, it's likely a nil function call. + // Start in the caller's frame. + if(pc == 0) { + pc = *(uintptr*)sp; + sp += sizeof(uintptr); + } + + stk = (Stktop*)g->stackbase; + for(n=0; n<100; n++) { + while(pc == (uintptr)retfromnewstack) { + // pop to earlier stack block + sp = stk->oldsp; + stk = (Stktop*)stk->oldbase; + pc = *(uintptr*)(sp+sizeof(uintptr)); + sp += 2*sizeof(uintptr); // two irrelevant calls on stack: morestack plus its call + } + f = findfunc(pc); + if(f == nil) { + // dangerous, but poke around to see if it is a closure + p = (byte*)pc; + // ADDL $xxx, SP; RET + if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) { + sp += *(uint32*)(p+2) + 8; + pc = *(uintptr*)(sp - 8); + if(pc <= 0x1000) + return; + continue; + } + printf("%p unknown pc\n", pc); + return; + } + if(f->frame < sizeof(uintptr)) // assembly funcs say 0 but lie + sp += sizeof(uintptr); + else + sp += f->frame; + + // print this frame + // main+0xf /home/rsc/go/src/runtime/x.go:23 + // main(0x1, 0x2, 0x3) + printf("%S", f->name); + if(pc > f->entry) + printf("+%p", (uintptr)(pc - f->entry)); + printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr. + printf("\t%S(", f->name); + for(i = 0; i < f->args; i++) { + if(i != 0) + prints(", "); + sys·printhex(((uint32*)sp)[i]); + if(i >= 4) { + prints(", ..."); + break; + } + } + prints(")\n"); + + pc = *(uintptr*)(sp-sizeof(uintptr)); + if(pc <= 0x1000) + return; + } + prints("...\n"); +} + +// func caller(n int) (pc uintptr, file string, line int, ok bool) +void +runtime·Caller(int32 n, uintptr retpc, String retfile, int32 retline, bool retbool) +{ + uintptr pc; + byte *sp; + byte *p; + Stktop *stk; + Func *f; + + // our caller's pc, sp. + sp = (byte*)&n; + pc = *((uintptr*)sp - 1); + if((f = findfunc(pc)) == nil) { + error: + retpc = 0; + retline = 0; + retfile = emptystring; + retbool = false; + FLUSH(&retpc); + FLUSH(&retfile); + FLUSH(&retline); + FLUSH(&retbool); + return; + } + + // now unwind n levels + stk = (Stktop*)g->stackbase; + while(n-- > 0) { + while(pc == (uintptr)retfromnewstack) { + sp = stk->oldsp; + stk = (Stktop*)stk->oldbase; + pc = *((uintptr*)sp + 1); + sp += 2*sizeof(uintptr); + } + + if(f->frame < sizeof(uintptr)) // assembly functions lie + sp += sizeof(uintptr); + else + sp += f->frame; + + loop: + pc = *((uintptr*)sp - 1); + if(pc <= 0x1000 || (f = findfunc(pc)) == nil) { + // dangerous, but let's try this. + // see if it is a closure. + p = (byte*)pc; + // ADDL $xxx, SP; RET + if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) { + sp += *(uint32*)(p+2) + sizeof(uintptr); + goto loop; + } + goto error; + } + } + + retpc = pc; + retfile = f->src; + retline = funcline(f, pc-1); + retbool = true; + FLUSH(&retpc); + FLUSH(&retfile); + FLUSH(&retline); + FLUSH(&retbool); +} + |