Commit 81221f51 authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

runtime: dump the full stack of a throwing goroutine

Useful for debugging of runtime bugs.
+ Do not print "stack segment boundary" unless GOTRACEBACK>1.
+ Do not traceback system goroutines unless GOTRACEBACK>1.

R=rsc, minux.ma
CC=golang-dev
https://golang.org/cl/7098050
parent 6c035469
...@@ -454,6 +454,8 @@ runtime·throwinit(void) ...@@ -454,6 +454,8 @@ runtime·throwinit(void)
void void
runtime·throw(int8 *s) runtime·throw(int8 *s)
{ {
if(m->throwing == 0)
m->throwing = 1;
runtime·startpanic(); runtime·startpanic();
runtime·printf("fatal error: %s\n", s); runtime·printf("fatal error: %s\n", s);
runtime·dopanic(0); runtime·dopanic(0);
......
...@@ -242,6 +242,7 @@ runtime·main(void) ...@@ -242,6 +242,7 @@ runtime·main(void)
setmcpumax(runtime·gomaxprocs); setmcpumax(runtime·gomaxprocs);
runtime·sched.init = true; runtime·sched.init = true;
scvg = runtime·newproc1((byte*)runtime·MHeap_Scavenger, nil, 0, 0, runtime·main); scvg = runtime·newproc1((byte*)runtime·MHeap_Scavenger, nil, 0, 0, runtime·main);
scvg->issystem = true;
main·init(); main·init();
runtime·sched.init = false; runtime·sched.init = false;
if(!runtime·sched.lockmain) if(!runtime·sched.lockmain)
...@@ -325,10 +326,14 @@ void ...@@ -325,10 +326,14 @@ void
runtime·tracebackothers(G *me) runtime·tracebackothers(G *me)
{ {
G *gp; G *gp;
int32 traceback;
traceback = runtime·gotraceback();
for(gp = runtime·allg; gp != nil; gp = gp->alllink) { for(gp = runtime·allg; gp != nil; gp = gp->alllink) {
if(gp == me || gp->status == Gdead) if(gp == me || gp->status == Gdead)
continue; continue;
if(gp->issystem && traceback < 2)
continue;
runtime·printf("\n"); runtime·printf("\n");
runtime·goroutineheader(gp); runtime·goroutineheader(gp);
runtime·traceback(gp->sched.pc, (byte*)gp->sched.sp, 0, gp); runtime·traceback(gp->sched.pc, (byte*)gp->sched.sp, 0, gp);
...@@ -624,6 +629,7 @@ top: ...@@ -624,6 +629,7 @@ top:
if((scvg == nil && runtime·sched.grunning == 0) || if((scvg == nil && runtime·sched.grunning == 0) ||
(scvg != nil && runtime·sched.grunning == 1 && runtime·sched.gwait == 0 && (scvg != nil && runtime·sched.grunning == 1 && runtime·sched.gwait == 0 &&
(scvg->status == Grunning || scvg->status == Gsyscall))) { (scvg->status == Grunning || scvg->status == Gsyscall))) {
m->throwing = -1; // do not dump full stacks
runtime·throw("all goroutines are asleep - deadlock!"); runtime·throw("all goroutines are asleep - deadlock!");
} }
......
...@@ -219,6 +219,7 @@ struct G ...@@ -219,6 +219,7 @@ struct G
G* schedlink; G* schedlink;
bool readyonstop; bool readyonstop;
bool ispanic; bool ispanic;
bool issystem;
int8 raceignore; // ignore race detection events int8 raceignore; // ignore race detection events
M* m; // for debuggers, but offset not hard-coded M* m; // for debuggers, but offset not hard-coded
M* lockedm; M* lockedm;
...@@ -252,6 +253,7 @@ struct M ...@@ -252,6 +253,7 @@ struct M
G* curg; // current running goroutine G* curg; // current running goroutine
int32 id; int32 id;
int32 mallocing; int32 mallocing;
int32 throwing;
int32 gcing; int32 gcing;
int32 locks; int32 locks;
int32 nomemprof; int32 nomemprof;
...@@ -865,7 +867,7 @@ Hmap* runtime·makemap_c(MapType*, int64); ...@@ -865,7 +867,7 @@ Hmap* runtime·makemap_c(MapType*, int64);
Hchan* runtime·makechan_c(ChanType*, int64); Hchan* runtime·makechan_c(ChanType*, int64);
void runtime·chansend(ChanType*, Hchan*, byte*, bool*, void*); void runtime·chansend(ChanType*, Hchan*, byte*, bool*, void*);
void runtime·chanrecv(ChanType*, Hchan*, byte*, bool*, bool*); void runtime·chanrecv(ChanType*, Hchan*, byte*, bool*, bool*);
bool runtime·showframe(Func*); bool runtime·showframe(Func*, bool);
void runtime·ifaceE2I(InterfaceType*, Eface, Iface*); void runtime·ifaceE2I(InterfaceType*, Eface, Iface*);
......
...@@ -559,11 +559,13 @@ contains(String s, int8 *p) ...@@ -559,11 +559,13 @@ contains(String s, int8 *p)
} }
bool bool
runtime·showframe(Func *f) runtime·showframe(Func *f, bool current)
{ {
static int32 traceback = -1; static int32 traceback = -1;
if(current && m->throwing > 0)
return 1;
if(traceback < 0) if(traceback < 0)
traceback = runtime·gotraceback(); traceback = runtime·gotraceback();
return traceback > 1 || contains(f->name, ".") && !hasprefix(f->name, "runtime."); return traceback > 1 || f != nil && contains(f->name, ".") && !hasprefix(f->name, "runtime.");
} }
...@@ -108,8 +108,10 @@ addtimer(Timer *t) ...@@ -108,8 +108,10 @@ addtimer(Timer *t)
runtime·ready(timers.timerproc); runtime·ready(timers.timerproc);
} }
} }
if(timers.timerproc == nil) if(timers.timerproc == nil) {
timers.timerproc = runtime·newproc1((byte*)timerproc, nil, 0, 0, addtimer); timers.timerproc = runtime·newproc1((byte*)timerproc, nil, 0, 0, addtimer);
timers.timerproc->issystem = true;
}
} }
// Delete timer t from the heap. // Delete timer t from the heap.
......
...@@ -60,7 +60,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -60,7 +60,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
sp = (byte*)stk->gobuf.sp; sp = (byte*)stk->gobuf.sp;
lr = 0; lr = 0;
fp = nil; fp = nil;
if(pcbuf == nil) if(pcbuf == nil && runtime·showframe(nil, gp == m->curg))
runtime·printf("----- stack segment boundary -----\n"); runtime·printf("----- stack segment boundary -----\n");
stk = (Stktop*)stk->stackbase; stk = (Stktop*)stk->stackbase;
continue; continue;
...@@ -118,7 +118,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -118,7 +118,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
else if(pcbuf != nil) else if(pcbuf != nil)
pcbuf[n++] = pc; pcbuf[n++] = pc;
else { else {
if(runtime·showframe(f)) { if(runtime·showframe(f, gp == m->curg)) {
// Print during crash. // Print during crash.
// main(0x1, 0x2, 0x3) // main(0x1, 0x2, 0x3)
// /home/rsc/go/src/runtime/x.go:23 +0xf // /home/rsc/go/src/runtime/x.go:23 +0xf
...@@ -184,7 +184,8 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -184,7 +184,8 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
sp += 12; sp += 12;
} }
if(pcbuf == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil && gp->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); runtime·printf("created by %S\n", f->name);
tracepc = pc; // back up to CALL instruction for funcline. tracepc = pc; // back up to CALL instruction for funcline.
if(n > 0 && pc > f->entry) if(n > 0 && pc > f->entry)
......
...@@ -77,7 +77,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -77,7 +77,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
sp = (byte*)stk->gobuf.sp; sp = (byte*)stk->gobuf.sp;
lr = 0; lr = 0;
fp = nil; fp = nil;
if(pcbuf == nil) if(pcbuf == nil && runtime·showframe(nil, gp == m->curg))
runtime·printf("----- stack segment boundary -----\n"); runtime·printf("----- stack segment boundary -----\n");
stk = (Stktop*)stk->stackbase; stk = (Stktop*)stk->stackbase;
continue; continue;
...@@ -126,7 +126,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -126,7 +126,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
else if(pcbuf != nil) else if(pcbuf != nil)
pcbuf[n++] = pc; pcbuf[n++] = pc;
else { else {
if(runtime·showframe(f)) { if(runtime·showframe(f, gp == m->curg)) {
// Print during crash. // Print during crash.
// main(0x1, 0x2, 0x3) // main(0x1, 0x2, 0x3)
// /home/rsc/go/src/runtime/x.go:23 +0xf // /home/rsc/go/src/runtime/x.go:23 +0xf
...@@ -196,7 +196,8 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -196,7 +196,8 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
} }
// Show what created goroutine, except main goroutine (goid 1). // Show what created goroutine, except main goroutine (goid 1).
if(pcbuf == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil && gp->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); runtime·printf("created by %S\n", f->name);
tracepc = pc; // back up to CALL instruction for funcline. tracepc = pc; // back up to CALL instruction for funcline.
if(n > 0 && pc > f->entry) if(n > 0 && pc > f->entry)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment