| // 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(", "); | |
| // runtime·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); | |
| } |