diff options
| author | Russ Cox <rsc@golang.org> | 2010-03-23 17:01:17 -0700 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2010-03-23 17:01:17 -0700 |
| commit | 2b7d147f1a916f26df6ee15ed0d54c30c7bede43 (patch) | |
| tree | 975c81a35455346620a3ef101dacf2d6c7cb453a /src/pkg/runtime/amd64 | |
| parent | 32c39fa1b7dd8601addc0e7e80ce6004703834c6 (diff) | |
| download | go-2b7d147f1a916f26df6ee15ed0d54c30c7bede43.tar.xz | |
runtime: add Callers
cut copies of traceback from 6 to 1.
R=r
CC=golang-dev
https://golang.org/cl/703041
Diffstat (limited to 'src/pkg/runtime/amd64')
| -rw-r--r-- | src/pkg/runtime/amd64/traceback.c | 195 |
1 files changed, 83 insertions, 112 deletions
diff --git a/src/pkg/runtime/amd64/traceback.c b/src/pkg/runtime/amd64/traceback.c index 8fe23f32ee..37c06d092d 100644 --- a/src/pkg/runtime/amd64/traceback.c +++ b/src/pkg/runtime/amd64/traceback.c @@ -3,144 +3,115 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "malloc.h" -void -traceback(byte *pc0, byte *sp, G *g) +// This code is also used for the 386 tracebacks. +// Use uintptr for an appropriate word-sized integer. + +// Generic traceback. Handles runtime stack prints (pcbuf == nil) +// as well as the runtime.Callers function (pcbuf != nil). +// A little clunky to merge the two but avoids duplicating +// the code and all its subtlety. +static int32 +gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m) { + byte *p; + int32 i, n, iter; + uintptr pc, tracepc; Stktop *stk; - uint64 pc, tracepc; - int32 i, n; Func *f; - byte *p; - - pc = (uint64)pc0; + + 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 = *(uint64*)sp; - sp += 8; + pc = *(uintptr*)sp; + sp += sizeof(uintptr); } - + + n = 0; stk = (Stktop*)g->stackbase; - for(n=0; n<100; n++) { - if(pc == (uint64)·lessstack) { - // pop to earlier stack block - // printf("-- stack jump %p => %p\n", sp, stk->gobuf.sp); + for(iter = 0; iter < 100 && n < m; iter++) { // iter avoids looping forever + if(pc == (uintptr)·lessstack) { + // Hit top of stack segment. Unwind to next segment. pc = (uintptr)stk->gobuf.pc; sp = stk->gobuf.sp; stk = (Stktop*)stk->stackbase; + continue; } - p = (byte*)pc; - tracepc = pc; // used for line number, function - if(n > 0 && pc != (uint64)goexit) - tracepc--; // get to CALL instruction - f = findfunc(tracepc); - if(f == nil) { - // dangerous, but poke around to see if it is a closure - // ADDQ $xxx, SP; RET - if(p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) { - sp += *(uint32*)(p+3) + 8; - pc = *(uint64*)(sp - 8); - if(pc <= 0x1000) - return; + + if(pc <= 0x1000 || (f = findfunc(pc)) == nil) { + // Dangerous, but worthwhile: see if this is a closure: + // ADDQ $wwxxyyzz, SP; RET + // [48] 81 c4 zz yy xx ww c3 + // The 0x48 byte is only on amd64. + p = (byte*)pc; + if(mheap.min < p && p+8 < mheap.max && // pointer in allocated memory + (sizeof(uintptr) != 8 || *p++ == 0x48) && // skip 0x48 byte on amd64 + p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) { + sp += *(uint32*)(p+2); + pc = *(uintptr*)sp; + sp += sizeof(uintptr); continue; } - printf("%p unknown pc\n", pc); - return; + // Unknown pc; stop. + break; } - 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, tracepc)); - printf("\t%S(", f->name); - for(i = 0; i < f->args; i++) { - if(i != 0) - prints(", "); - ·printhex(((uint32*)sp)[i]); - if(i >= 4) { - prints(", ..."); - break; + // Found an actual function worth reporting. + if(skip > 0) + skip--; + else if(pcbuf != nil) + pcbuf[n++] = pc; + else { + // Print during crash. + // 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)); + tracepc = pc; // back up to CALL instruction for funcline. + if(n > 0 && pc > f->entry) + tracepc--; + printf(" %S:%d\n", f->src, funcline(f, tracepc)); + printf("\t%S(", f->name); + for(i = 0; i < f->args; i++) { + if(i != 0) + prints(", "); + ·printhex(((uintptr*)sp)[i]); + if(i >= 4) { + prints(", ..."); + break; + } } + prints(")\n"); + n++; } - prints(")\n"); - - pc = *(uintptr*)(sp-sizeof(uintptr)); - if(pc <= 0x1000) - return; + + if(f->frame < sizeof(uintptr)) // assembly functions lie + sp += sizeof(uintptr); + else + sp += f->frame; + pc = *((uintptr*)sp - 1); } - prints("...\n"); + return n; } -// func caller(n int) (pc uint64, file string, line int, ok bool) void -·Caller(int32 n, uint64 retpc, String retfile, int32 retline, bool retbool) +traceback(byte *pc0, byte *sp, G *g) { - uint64 pc; - byte *sp; - byte *p; - Stktop *stk; - Func *f; - - // our caller's pc, sp. - sp = (byte*)&n; - pc = *(uint64*)(sp-8); - 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)·lessstack) { - pc = (uintptr)stk->gobuf.pc; - sp = stk->gobuf.sp; - stk = (Stktop*)stk->stackbase; - } + gentraceback(pc0, sp, g, 0, nil, 100); +} - if(f->frame < sizeof(uintptr)) // assembly functions lie - sp += sizeof(uintptr); - else - sp += f->frame; +int32 +callers(int32 skip, uintptr *pcbuf, int32 m) +{ + byte *pc, *sp; - 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; - // ADDQ $xxx, SP; RET - if(pc > 0x1000 && p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) { - sp += *(uint32*)(p+3) + 8; - goto loop; - } - goto error; - } - } + // our caller's pc, sp. + sp = (byte*)&skip; + pc = *(byte**)(sp-sizeof(uintptr)); - retpc = pc; - retfile = f->src; - retline = funcline(f, pc-1); - retbool = true; - FLUSH(&retpc); - FLUSH(&retfile); - FLUSH(&retline); - FLUSH(&retbool); + return gentraceback(pc, sp, g, skip, pcbuf, m); } |
