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)
void
runtime·throw(int8 *s)
{
if(m->throwing == 0)
m->throwing = 1;
runtime·startpanic();
runtime·printf("fatal error: %s\n", s);
runtime·dopanic(0);
......
......@@ -242,6 +242,7 @@ runtime·main(void)
setmcpumax(runtime·gomaxprocs);
runtime·sched.init = true;
scvg = runtime·newproc1((byte*)runtime·MHeap_Scavenger, nil, 0, 0, runtime·main);
scvg->issystem = true;
main·init();
runtime·sched.init = false;
if(!runtime·sched.lockmain)
......@@ -325,10 +326,14 @@ void
runtime·tracebackothers(G *me)
{
G *gp;
int32 traceback;
traceback = runtime·gotraceback();
for(gp = runtime·allg; gp != nil; gp = gp->alllink) {
if(gp == me || gp->status == Gdead)
continue;
if(gp->issystem && traceback < 2)
continue;
runtime·printf("\n");
runtime·goroutineheader(gp);
runtime·traceback(gp->sched.pc, (byte*)gp->sched.sp, 0, gp);
......@@ -624,6 +629,7 @@ top:
if((scvg == nil && runtime·sched.grunning == 0) ||
(scvg != nil && runtime·sched.grunning == 1 && runtime·sched.gwait == 0 &&
(scvg->status == Grunning || scvg->status == Gsyscall))) {
m->throwing = -1; // do not dump full stacks
runtime·throw("all goroutines are asleep - deadlock!");
}
......
......@@ -219,6 +219,7 @@ struct G
G* schedlink;
bool readyonstop;
bool ispanic;
bool issystem;
int8 raceignore; // ignore race detection events
M* m; // for debuggers, but offset not hard-coded
M* lockedm;
......@@ -252,6 +253,7 @@ struct M
G* curg; // current running goroutine
int32 id;
int32 mallocing;
int32 throwing;
int32 gcing;
int32 locks;
int32 nomemprof;
......@@ -865,7 +867,7 @@ Hmap* runtime·makemap_c(MapType*, int64);
Hchan* runtime·makechan_c(ChanType*, int64);
void runtime·chansend(ChanType*, Hchan*, byte*, bool*, void*);
void runtime·chanrecv(ChanType*, Hchan*, byte*, bool*, bool*);
bool runtime·showframe(Func*);
bool runtime·showframe(Func*, bool);
void runtime·ifaceE2I(InterfaceType*, Eface, Iface*);
......
......@@ -559,11 +559,13 @@ contains(String s, int8 *p)
}
bool
runtime·showframe(Func *f)
runtime·showframe(Func *f, bool current)
{
static int32 traceback = -1;
if(current && m->throwing > 0)
return 1;
if(traceback < 0)
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)
runtime·ready(timers.timerproc);
}
}
if(timers.timerproc == nil)
if(timers.timerproc == nil) {
timers.timerproc = runtime·newproc1((byte*)timerproc, nil, 0, 0, addtimer);
timers.timerproc->issystem = true;
}
}
// Delete timer t from the heap.
......
......@@ -25,7 +25,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
bool waspanic;
Stktop *stk;
Func *f;
pc = (uintptr)pc0;
lr = (uintptr)lr0;
fp = nil;
......@@ -60,7 +60,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
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;
......@@ -118,7 +118,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, 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
......@@ -184,7 +184,8 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
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);
tracepc = pc; // back up to CALL instruction for funcline.
if(n > 0 && pc > f->entry)
......
......@@ -77,7 +77,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
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;
......@@ -126,7 +126,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, 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
......@@ -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).
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);
tracepc = pc; // back up to CALL instruction for funcline.
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