mirror of
https://github.com/golang/go
synced 2024-11-20 01:54:41 -07:00
cmd/ld, runtime: restrict stack root scan to locals and arguments
Updates #5134 R=golang-dev, bradfitz, cshapiro, daniel.morsing, ality, iant CC=golang-dev https://golang.org/cl/8022044
This commit is contained in:
parent
7e7f89933b
commit
c676b8b27b
@ -1862,7 +1862,10 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
|
|||||||
/* frame, locals, args, auto and param after */
|
/* frame, locals, args, auto and param after */
|
||||||
put(nil, ".frame", 'm', (uint32)s->text->to.offset+PtrSize, 0, 0, 0);
|
put(nil, ".frame", 'm', (uint32)s->text->to.offset+PtrSize, 0, 0, 0);
|
||||||
put(nil, ".locals", 'm', s->locals, 0, 0, 0);
|
put(nil, ".locals", 'm', s->locals, 0, 0, 0);
|
||||||
put(nil, ".args", 'm', s->args, 0, 0, 0);
|
if(s->text->textflag & NOSPLIT)
|
||||||
|
put(nil, ".args", 'm', ArgsSizeUnknown, 0, 0, 0);
|
||||||
|
else
|
||||||
|
put(nil, ".args", 'm', s->args, 0, 0, 0);
|
||||||
|
|
||||||
for(a=s->autom; a; a=a->link) {
|
for(a=s->autom; a; a=a->link) {
|
||||||
// Emit a or p according to actual offset, even if label is wrong.
|
// Emit a or p according to actual offset, even if label is wrong.
|
||||||
|
@ -71,6 +71,13 @@ enum
|
|||||||
NHASH = 100003,
|
NHASH = 100003,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
// This value is known to the garbage collector and should be kept in
|
||||||
|
// sync with runtime/pkg/runtime.h
|
||||||
|
ArgsSizeUnknown = 0x80000000
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct Library Library;
|
typedef struct Library Library;
|
||||||
struct Library
|
struct Library
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,7 @@ enum {
|
|||||||
Debug = 0,
|
Debug = 0,
|
||||||
DebugMark = 0, // run second pass to check mark
|
DebugMark = 0, // run second pass to check mark
|
||||||
CollectStats = 0,
|
CollectStats = 0,
|
||||||
|
ScanStackByFrames = 0,
|
||||||
|
|
||||||
// Four bits per word (see #defines below).
|
// Four bits per word (see #defines below).
|
||||||
wordsPerBitmapWord = sizeof(void*)*8/4,
|
wordsPerBitmapWord = sizeof(void*)*8/4,
|
||||||
@ -1316,51 +1317,94 @@ addroot(Obj obj)
|
|||||||
work.nroot++;
|
work.nroot++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scan a stack frame. The doframe parameter is a signal that the previously
|
||||||
|
// scanned activation has an unknown argument size. When *doframe is true the
|
||||||
|
// current activation must have its entire frame scanned. Otherwise, only the
|
||||||
|
// locals need to be scanned.
|
||||||
|
static void
|
||||||
|
addframeroots(Func *f, byte*, byte *sp, void *doframe)
|
||||||
|
{
|
||||||
|
uintptr outs;
|
||||||
|
|
||||||
|
if(thechar == '5')
|
||||||
|
sp += sizeof(uintptr);
|
||||||
|
if(f->locals == 0 || *(bool*)doframe == true)
|
||||||
|
addroot((Obj){sp, f->frame - sizeof(uintptr), 0});
|
||||||
|
else if(f->locals > 0) {
|
||||||
|
outs = f->frame - sizeof(uintptr) - f->locals;
|
||||||
|
addroot((Obj){sp + outs, f->locals, 0});
|
||||||
|
}
|
||||||
|
if(f->args > 0)
|
||||||
|
addroot((Obj){sp + f->frame, f->args, 0});
|
||||||
|
*(bool*)doframe = (f->args == ArgsSizeUnknown);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
addstackroots(G *gp)
|
addstackroots(G *gp)
|
||||||
{
|
{
|
||||||
M *mp;
|
M *mp;
|
||||||
int32 n;
|
int32 n;
|
||||||
Stktop *stk;
|
Stktop *stk;
|
||||||
byte *sp, *guard;
|
byte *sp, *guard, *pc;
|
||||||
|
Func *f;
|
||||||
|
bool doframe;
|
||||||
|
|
||||||
stk = (Stktop*)gp->stackbase;
|
stk = (Stktop*)gp->stackbase;
|
||||||
guard = (byte*)gp->stackguard;
|
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 = runtime·getcallersp(&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;
|
||||||
|
stk = (Stktop*)gp->gcstack;
|
||||||
|
guard = (byte*)gp->gcguard;
|
||||||
} 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;
|
||||||
// The exception is that if the goroutine is about to enter or might
|
if(ScanStackByFrames && pc == (byte*)runtime·goexit && gp->fnstart != nil) {
|
||||||
// have just exited a system call, it may be executing code such
|
// The goroutine has not started. However, its incoming
|
||||||
// as schedlock and may have needed to start a new stack segment.
|
// arguments are live at the top of the stack and must
|
||||||
// Use the stack segment and stack pointer at the time of
|
// be scanned. No other live values should be on the
|
||||||
// the system call instead, since that won't change underfoot.
|
// stack.
|
||||||
if(gp->gcstack != (uintptr)nil) {
|
f = runtime·findfunc((uintptr)gp->fnstart->fn);
|
||||||
stk = (Stktop*)gp->gcstack;
|
if(f->args > 0) {
|
||||||
sp = (byte*)gp->gcsp;
|
if(thechar == '5')
|
||||||
guard = (byte*)gp->gcguard;
|
sp += sizeof(uintptr);
|
||||||
|
addroot((Obj){sp, f->args, 0});
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ScanStackByFrames) {
|
||||||
n = 0;
|
doframe = false;
|
||||||
while(stk) {
|
runtime·gentraceback(pc, sp, nil, gp, 0, nil, 0x7fffffff, addframeroots, &doframe);
|
||||||
if(sp < guard-StackGuard || (byte*)stk < sp) {
|
} else {
|
||||||
runtime·printf("scanstack inconsistent: g%D#%d sp=%p not in [%p,%p]\n", gp->goid, n, sp, guard-StackGuard, stk);
|
USED(pc);
|
||||||
runtime·throw("scanstack");
|
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, (uintptr)defaultProg | PRECISE | LOOP});
|
||||||
|
sp = (byte*)stk->gobuf.sp;
|
||||||
|
guard = stk->stackguard;
|
||||||
|
stk = (Stktop*)stk->stackbase;
|
||||||
|
n++;
|
||||||
}
|
}
|
||||||
addroot((Obj){sp, (byte*)stk - sp, (uintptr)defaultProg | PRECISE | LOOP});
|
|
||||||
sp = (byte*)stk->gobuf.sp;
|
|
||||||
guard = stk->stackguard;
|
|
||||||
stk = (Stktop*)stk->stackbase;
|
|
||||||
n++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
n = runtime·gentraceback(pc, sp, 0, gp, 0, r->stk, nelem(r->stk), nil, nil);
|
||||||
if(n < nelem(r->stk))
|
if(n < nelem(r->stk))
|
||||||
r->stk[n] = 0;
|
r->stk[n] = 0;
|
||||||
}
|
}
|
||||||
|
@ -1778,7 +1778,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));
|
n = runtime·gentraceback(pc, sp, lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil);
|
||||||
if(n > 0)
|
if(n > 0)
|
||||||
prof.fn(prof.pcbuf, n);
|
prof.fn(prof.pcbuf, n);
|
||||||
runtime·unlock(&prof);
|
runtime·unlock(&prof);
|
||||||
|
@ -147,7 +147,12 @@ enum
|
|||||||
// Global <-> per-M stack segment cache transfer batch size.
|
// Global <-> per-M stack segment cache transfer batch size.
|
||||||
StackCacheBatch = 16,
|
StackCacheBatch = 16,
|
||||||
};
|
};
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
// This value is generated by the linker and should be kept in
|
||||||
|
// sync with cmd/ld/lib.h
|
||||||
|
ArgsSizeUnknown = 0x80000000,
|
||||||
|
};
|
||||||
/*
|
/*
|
||||||
* structures
|
* structures
|
||||||
*/
|
*/
|
||||||
@ -775,7 +780,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);
|
int32 runtime·gentraceback(byte*, byte*, byte*, G*, int32, uintptr*, int32, void (*)(Func*, byte*, byte*, void*), void*);
|
||||||
int64 runtime·nanotime(void);
|
int64 runtime·nanotime(void);
|
||||||
void runtime·dopanic(int32);
|
void runtime·dopanic(int32);
|
||||||
void runtime·startpanic(void);
|
void runtime·startpanic(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)
|
runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*fn)(Func*, byte*, byte*, void*), void *arg)
|
||||||
{
|
{
|
||||||
int32 i, n, iter;
|
int32 i, n;
|
||||||
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
|
|||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
stk = (Stktop*)gp->stackbase;
|
stk = (Stktop*)gp->stackbase;
|
||||||
for(iter = 0; iter < 100 && n < max; iter++) { // iter avoids looping forever
|
while(n < max) {
|
||||||
// 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,14 +60,17 @@ 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 && runtime·showframe(nil, gp == m->curg))
|
if(pcbuf == nil && fn == 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)
|
||||||
@ -83,6 +86,8 @@ 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.
|
||||||
@ -114,7 +119,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 && f->entry == (uintptr)runtime·newstack && gp == m->g0) {
|
if(pcbuf == nil && fn == 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*);
|
||||||
@ -125,7 +130,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pcbuf == nil && f->entry == (uintptr)runtime·lessstack && gp == m->g0) {
|
if(pcbuf == nil && fn == 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;
|
||||||
@ -136,6 +141,10 @@ 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;
|
||||||
@ -163,7 +172,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pcbuf == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil
|
if(pcbuf == nil && fn == 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.
|
||||||
@ -187,7 +196,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);
|
runtime·gentraceback(pc0, sp, lr, gp, 0, nil, 100, nil, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
// func caller(n int) (pc uintptr, file string, line int, ok bool)
|
// func caller(n int) (pc uintptr, file string, line int, ok bool)
|
||||||
@ -199,5 +208,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);
|
return runtime·gentraceback(pc, sp, 0, g, skip, pcbuf, m, nil, nil);
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
// as well as the runtime.Callers function (pcbuf != nil).
|
// the runtime.Callers function (pcbuf != nil), as well as the garbage
|
||||||
// A little clunky to merge the two but avoids duplicating
|
// collector (fn != nil). A little clunky to merge the two but avoids
|
||||||
// the code and all its subtlety.
|
// duplicating the code and all its subtlety.
|
||||||
int32
|
int32
|
||||||
runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max)
|
runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*fn)(Func*, byte*, byte*, void*), void *arg)
|
||||||
{
|
{
|
||||||
int32 i, n, iter, sawnewstack;
|
int32 i, n, 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
|
|||||||
n = 0;
|
n = 0;
|
||||||
sawnewstack = 0;
|
sawnewstack = 0;
|
||||||
stk = (Stktop*)gp->stackbase;
|
stk = (Stktop*)gp->stackbase;
|
||||||
for(iter = 0; iter < 100 && n < max; iter++) { // iter avoids looping forever
|
while(n < max) {
|
||||||
// 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,13 +68,16 @@ 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 && runtime·showframe(nil, gp == m->curg))
|
if(pcbuf == nil && fn == 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) {
|
||||||
@ -91,6 +94,8 @@ 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.
|
||||||
@ -129,7 +134,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 && f->entry == (uintptr)runtime·morestack && gp == m->g0 && sawnewstack) {
|
if(pcbuf == nil && fn == 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.
|
||||||
@ -144,7 +149,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pcbuf == nil && f->entry == (uintptr)runtime·lessstack && gp == m->g0) {
|
if(pcbuf == nil && fn == 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;
|
||||||
@ -156,6 +161,10 @@ 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;
|
||||||
@ -164,7 +173,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 && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil
|
if(pcbuf == nil && fn == 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.
|
||||||
@ -187,7 +196,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);
|
runtime·gentraceback(pc0, sp, nil, gp, 0, nil, 100, nil, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32
|
int32
|
||||||
@ -199,5 +208,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);
|
return runtime·gentraceback(pc, sp, nil, g, skip, pcbuf, m, nil, nil);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user