| // 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); |
| } |