Commit e0deb2ef authored by Russ Cox's avatar Russ Cox

undo CL 7301062 / 9742f722b558

broke arm garbage collector

traceback_arm fails with a missing pc. It needs CL 7494043.
But that only makes the build break later, this time with
"invalid freelist". Roll back until it can be fixed correctly.

««« original CL description
runtime: restrict stack root scan to locals and arguments

R=rsc
CC=golang-dev
https://golang.org/cl/7301062
»»»

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/7493044
parent d0151679
...@@ -1299,53 +1299,52 @@ addroot(Obj obj) ...@@ -1299,53 +1299,52 @@ addroot(Obj obj)
work.nroot++; work.nroot++;
} }
static void
addframeroots(Func *f, byte*, byte *sp, void*)
{
if (f->frame > sizeof(uintptr))
addroot((Obj){sp, f->frame - sizeof(uintptr), 0});
if (f->args > 0)
addroot((Obj){sp + f->frame, f->args, 0});
}
static void static void
addstackroots(G *gp) addstackroots(G *gp)
{ {
M *mp; M *mp;
Func *f; int32 n;
byte *sp, *pc; Stktop *stk;
byte *sp, *guard;
stk = (Stktop*)gp->stackbase;
guard = (byte*)gp->stackguard;
if(gp == g) { if(gp == g) {
// Scanning our own stack: start at &gp. // Scanning our own stack: start at &gp.
sp = (byte*)&gp; sp = (byte*)&gp;
pc = runtime·getcallerpc(&gp);
} else if((mp = gp->m) != nil && mp->helpgc) { } else if((mp = gp->m) != nil && mp->helpgc) {
// gchelper's stack is in active use and has no interesting pointers. // gchelper's stack is in active use and has no interesting pointers.
return; return;
} else if(gp->gcstack != (uintptr)nil) {
// Scanning another goroutine that is about to enter or might
// have just exited a system call. It may be executing code such
// as schedlock and may have needed to start a new stack segment.
// Use the stack segment and stack pointer at the time of
// the system call instead, since that won't change underfoot.
sp = (byte*)gp->gcsp;
pc = gp->gcpc;
} else { } else {
// Scanning another goroutine's stack. // Scanning another goroutine's stack.
// The goroutine is usually asleep (the world is stopped). // The goroutine is usually asleep (the world is stopped).
sp = (byte*)gp->sched.sp; sp = (byte*)gp->sched.sp;
pc = gp->sched.pc;
if (pc == (byte*)runtime·goexit && gp->fnstart != nil) { // The exception is that if the goroutine is about to enter or might
// The goroutine has not started. Its incoming // have just exited a system call, it may be executing code such
// arguments are at the top of the stack and must // as schedlock and may have needed to start a new stack segment.
// be scanned. No other data on the stack. // Use the stack segment and stack pointer at the time of
f = runtime·findfunc((uintptr)gp->fnstart->fn); // the system call instead, since that won't change underfoot.
if (f->args > 0) if(gp->gcstack != (uintptr)nil) {
addroot((Obj){sp, f->args, 0}); stk = (Stktop*)gp->gcstack;
return; sp = (byte*)gp->gcsp;
guard = (byte*)gp->gcguard;
}
} }
n = 0;
while(stk) {
if(sp < guard-StackGuard || (byte*)stk < sp) {
runtime·printf("scanstack inconsistent: g%D#%d sp=%p not in [%p,%p]\n", gp->goid, n, sp, guard-StackGuard, stk);
runtime·throw("scanstack");
}
addroot((Obj){sp, (byte*)stk - sp, 0});
sp = (byte*)stk->gobuf.sp;
guard = stk->stackguard;
stk = (Stktop*)stk->stackbase;
n++;
} }
runtime·gentraceback(pc, sp, nil, gp, 0, nil, 0x7fffffff, addframeroots, nil);
} }
static void static void
......
...@@ -511,7 +511,7 @@ saveg(byte *pc, byte *sp, G *gp, TRecord *r) ...@@ -511,7 +511,7 @@ saveg(byte *pc, byte *sp, G *gp, TRecord *r)
{ {
int32 n; int32 n;
n = runtime·gentraceback(pc, sp, 0, gp, 0, r->stk, nelem(r->stk), nil, nil); n = runtime·gentraceback(pc, sp, 0, gp, 0, r->stk, nelem(r->stk));
if(n < nelem(r->stk)) if(n < nelem(r->stk))
r->stk[n] = 0; r->stk[n] = 0;
} }
......
...@@ -1710,7 +1710,7 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp) ...@@ -1710,7 +1710,7 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
runtime·unlock(&prof); runtime·unlock(&prof);
return; return;
} }
n = runtime·gentraceback(pc, sp, lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil); n = runtime·gentraceback(pc, sp, lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf));
if(n > 0) if(n > 0)
prof.fn(prof.pcbuf, n); prof.fn(prof.pcbuf, n);
runtime·unlock(&prof); runtime·unlock(&prof);
......
...@@ -749,7 +749,7 @@ void runtime·exitsyscall(void); ...@@ -749,7 +749,7 @@ void runtime·exitsyscall(void);
G* runtime·newproc1(FuncVal*, byte*, int32, int32, void*); G* runtime·newproc1(FuncVal*, byte*, int32, int32, void*);
bool runtime·sigsend(int32 sig); bool runtime·sigsend(int32 sig);
int32 runtime·callers(int32, uintptr*, int32); int32 runtime·callers(int32, uintptr*, int32);
int32 runtime·gentraceback(byte*, byte*, byte*, G*, int32, uintptr*, int32, void (*fn)(Func*, byte*, byte*, void*), void *arg); int32 runtime·gentraceback(byte*, byte*, byte*, G*, int32, uintptr*, int32);
int64 runtime·nanotime(void); int64 runtime·nanotime(void);
void runtime·dopanic(int32); void runtime·dopanic(int32);
void runtime·startpanic(void); void runtime·startpanic(void);
......
...@@ -84,7 +84,6 @@ func signal_recv() (m uint32) { ...@@ -84,7 +84,6 @@ func signal_recv() (m uint32) {
static uint32 recv[nelem(sig.mask)]; static uint32 recv[nelem(sig.mask)];
uint32 i, old, new; uint32 i, old, new;
g->issystem = true;
for(;;) { for(;;) {
// Serve from local copy if there are bits left. // Serve from local copy if there are bits left.
for(i=0; i<NSIG; i++) { for(i=0; i<NSIG; i++) {
......
...@@ -17,9 +17,9 @@ void _divu(void); ...@@ -17,9 +17,9 @@ void _divu(void);
void _modu(void); void _modu(void);
int32 int32
runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*fn)(Func*, byte*, byte*, void*), void *arg) runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max)
{ {
int32 i, n; int32 i, n, iter;
uintptr pc, lr, tracepc, x; uintptr pc, lr, tracepc, x;
byte *fp; byte *fp;
bool waspanic; bool waspanic;
...@@ -46,7 +46,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -46,7 +46,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
n = 0; n = 0;
stk = (Stktop*)gp->stackbase; stk = (Stktop*)gp->stackbase;
while(n < max) { for(iter = 0; iter < 100 && n < max; iter++) { // iter avoids looping forever
// Typically: // Typically:
// pc is the PC of the running function. // pc is the PC of the running function.
// sp is the stack pointer at that program counter. // sp is the stack pointer at that program counter.
...@@ -60,17 +60,14 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -60,17 +60,14 @@ 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 && fn == nil && runtime·showframe(nil, gp == m->curg)) 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;
} }
if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil) { if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil)
if(fn != nil)
runtime·throw("unknown pc");
break; break;
}
// Found an actual function. // Found an actual function.
if(lr == 0) if(lr == 0)
...@@ -85,8 +82,6 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -85,8 +82,6 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
skip--; skip--;
else if(pcbuf != nil) else if(pcbuf != nil)
pcbuf[n++] = pc; pcbuf[n++] = pc;
else if(fn != nil)
(*fn)(f, (byte*)pc, sp, arg);
else { else {
if(runtime·showframe(f, gp == m->curg)) { if(runtime·showframe(f, gp == m->curg)) {
// Print during crash. // Print during crash.
...@@ -118,7 +113,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -118,7 +113,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
waspanic = f->entry == (uintptr)runtime·sigpanic; waspanic = f->entry == (uintptr)runtime·sigpanic;
if(pcbuf == nil && fn == nil && f->entry == (uintptr)runtime·newstack && gp == m->g0) { if(pcbuf == nil && f->entry == (uintptr)runtime·newstack && gp == m->g0) {
runtime·printf("----- newstack called from goroutine %D -----\n", m->curg->goid); runtime·printf("----- newstack called from goroutine %D -----\n", m->curg->goid);
pc = (uintptr)m->morepc; pc = (uintptr)m->morepc;
sp = (byte*)m->moreargp - sizeof(void*); sp = (byte*)m->moreargp - sizeof(void*);
...@@ -129,7 +124,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -129,7 +124,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
continue; continue;
} }
if(pcbuf == nil && fn == nil && f->entry == (uintptr)runtime·lessstack && gp == m->g0) { if(pcbuf == nil && f->entry == (uintptr)runtime·lessstack && gp == m->g0) {
runtime·printf("----- lessstack called from goroutine %D -----\n", m->curg->goid); runtime·printf("----- lessstack called from goroutine %D -----\n", m->curg->goid);
gp = m->curg; gp = m->curg;
stk = (Stktop*)gp->stackbase; stk = (Stktop*)gp->stackbase;
...@@ -140,10 +135,6 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -140,10 +135,6 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
continue; continue;
} }
// Do not unwind past the bottom of the stack.
if(pc == (uintptr)runtime·goexit)
break;
// Unwind to next frame. // Unwind to next frame.
pc = lr; pc = lr;
lr = 0; lr = 0;
...@@ -171,7 +162,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -171,7 +162,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
} }
} }
if(pcbuf == nil && fn == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil if(pcbuf == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil
&& runtime·showframe(f, gp == m->curg) && gp->goid != 1) { && 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.
...@@ -195,7 +186,7 @@ runtime·traceback(byte *pc0, byte *sp, byte *lr, G *gp) ...@@ -195,7 +186,7 @@ runtime·traceback(byte *pc0, byte *sp, byte *lr, G *gp)
sp = (byte*)gp->sched.sp; sp = (byte*)gp->sched.sp;
lr = nil; lr = nil;
} }
runtime·gentraceback(pc0, sp, lr, gp, 0, nil, 100, nil, nil); runtime·gentraceback(pc0, sp, lr, gp, 0, nil, 100);
} }
// func caller(n int) (pc uintptr, file string, line int, ok bool) // func caller(n int) (pc uintptr, file string, line int, ok bool)
...@@ -207,5 +198,5 @@ runtime·callers(int32 skip, uintptr *pcbuf, int32 m) ...@@ -207,5 +198,5 @@ runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
sp = runtime·getcallersp(&skip); sp = runtime·getcallersp(&skip);
pc = runtime·getcallerpc(&skip); pc = runtime·getcallerpc(&skip);
return runtime·gentraceback(pc, sp, 0, g, skip, pcbuf, m, nil, nil); return runtime·gentraceback(pc, sp, 0, g, skip, pcbuf, m);
} }
...@@ -17,14 +17,14 @@ void runtime·sigpanic(void); ...@@ -17,14 +17,14 @@ void runtime·sigpanic(void);
// This code is also used for the 386 tracebacks. // This code is also used for the 386 tracebacks.
// Use uintptr for an appropriate word-sized integer. // Use uintptr for an appropriate word-sized integer.
// Generic traceback. Handles runtime stack prints (pcbuf == nil), // Generic traceback. Handles runtime stack prints (pcbuf == nil)
// the runtime.Callers function (pcbuf != nil), as well as the garbage // as well as the runtime.Callers function (pcbuf != nil).
// collector (fn != nil). A little clunky to merge the two but avoids // A little clunky to merge the two but avoids duplicating
// duplicating the code and all its subtlety. // the code and all its subtlety.
int32 int32
runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*fn)(Func*, byte*, byte*, void*), void *arg) runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max)
{ {
int32 i, n, sawnewstack; int32 i, n, iter, sawnewstack;
uintptr pc, lr, tracepc; uintptr pc, lr, tracepc;
byte *fp; byte *fp;
Stktop *stk; Stktop *stk;
...@@ -54,7 +54,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -54,7 +54,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
n = 0; n = 0;
sawnewstack = 0; sawnewstack = 0;
stk = (Stktop*)gp->stackbase; stk = (Stktop*)gp->stackbase;
while(n < max) { for(iter = 0; iter < 100 && n < max; iter++) { // iter avoids looping forever
// Typically: // Typically:
// pc is the PC of the running function. // pc is the PC of the running function.
// sp is the stack pointer at that program counter. // sp is the stack pointer at that program counter.
...@@ -68,16 +68,13 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -68,16 +68,13 @@ 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 && fn == nil && runtime·showframe(nil, gp == m->curg)) 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;
} }
if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil) { if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil)
if(fn != nil)
runtime·throw("unknown pc");
break; break;
}
// Found an actual function. // Found an actual function.
if(fp == nil) { if(fp == nil) {
...@@ -94,8 +91,6 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -94,8 +91,6 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
skip--; skip--;
else if(pcbuf != nil) else if(pcbuf != nil)
pcbuf[n++] = pc; pcbuf[n++] = pc;
else if(fn != nil)
(*fn)(f, (byte*)pc, sp, arg);
else { else {
if(runtime·showframe(f, gp == m->curg)) { if(runtime·showframe(f, gp == m->curg)) {
// Print during crash. // Print during crash.
...@@ -134,7 +129,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -134,7 +129,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
if(f->entry == (uintptr)runtime·newstack) if(f->entry == (uintptr)runtime·newstack)
sawnewstack = 1; sawnewstack = 1;
if(pcbuf == nil && fn == nil && f->entry == (uintptr)runtime·morestack && gp == m->g0 && sawnewstack) { if(pcbuf == nil && f->entry == (uintptr)runtime·morestack && gp == m->g0 && sawnewstack) {
// The fact that we saw newstack means that morestack // The fact that we saw newstack means that morestack
// has managed to record its information in m, so we can // has managed to record its information in m, so we can
// use it to keep unwinding the stack. // use it to keep unwinding the stack.
...@@ -149,7 +144,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -149,7 +144,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
continue; continue;
} }
if(pcbuf == nil && fn == nil && f->entry == (uintptr)runtime·lessstack && gp == m->g0) { if(pcbuf == nil && f->entry == (uintptr)runtime·lessstack && gp == m->g0) {
// Lessstack is running on scheduler stack. Switch to original goroutine. // Lessstack is running on scheduler stack. Switch to original goroutine.
runtime·printf("----- lessstack called from goroutine %D -----\n", m->curg->goid); runtime·printf("----- lessstack called from goroutine %D -----\n", m->curg->goid);
gp = m->curg; gp = m->curg;
...@@ -161,10 +156,6 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -161,10 +156,6 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
continue; continue;
} }
// Do not unwind past the bottom of the stack.
if(pc == (uintptr)runtime·goexit)
break;
// Unwind to next frame. // Unwind to next frame.
pc = lr; pc = lr;
lr = 0; lr = 0;
...@@ -173,7 +164,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr ...@@ -173,7 +164,7 @@ 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 && fn == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil if(pcbuf == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil
&& runtime·showframe(f, gp == m->curg) && gp->goid != 1) { && 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.
...@@ -196,7 +187,7 @@ runtime·traceback(byte *pc0, byte *sp, byte*, G *gp) ...@@ -196,7 +187,7 @@ runtime·traceback(byte *pc0, byte *sp, byte*, G *gp)
pc0 = gp->sched.pc; pc0 = gp->sched.pc;
sp = (byte*)gp->sched.sp; sp = (byte*)gp->sched.sp;
} }
runtime·gentraceback(pc0, sp, nil, gp, 0, nil, 100, nil, nil); runtime·gentraceback(pc0, sp, nil, gp, 0, nil, 100);
} }
int32 int32
...@@ -208,5 +199,5 @@ runtime·callers(int32 skip, uintptr *pcbuf, int32 m) ...@@ -208,5 +199,5 @@ runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
sp = (byte*)&skip; sp = (byte*)&skip;
pc = runtime·getcallerpc(&skip); pc = runtime·getcallerpc(&skip);
return runtime·gentraceback(pc, sp, nil, g, skip, pcbuf, m, nil, nil); return runtime·gentraceback(pc, sp, nil, g, skip, pcbuf, m);
} }
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