diff options
author | Michael Stapelberg <stapelberg@debian.org> | 2013-03-04 21:27:36 +0100 |
---|---|---|
committer | Michael Stapelberg <michael@stapelberg.de> | 2013-03-04 21:27:36 +0100 |
commit | 04b08da9af0c450d645ab7389d1467308cfc2db8 (patch) | |
tree | db247935fa4f2f94408edc3acd5d0d4f997aa0d8 /src/pkg/runtime/traceback_x86.c | |
parent | 917c5fb8ec48e22459d77e3849e6d388f93d3260 (diff) | |
download | golang-04b08da9af0c450d645ab7389d1467308cfc2db8.tar.gz |
Imported Upstream version 1.1~hg20130304upstream/1.1_hg20130304
Diffstat (limited to 'src/pkg/runtime/traceback_x86.c')
-rw-r--r-- | src/pkg/runtime/traceback_x86.c | 162 |
1 files changed, 31 insertions, 131 deletions
diff --git a/src/pkg/runtime/traceback_x86.c b/src/pkg/runtime/traceback_x86.c index be35bab00..72603ae8e 100644 --- a/src/pkg/runtime/traceback_x86.c +++ b/src/pkg/runtime/traceback_x86.c @@ -8,7 +8,6 @@ #include "arch_GOARCH.h" #include "malloc.h" -static uintptr isclosureentry(uintptr); void runtime·deferproc(void); void runtime·newproc(void); void runtime·newstack(void); @@ -23,9 +22,8 @@ void runtime·sigpanic(void); // A little clunky to merge the two but avoids duplicating // the code and all its subtlety. int32 -runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, int32 max) +runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max) { - byte *p; int32 i, n, iter, sawnewstack; uintptr pc, lr, tracepc; byte *fp; @@ -40,29 +38,22 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr waspanic = false; // If the PC is goexit, the goroutine hasn't started yet. - if(pc0 == g->sched.pc && sp == g->sched.sp && pc0 == (byte*)runtime·goexit) { + if(pc0 == gp->sched.pc && sp == (byte*)gp->sched.sp && pc0 == (byte*)runtime·goexit && gp->fnstart != nil) { fp = sp; lr = pc; - pc = (uintptr)g->entry; + pc = (uintptr)gp->fnstart->fn; } // If the PC is zero, it's likely a nil function call. // Start in the caller's frame. if(pc == 0) { - pc = lr; - lr = 0; - } - - // 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); } n = 0; sawnewstack = 0; - stk = (Stktop*)g->stackbase; + stk = (Stktop*)gp->stackbase; for(iter = 0; iter < 100 && n < max; iter++) { // iter avoids looping forever // Typically: // pc is the PC of the running function. @@ -74,41 +65,16 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr if(pc == (uintptr)runtime·lessstack) { // Hit top of stack segment. Unwind to next segment. pc = (uintptr)stk->gobuf.pc; - sp = stk->gobuf.sp; + sp = (byte*)stk->gobuf.sp; lr = 0; fp = nil; - if(pcbuf == nil) + if(pcbuf == nil && runtime·showframe(nil, gp == m->curg)) runtime·printf("----- stack segment boundary -----\n"); stk = (Stktop*)stk->stackbase; continue; } - if(pc <= 0x1000 || (f = runtime·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; - // We check p < p+8 to avoid wrapping and faulting if we lose track. - if(runtime·mheap.arena_start < p && p < p+8 && p+8 < runtime·mheap.arena_used && // 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); - lr = 0; - fp = nil; - continue; - } - - // Closure at top of stack, not yet started. - if(lr == (uintptr)runtime·goexit && (pc = isclosureentry(pc)) != 0) { - fp = sp; - continue; - } - - // Unknown pc: stop. + if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil) break; - } // Found an actual function. if(fp == nil) { @@ -126,7 +92,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr else if(pcbuf != nil) pcbuf[n++] = pc; else { - if(runtime·showframe(f)) { + if(runtime·showframe(f, gp == m->curg)) { // Print during crash. // main(0x1, 0x2, 0x3) // /home/rsc/go/src/runtime/x.go:23 +0xf @@ -134,8 +100,10 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr tracepc = pc; // back up to CALL instruction for funcline. if(n > 0 && pc > f->entry && !waspanic) tracepc--; + if(m->throwing && gp == m->curg) + runtime·printf("[fp=%p] ", fp); runtime·printf("%S(", f->name); - for(i = 0; i < f->args; i++) { + for(i = 0; i < f->args/sizeof(uintptr); i++) { if(i != 0) runtime·prints(", "); runtime·printhex(((uintptr*)fp)[i]); @@ -161,27 +129,27 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr if(f->entry == (uintptr)runtime·newstack) sawnewstack = 1; - if(pcbuf == nil && f->entry == (uintptr)runtime·morestack && g == m->g0 && sawnewstack) { + if(pcbuf == nil && f->entry == (uintptr)runtime·morestack && gp == m->g0 && sawnewstack) { // The fact that we saw newstack means that morestack // has managed to record its information in m, so we can // use it to keep unwinding the stack. - runtime·printf("----- morestack called from goroutine %d -----\n", m->curg->goid); + runtime·printf("----- morestack called from goroutine %D -----\n", m->curg->goid); pc = (uintptr)m->morepc; - sp = m->morebuf.sp - sizeof(void*); + sp = (byte*)m->morebuf.sp - sizeof(void*); lr = (uintptr)m->morebuf.pc; - fp = m->morebuf.sp; + fp = (byte*)m->morebuf.sp; sawnewstack = 0; - g = m->curg; - stk = (Stktop*)g->stackbase; + gp = m->curg; + stk = (Stktop*)gp->stackbase; continue; } - if(pcbuf == nil && f->entry == (uintptr)runtime·lessstack && g == m->g0) { + if(pcbuf == nil && f->entry == (uintptr)runtime·lessstack && gp == m->g0) { // Lessstack is running on scheduler stack. Switch to original goroutine. - runtime·printf("----- lessstack called from goroutine %d -----\n", m->curg->goid); - g = m->curg; - stk = (Stktop*)g->stackbase; - sp = stk->gobuf.sp; + runtime·printf("----- lessstack called from goroutine %D -----\n", m->curg->goid); + gp = m->curg; + stk = (Stktop*)gp->stackbase; + sp = (byte*)stk->gobuf.sp; pc = (uintptr)stk->gobuf.pc; fp = nil; lr = 0; @@ -196,7 +164,8 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr } // Show what created goroutine, except main goroutine (goid 1). - if(pcbuf == nil && (pc = g->gopc) != 0 && (f = runtime·findfunc(pc)) != nil && g->goid != 1) { + if(pcbuf == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil + && runtime·showframe(f, gp == m->curg) && gp->goid != 1) { runtime·printf("created by %S\n", f->name); tracepc = pc; // back up to CALL instruction for funcline. if(n > 0 && pc > f->entry) @@ -211,9 +180,14 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr } void -runtime·traceback(byte *pc0, byte *sp, byte*, G *g) +runtime·traceback(byte *pc0, byte *sp, byte*, G *gp) { - runtime·gentraceback(pc0, sp, nil, g, 0, nil, 100); + if(gp->status == Gsyscall) { + // Override signal registers if blocked in system call. + pc0 = gp->sched.pc; + sp = (byte*)gp->sched.sp; + } + runtime·gentraceback(pc0, sp, nil, gp, 0, nil, 100); } int32 @@ -227,77 +201,3 @@ runtime·callers(int32 skip, uintptr *pcbuf, int32 m) return runtime·gentraceback(pc, sp, nil, g, skip, pcbuf, m); } - -static uintptr -isclosureentry(uintptr pc) -{ - byte *p; - int32 i, siz; - - p = (byte*)pc; - if(p < runtime·mheap.arena_start || p+32 > runtime·mheap.arena_used) - return 0; - - if(*p == 0xe8) { - // CALL fn - return pc+5+*(int32*)(p+1); - } - - if(sizeof(uintptr) == 8 && p[0] == 0x48 && p[1] == 0xb9 && p[10] == 0xff && p[11] == 0xd1) { - // MOVQ $fn, CX; CALL *CX - return *(uintptr*)(p+2); - } - - // SUBQ $siz, SP - if((sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0x81 || *p++ != 0xec) - return 0; - siz = *(uint32*)p; - p += 4; - - // MOVQ $q, SI - if((sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0xbe) - return 0; - p += sizeof(uintptr); - - // MOVQ SP, DI - if((sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0x89 || *p++ != 0xe7) - return 0; - - // CLD on 32-bit - if(sizeof(uintptr) == 4 && *p++ != 0xfc) - return 0; - - if(siz <= 4*sizeof(uintptr)) { - // MOVSQ... - for(i=0; i<siz; i+=sizeof(uintptr)) - if((sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0xa5) - return 0; - } else { - // MOVQ $(siz/8), CX [32-bit immediate siz/8] - if((sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0xc7 || *p++ != 0xc1) - return 0; - p += 4; - - // REP MOVSQ - if(*p++ != 0xf3 || (sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0xa5) - return 0; - } - - // CALL fn - if(*p == 0xe8) { - p++; - return (uintptr)p+4 + *(int32*)p; - } - - // MOVQ $fn, CX; CALL *CX - if(sizeof(uintptr) != 8 || *p++ != 0x48 || *p++ != 0xb9) - return 0; - - pc = *(uintptr*)p; - p += 8; - - if(*p++ != 0xff || *p != 0xd1) - return 0; - - return pc; -} |