diff options
| author | Russ Cox <rsc@golang.org> | 2013-07-17 12:47:18 -0400 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2013-07-17 12:47:18 -0400 |
| commit | a83748596c009db47bcd35a69531e485e2c7f924 (patch) | |
| tree | 2cd2f1b4cb878e05dde91af1b12d2929937f9203 /src/pkg/runtime/traceback_arm.c | |
| parent | 7b7dac5e235145b08644e2fe4864b3d1fb8e2d5a (diff) | |
| download | go-a83748596c009db47bcd35a69531e485e2c7f924.tar.xz | |
runtime: use new frame argument size information
With this CL, I believe the runtime always knows
the frame size during the gc walk. There is no fallback
to "assume entire stack frame of caller" anymore.
R=golang-dev, khr, cshapiro, dvyukov
CC=golang-dev
https://golang.org/cl/11374044
Diffstat (limited to 'src/pkg/runtime/traceback_arm.c')
| -rw-r--r-- | src/pkg/runtime/traceback_arm.c | 96 |
1 files changed, 57 insertions, 39 deletions
diff --git a/src/pkg/runtime/traceback_arm.c b/src/pkg/runtime/traceback_arm.c index e5a475f80f..6cd924da0d 100644 --- a/src/pkg/runtime/traceback_arm.c +++ b/src/pkg/runtime/traceback_arm.c @@ -6,30 +6,21 @@ #include "arch_GOARCH.h" #include "malloc.h" -void runtime·deferproc(void); -void runtime·newproc(void); -void runtime·morestack(void); void runtime·sigpanic(void); -void _div(void); -void _mod(void); -void _divu(void); -void _modu(void); static String unknown = { (uint8*)"?", 1 }; int32 runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v, bool printall) { - int32 i, n, nprint, skip0, line; + int32 i, n, nprint, line; uintptr x, tracepc; bool waspanic, printing; - Func *f, *f2; + Func *f, *flr; Stkframe frame; Stktop *stk; String file; - skip0 = skip; - nprint = 0; runtime·memclr((byte*)&frame, sizeof frame); frame.pc = pc0; @@ -44,6 +35,16 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, frame.pc = frame.lr; frame.lr = 0; } + + f = runtime·findfunc(frame.pc); + if(f == nil) { + if(callback != nil) { + runtime·printf("runtime: unknown pc %p\n", frame.pc); + runtime·throw("unknown pc"); + } + return 0; + } + frame.fn = f; n = 0; stk = (Stktop*)gp->stackbase; @@ -64,41 +65,57 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, if(printing && runtime·showframe(nil, gp)) runtime·printf("----- stack segment boundary -----\n"); stk = (Stktop*)stk->stackbase; - continue; - } - - if(frame.pc <= 0x1000 || (frame.fn = f = runtime·findfunc(frame.pc)) == nil) { - if(callback != nil) { - runtime·printf("runtime: unknown pc %p at frame %d\n", frame.pc, skip0-skip+n); - runtime·throw("invalid stack"); + + f = runtime·findfunc(frame.pc); + if(f == nil) { + runtime·printf("runtime: unknown pc %p after stack split\n", frame.pc); + runtime·throw("unknown pc"); } - break; + frame.fn = f; + continue; } + f = frame.fn; // Found an actual function. // Derive frame pointer and link register. - if(frame.lr == 0) - frame.lr = *(uintptr*)frame.sp; if(frame.fp == 0) frame.fp = frame.sp + runtime·funcspdelta(f, frame.pc); - + if(runtime·topofstack(f)) { + frame.lr = 0; + flr = nil; + } else { + if(frame.lr == 0) + frame.lr = *(uintptr*)frame.sp; + flr = runtime·findfunc(frame.lr); + if(flr == nil) { + runtime·printf("runtime: unexpected return pc for %S called from %p", *f->name, frame.lr); + runtime·throw("unknown caller pc"); + } + } + // Derive size of arguments. - frame.argp = (byte*)frame.fp + sizeof(uintptr); - frame.arglen = 0; - if(f->args != ArgsSizeUnknown) - frame.arglen = f->args; - else if(runtime·haszeroargs(f->entry)) - frame.arglen = 0; - else if(frame.lr == (uintptr)runtime·lessstack) - frame.arglen = stk->argsize; - else if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc) - frame.arglen = 3*sizeof(uintptr) + *(int32*)frame.argp; - else if((f2 = runtime·findfunc(frame.lr)) != nil && f2->frame >= sizeof(uintptr)) - frame.arglen = f2->frame; // conservative overestimate - else { - runtime·printf("runtime: unknown argument frame size for %S\n", *f->name); - if(!printing) - runtime·throw("invalid stack"); + // Most functions have a fixed-size argument block, + // so we can use metadata about the function f. + // Not all, though: there are some variadic functions + // in package runtime, and for those we use call-specific + // metadata recorded by f's caller. + if(callback != nil || printing) { + frame.argp = (byte*)frame.fp + sizeof(uintptr); + if(f->args != ArgsSizeUnknown) + frame.arglen = f->args; + else if(flr == nil) + frame.arglen = 0; + else if(frame.lr == (uintptr)runtime·lessstack) + frame.arglen = stk->argsize; + else if((i = runtime·funcarglen(flr, frame.lr)) >= 0) + frame.arglen = i; + else { + runtime·printf("runtime: unknown argument frame size for %S called from %p [%S]\n", + *f->name, frame.lr, flr ? *flr->name : unknown); + if(!printing) + runtime·throw("invalid stack"); + frame.arglen = 0; + } } // Derive location and size of local variables. @@ -165,11 +182,12 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, waspanic = f->entry == (uintptr)runtime·sigpanic; // Do not unwind past the bottom of the stack. - if(f->entry == (uintptr)runtime·goexit || f->entry == (uintptr)runtime·mstart || f->entry == (uintptr)runtime·mcall || f->entry == (uintptr)_rt0_go) + if(flr == nil) break; // Unwind to next frame. frame.pc = frame.lr; + frame.fn = flr; frame.lr = 0; frame.sp = frame.fp; frame.fp = 0; |
