aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-11-14 11:37:54 -0500
committerRuss Cox <rsc@golang.org>2014-11-14 11:37:54 -0500
commit3dcc62e1dad3c62a1c8df1b6f613f93521124764 (patch)
tree104445da5e3ecfc84f1973cef910a4ab481b2fde /src/runtime
parent18ed947ee17be6bbd9d169256ad9382611eb3eb1 (diff)
parentc99616fc6795123ec1a6b4d742099789865bd939 (diff)
downloadgo-3dcc62e1dad3c62a1c8df1b6f613f93521124764.tar.xz
[dev.garbage] all: merge default (f38460037b72) into dev.garbage
This is the revision that dev.cc is branched from. LGTM=austin R=austin CC=golang-codereviews https://golang.org/cl/169590043
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/asm_386.s6
-rw-r--r--src/runtime/asm_amd64.s6
-rw-r--r--src/runtime/asm_amd64p32.s6
-rw-r--r--src/runtime/asm_arm.s6
-rw-r--r--src/runtime/cgo/dragonfly.c2
-rw-r--r--src/runtime/cgo/freebsd.c2
-rw-r--r--src/runtime/cgo/netbsd.c2
-rw-r--r--src/runtime/cgo/openbsd.c2
-rw-r--r--src/runtime/crash_cgo_test.go29
-rw-r--r--src/runtime/extern.go11
-rw-r--r--src/runtime/heapdump.c6
-rw-r--r--src/runtime/malloc.go6
-rw-r--r--src/runtime/mgc0.c4
-rw-r--r--src/runtime/mprof.go45
-rw-r--r--src/runtime/os_android.c2
-rw-r--r--src/runtime/os_plan9_386.c2
-rw-r--r--src/runtime/os_plan9_amd64.c2
-rw-r--r--src/runtime/os_windows_386.c2
-rw-r--r--src/runtime/os_windows_amd64.c2
-rw-r--r--src/runtime/proc.c23
-rw-r--r--src/runtime/runtime.h8
-rw-r--r--src/runtime/sema.go1
-rw-r--r--src/runtime/signal_386.c2
-rw-r--r--src/runtime/signal_amd64x.c2
-rw-r--r--src/runtime/signal_arm.c2
-rw-r--r--src/runtime/stack.c2
-rw-r--r--src/runtime/stubs.go28
-rw-r--r--src/runtime/traceback.go53
28 files changed, 207 insertions, 57 deletions
diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s
index d456e6bca4..501e64b094 100644
--- a/src/runtime/asm_386.s
+++ b/src/runtime/asm_386.s
@@ -2284,3 +2284,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
MOVL m_curg(AX), AX
MOVL (g_stack+stack_hi)(AX), AX
RET
+
+// The top-most function running on a goroutine
+// returns to goexit+PCQuantum.
+TEXT runtime·goexit(SB),NOSPLIT,$0-0
+ BYTE $0x90 // NOP
+ CALL runtime·goexit1(SB) // does not return
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 5d176575c3..1aa2d71a80 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -2229,3 +2229,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
MOVQ m_curg(AX), AX
MOVQ (g_stack+stack_hi)(AX), AX
RET
+
+// The top-most function running on a goroutine
+// returns to goexit+PCQuantum.
+TEXT runtime·goexit(SB),NOSPLIT,$0-0
+ BYTE $0x90 // NOP
+ CALL runtime·goexit1(SB) // does not return
diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s
index 2b2155753e..153564b14e 100644
--- a/src/runtime/asm_amd64p32.s
+++ b/src/runtime/asm_amd64p32.s
@@ -1079,3 +1079,9 @@ TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
TEXT runtime·return0(SB), NOSPLIT, $0
MOVL $0, AX
RET
+
+// The top-most function running on a goroutine
+// returns to goexit+PCQuantum.
+TEXT runtime·goexit(SB),NOSPLIT,$0-0
+ BYTE $0x90 // NOP
+ CALL runtime·goexit1(SB) // does not return
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index 9a58fdc51e..58aebf3884 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -1320,3 +1320,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$8
MOVW saveG-8(SP), g
MOVW saveR11-4(SP), R11
RET
+
+// The top-most function running on a goroutine
+// returns to goexit+PCQuantum.
+TEXT runtime·goexit(SB),NOSPLIT,$-4-0
+ MOVW R0, R0 // NOP
+ BL runtime·goexit1(SB) // does not return
diff --git a/src/runtime/cgo/dragonfly.c b/src/runtime/cgo/dragonfly.c
index 3c95ff354e..c233c8ba9a 100644
--- a/src/runtime/cgo/dragonfly.c
+++ b/src/runtime/cgo/dragonfly.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build dragonfly
+
#include "textflag.h"
// Supply environ and __progname, because we don't
diff --git a/src/runtime/cgo/freebsd.c b/src/runtime/cgo/freebsd.c
index aefc481e64..4876b2abe4 100644
--- a/src/runtime/cgo/freebsd.c
+++ b/src/runtime/cgo/freebsd.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build freebsd
+
#include "textflag.h"
// Supply environ and __progname, because we don't
diff --git a/src/runtime/cgo/netbsd.c b/src/runtime/cgo/netbsd.c
index de38bb7707..076cc87f12 100644
--- a/src/runtime/cgo/netbsd.c
+++ b/src/runtime/cgo/netbsd.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build netbsd
+
#include "textflag.h"
// Supply environ and __progname, because we don't
diff --git a/src/runtime/cgo/openbsd.c b/src/runtime/cgo/openbsd.c
index 7c2b6c1737..476649544d 100644
--- a/src/runtime/cgo/openbsd.c
+++ b/src/runtime/cgo/openbsd.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build openbsd
+
#include "textflag.h"
// Supply environ, __progname and __guard_local, because
diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go
index 5958ad8914..972eedc624 100644
--- a/src/runtime/crash_cgo_test.go
+++ b/src/runtime/crash_cgo_test.go
@@ -36,10 +36,14 @@ func TestCgoTraceback(t *testing.T) {
}
func TestCgoExternalThreadPanic(t *testing.T) {
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ if runtime.GOOS == "plan9" {
t.Skipf("no pthreads on %s", runtime.GOOS)
}
- got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", cgoExternalThreadPanicC)
+ csrc := cgoExternalThreadPanicC
+ if runtime.GOOS == "windows" {
+ csrc = cgoExternalThreadPanicC_windows
+ }
+ got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", csrc)
want := "panic: BOOM"
if !strings.Contains(got, want) {
t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
@@ -169,3 +173,24 @@ start(void)
printf("pthread_create failed\n");
}
`
+
+const cgoExternalThreadPanicC_windows = `
+#include <stdlib.h>
+#include <stdio.h>
+
+void gopanic(void);
+
+static void*
+die(void* x)
+{
+ gopanic();
+ return 0;
+}
+
+void
+start(void)
+{
+ if(_beginthreadex(0, 0, die, 0, 0, 0) != 0)
+ printf("_beginthreadex failed\n");
+}
+`
diff --git a/src/runtime/extern.go b/src/runtime/extern.go
index 1b8052bb56..6cc5df810c 100644
--- a/src/runtime/extern.go
+++ b/src/runtime/extern.go
@@ -117,11 +117,20 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
return
}
-// Callers fills the slice pc with the program counters of function invocations
+// Callers fills the slice pc with the return program counters of function invocations
// on the calling goroutine's stack. The argument skip is the number of stack frames
// to skip before recording in pc, with 0 identifying the frame for Callers itself and
// 1 identifying the caller of Callers.
// It returns the number of entries written to pc.
+//
+// Note that since each slice entry pc[i] is a return program counter,
+// looking up the file and line for pc[i] (for example, using (*Func).FileLine)
+// will return the file and line number of the instruction immediately
+// following the call.
+// To look up the file and line number of the call itself, use pc[i]-1.
+// As an exception to this rule, if pc[i-1] corresponds to the function
+// runtime.sigpanic, then pc[i] is the program counter of a faulting
+// instruction and should be used without any subtraction.
func Callers(skip int, pc []uintptr) int {
// runtime.callers uses pc.array==nil as a signal
// to print a stack trace. Pick off 0-length pc here
diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c
index 5ac37803bb..da14f2d241 100644
--- a/src/runtime/heapdump.c
+++ b/src/runtime/heapdump.c
@@ -251,7 +251,9 @@ dumpbv(BitVector *bv, uintptr offset)
for(i = 0; i < bv->n; i += BitsPerPointer) {
switch(bv->bytedata[i/8] >> i%8 & 3) {
case BitsDead:
- return;
+ // BitsDead has already been processed in makeheapobjbv.
+ // We should only see it in stack maps, in which case we should continue processing.
+ break;
case BitsScalar:
break;
case BitsPointer:
@@ -400,7 +402,7 @@ dumpgoroutine(G *gp)
child.sp = nil;
child.depth = 0;
fn = dumpframe;
- runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, &fn, &child, false);
+ runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, &fn, &child, 0);
// dump defer & panic records
for(d = gp->defer; d != nil; d = d->link) {
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index a18e77421e..fab8cf2695 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -41,7 +41,7 @@ var zerobase uintptr
// Allocate an object of size bytes.
// Small objects are allocated from the per-P cache's free lists.
// Large objects (> 32 kB) are allocated straight from the heap.
-func mallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer {
+func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
if size == 0 {
return unsafe.Pointer(&zerobase)
}
@@ -391,7 +391,7 @@ func loadPtrMask(typ *_type) []uint8 {
// implementation of new builtin
func newobject(typ *_type) unsafe.Pointer {
- flags := 0
+ flags := uint32(0)
if typ.kind&kindNoPointers != 0 {
flags |= flagNoScan
}
@@ -400,7 +400,7 @@ func newobject(typ *_type) unsafe.Pointer {
// implementation of make builtin for slices
func newarray(typ *_type, n uintptr) unsafe.Pointer {
- flags := 0
+ flags := uint32(0)
if typ.kind&kindNoPointers != 0 {
flags |= flagNoScan
}
diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c
index 214b9ebc24..3248b0f49a 100644
--- a/src/runtime/mgc0.c
+++ b/src/runtime/mgc0.c
@@ -1021,7 +1021,7 @@ scanstack(G *gp)
runtime·throw("can't scan gchelper stack");
fn = scanframe;
- runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &fn, nil, false);
+ runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &fn, nil, 0);
runtime·tracebackdefers(gp, &fn, nil);
}
@@ -2635,7 +2635,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
frame.fn = nil;
frame.sp = (uintptr)p;
cb = getgcmaskcb;
- runtime·gentraceback(g->m->curg->sched.pc, g->m->curg->sched.sp, 0, g->m->curg, 0, nil, 1000, &cb, &frame, false);
+ runtime·gentraceback(g->m->curg->sched.pc, g->m->curg->sched.sp, 0, g->m->curg, 0, nil, 1000, &cb, &frame, 0);
if(frame.fn != nil) {
Func *f;
StackMap *stackmap;
diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go
index 803da56670..d409c6c306 100644
--- a/src/runtime/mprof.go
+++ b/src/runtime/mprof.go
@@ -528,8 +528,6 @@ var allgs []*g // proc.c
// Most clients should use the runtime/pprof package instead
// of calling GoroutineProfile directly.
func GoroutineProfile(p []StackRecord) (n int, ok bool) {
- sp := getcallersp(unsafe.Pointer(&p))
- pc := getcallerpc(unsafe.Pointer(&p))
n = NumGoroutine()
if n <= len(p) {
@@ -542,7 +540,11 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
if n <= len(p) {
ok = true
r := p
- saveg(pc, sp, gp, &r[0])
+ sp := getcallersp(unsafe.Pointer(&p))
+ pc := getcallerpc(unsafe.Pointer(&p))
+ onM(func() {
+ saveg(pc, sp, gp, &r[0])
+ })
r = r[1:]
for _, gp1 := range allgs {
if gp1 == gp || readgstatus(gp1) == _Gdead {
@@ -562,7 +564,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
}
func saveg(pc, sp uintptr, gp *g, r *StackRecord) {
- n := gentraceback(pc, sp, 0, gp, 0, &r.Stack0[0], len(r.Stack0), nil, nil, false)
+ n := gentraceback(pc, sp, 0, gp, 0, &r.Stack0[0], len(r.Stack0), nil, nil, 0)
if n < len(r.Stack0) {
r.Stack0[n] = 0
}
@@ -573,8 +575,6 @@ func saveg(pc, sp uintptr, gp *g, r *StackRecord) {
// If all is true, Stack formats stack traces of all other goroutines
// into buf after the trace for the current goroutine.
func Stack(buf []byte, all bool) int {
- sp := getcallersp(unsafe.Pointer(&buf))
- pc := getcallerpc(unsafe.Pointer(&buf))
mp := acquirem()
gp := mp.curg
if all {
@@ -589,14 +589,19 @@ func Stack(buf []byte, all bool) int {
n := 0
if len(buf) > 0 {
- gp.writebuf = buf[0:0:len(buf)]
- goroutineheader(gp)
- traceback(pc, sp, 0, gp)
- if all {
- tracebackothers(gp)
- }
- n = len(gp.writebuf)
- gp.writebuf = nil
+ sp := getcallersp(unsafe.Pointer(&buf))
+ pc := getcallerpc(unsafe.Pointer(&buf))
+ onM(func() {
+ g0 := getg()
+ g0.writebuf = buf[0:0:len(buf)]
+ goroutineheader(gp)
+ traceback(pc, sp, 0, gp)
+ if all {
+ tracebackothers(gp)
+ }
+ n = len(g0.writebuf)
+ g0.writebuf = nil
+ })
}
if all {
@@ -623,7 +628,11 @@ func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) {
}
if gp.m.curg == nil || gp == gp.m.curg {
goroutineheader(gp)
- traceback(getcallerpc(unsafe.Pointer(&p)), getcallersp(unsafe.Pointer(&p)), 0, gp)
+ pc := getcallerpc(unsafe.Pointer(&p))
+ sp := getcallersp(unsafe.Pointer(&p))
+ onM(func() {
+ traceback(pc, sp, 0, gp)
+ })
} else {
goroutineheader(gp.m.curg)
traceback(^uintptr(0), ^uintptr(0), 0, gp.m.curg)
@@ -639,7 +648,11 @@ func tracefree(p unsafe.Pointer, size uintptr) {
gp.m.traceback = 2
print("tracefree(", p, ", ", hex(size), ")\n")
goroutineheader(gp)
- traceback(getcallerpc(unsafe.Pointer(&p)), getcallersp(unsafe.Pointer(&p)), 0, gp)
+ pc := getcallerpc(unsafe.Pointer(&p))
+ sp := getcallersp(unsafe.Pointer(&p))
+ onM(func() {
+ traceback(pc, sp, 0, gp)
+ })
print("\n")
gp.m.traceback = 0
unlock(&tracelock)
diff --git a/src/runtime/os_android.c b/src/runtime/os_android.c
index 58e0dac939..5805f68713 100644
--- a/src/runtime/os_android.c
+++ b/src/runtime/os_android.c
@@ -9,7 +9,7 @@
// Export the runtime entry point symbol.
//
// Used by the app package to start the Go runtime after loading
-// a shared library via JNI. See code.google.com/p/go.mobile/app.
+// a shared library via JNI. See golang.org/x/mobile/app.
void _rt0_arm_linux1();
#pragma cgo_export_static _rt0_arm_linux1
diff --git a/src/runtime/os_plan9_386.c b/src/runtime/os_plan9_386.c
index 3490862244..42c6d161c7 100644
--- a/src/runtime/os_plan9_386.c
+++ b/src/runtime/os_plan9_386.c
@@ -114,7 +114,7 @@ Throw:
if(runtime·gotraceback(&crash)) {
runtime·goroutineheader(gp);
- runtime·traceback(ureg->pc, ureg->sp, 0, gp);
+ runtime·tracebacktrap(ureg->pc, ureg->sp, 0, gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
runtime·dumpregs(ureg);
diff --git a/src/runtime/os_plan9_amd64.c b/src/runtime/os_plan9_amd64.c
index 6b0f8ae3a2..a9dc0eb966 100644
--- a/src/runtime/os_plan9_amd64.c
+++ b/src/runtime/os_plan9_amd64.c
@@ -122,7 +122,7 @@ Throw:
if(runtime·gotraceback(&crash)) {
runtime·goroutineheader(gp);
- runtime·traceback(ureg->ip, ureg->sp, 0, gp);
+ runtime·tracebacktrap(ureg->ip, ureg->sp, 0, gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
runtime·dumpregs(ureg);
diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c
index 213582799b..9962f0dc2e 100644
--- a/src/runtime/os_windows_386.c
+++ b/src/runtime/os_windows_386.c
@@ -97,7 +97,7 @@ runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
runtime·printf("\n");
if(runtime·gotraceback(&crash)){
- runtime·traceback(r->Eip, r->Esp, 0, gp);
+ runtime·tracebacktrap(r->Eip, r->Esp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(r);
}
diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c
index b96cf70d1e..e4617e4cef 100644
--- a/src/runtime/os_windows_amd64.c
+++ b/src/runtime/os_windows_amd64.c
@@ -119,7 +119,7 @@ runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
runtime·printf("\n");
if(runtime·gotraceback(&crash)){
- runtime·traceback(r->Rip, r->Rsp, 0, gp);
+ runtime·tracebacktrap(r->Rip, r->Rsp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(r);
}
diff --git a/src/runtime/proc.c b/src/runtime/proc.c
index c1df40d02f..ce39db4abb 100644
--- a/src/runtime/proc.c
+++ b/src/runtime/proc.c
@@ -994,7 +994,7 @@ runtime·newextram(void)
// the goroutine stack ends.
mp = runtime·allocm(nil);
gp = runtime·malg(4096);
- gp->sched.pc = (uintptr)runtime·goexit;
+ gp->sched.pc = (uintptr)runtime·goexit + PCQuantum;
gp->sched.sp = gp->stack.hi;
gp->sched.sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame
gp->sched.lr = 0;
@@ -1647,12 +1647,10 @@ runtime·gosched_m(G *gp)
}
// Finishes execution of the current goroutine.
-// Need to mark it as nosplit, because it runs with sp > stackbase.
-// Since it does not return it does not matter. But if it is preempted
-// at the split stack check, GC will complain about inconsistent sp.
+// Must be NOSPLIT because it is called from Go.
#pragma textflag NOSPLIT
void
-runtime·goexit(void)
+runtime·goexit1(void)
{
void (*fn)(G*);
@@ -2198,7 +2196,7 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
runtime·memclr((byte*)&newg->sched, sizeof newg->sched);
newg->sched.sp = (uintptr)sp;
- newg->sched.pc = (uintptr)runtime·goexit;
+ newg->sched.pc = (uintptr)runtime·goexit + PCQuantum; // +PCQuantum so that previous instruction is in same function
newg->sched.g = newg;
runtime·gostartcallfn(&newg->sched, fn);
newg->gopc = (uintptr)callerpc;
@@ -2432,9 +2430,10 @@ static struct ProfState {
int32 hz;
} prof;
-static void System(void) {}
-static void ExternalCode(void) {}
-static void GC(void) {}
+static void System(void) { System(); }
+static void ExternalCode(void) { ExternalCode(); }
+static void GC(void) { GC(); }
+
extern void runtime·cpuproftick(uintptr*, int32);
extern byte runtime·etext[];
@@ -2538,7 +2537,7 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
n = 0;
if(traceback)
- n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk, nelem(stk), nil, nil, false);
+ n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk, nelem(stk), nil, nil, TraceTrap);
if(!traceback || n <= 0) {
// Normal traceback is impossible or has failed.
// See if it falls into several common cases.
@@ -2548,13 +2547,13 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
// Cgo, we can't unwind and symbolize arbitrary C code,
// so instead collect Go stack that leads to the cgo call.
// This is especially important on windows, since all syscalls are cgo calls.
- n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->syscallsp, 0, mp->curg, 0, stk, nelem(stk), nil, nil, false);
+ n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->syscallsp, 0, mp->curg, 0, stk, nelem(stk), nil, nil, 0);
}
#ifdef GOOS_windows
if(n == 0 && mp->libcallg != nil && mp->libcallpc != 0 && mp->libcallsp != 0) {
// Libcall, i.e. runtime syscall on windows.
// Collect Go stack that leads to the call.
- n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0, mp->libcallg, 0, stk, nelem(stk), nil, nil, false);
+ n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0, mp->libcallg, 0, stk, nelem(stk), nil, nil, 0);
}
#endif
if(n == 0) {
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
index fec224390c..330ed429b9 100644
--- a/src/runtime/runtime.h
+++ b/src/runtime/runtime.h
@@ -737,9 +737,15 @@ struct Stkframe
BitVector* argmap; // force use of this argmap
};
-intgo runtime·gentraceback(uintptr, uintptr, uintptr, G*, intgo, uintptr*, intgo, bool(**)(Stkframe*, void*), void*, bool);
+enum
+{
+ TraceRuntimeFrames = 1<<0, // include frames for internal runtime functions.
+ TraceTrap = 1<<1, // the initial PC, SP are from a trap, not a return PC from a call
+};
+intgo runtime·gentraceback(uintptr, uintptr, uintptr, G*, intgo, uintptr*, intgo, bool(**)(Stkframe*, void*), void*, uintgo);
void runtime·tracebackdefers(G*, bool(**)(Stkframe*, void*), void*);
void runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G* gp);
+void runtime·tracebacktrap(uintptr pc, uintptr sp, uintptr lr, G* gp);
void runtime·tracebackothers(G*);
bool runtime·haszeroargs(uintptr pc);
bool runtime·topofstack(Func*);
diff --git a/src/runtime/sema.go b/src/runtime/sema.go
index a42a29988a..d2a028c01b 100644
--- a/src/runtime/sema.go
+++ b/src/runtime/sema.go
@@ -259,6 +259,7 @@ func syncsemrelease(s *syncSema, n uint32) {
}
s.tail = w
goparkunlock(&s.lock, "semarelease")
+ releaseSudog(w)
} else {
unlock(&s.lock)
}
diff --git a/src/runtime/signal_386.c b/src/runtime/signal_386.c
index d55e304528..30a7488bd7 100644
--- a/src/runtime/signal_386.c
+++ b/src/runtime/signal_386.c
@@ -109,7 +109,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(runtime·gotraceback(&crash)){
runtime·goroutineheader(gp);
- runtime·traceback(SIG_EIP(info, ctxt), SIG_ESP(info, ctxt), 0, gp);
+ runtime·tracebacktrap(SIG_EIP(info, ctxt), SIG_ESP(info, ctxt), 0, gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
runtime·dumpregs(info, ctxt);
diff --git a/src/runtime/signal_amd64x.c b/src/runtime/signal_amd64x.c
index 44e68cecfc..feb4afcce3 100644
--- a/src/runtime/signal_amd64x.c
+++ b/src/runtime/signal_amd64x.c
@@ -143,7 +143,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(runtime·gotraceback(&crash)){
runtime·goroutineheader(gp);
- runtime·traceback(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp);
+ runtime·tracebacktrap(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
runtime·dumpregs(info, ctxt);
diff --git a/src/runtime/signal_arm.c b/src/runtime/signal_arm.c
index 3571cf3ac6..afad5e7d16 100644
--- a/src/runtime/signal_arm.c
+++ b/src/runtime/signal_arm.c
@@ -108,7 +108,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(runtime·gotraceback(&crash)){
runtime·goroutineheader(gp);
- runtime·traceback(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LR(info, ctxt), gp);
+ runtime·tracebacktrap(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LR(info, ctxt), gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
runtime·dumpregs(info, ctxt);
diff --git a/src/runtime/stack.c b/src/runtime/stack.c
index a4947a53b3..ffae73a2ab 100644
--- a/src/runtime/stack.c
+++ b/src/runtime/stack.c
@@ -582,7 +582,7 @@ copystack(G *gp, uintptr newsize)
adjinfo.old = old;
adjinfo.delta = new.hi - old.hi;
cb = adjustframe;
- runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &adjinfo, false);
+ runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &adjinfo, 0);
// adjust other miscellaneous things that have pointers into stacks.
adjustctxt(gp, &adjinfo);
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index 421ab04e50..9889567d61 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -228,6 +228,34 @@ func atomicloaduint(ptr *uint) uint
//go:noescape
func setcallerpc(argp unsafe.Pointer, pc uintptr)
+// getcallerpc returns the program counter (PC) of its caller's caller.
+// getcallersp returns the stack pointer (SP) of its caller's caller.
+// For both, the argp must be a pointer to the caller's first function argument.
+// The implementation may or may not use argp, depending on
+// the architecture.
+//
+// For example:
+//
+// func f(arg1, arg2, arg3 int) {
+// pc := getcallerpc(unsafe.Pointer(&arg1))
+// sp := getcallerpc(unsafe.Pointer(&arg2))
+// }
+//
+// These two lines find the PC and SP immediately following
+// the call to f (where f will return).
+//
+// The call to getcallerpc and getcallersp must be done in the
+// frame being asked about. It would not be correct for f to pass &arg1
+// to another function g and let g call getcallerpc/getcallersp.
+// The call inside g might return information about g's caller or
+// information about f's caller or complete garbage.
+//
+// The result of getcallersp is correct at the time of the return,
+// but it may be invalidated by any subsequent call to a function
+// that might relocate the stack in order to grow or shrink it.
+// A general rule is that the result of getcallersp should be used
+// immediately and can only be passed to nosplit functions.
+
//go:noescape
func getcallerpc(argp unsafe.Pointer) uintptr
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 24dc3eea95..1c6ce6e644 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -96,11 +96,27 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
// the runtime.Callers function (pcbuf != nil), as well as the garbage
// collector (callback != nil). A little clunky to merge these, but avoids
// duplicating the code and all its subtlety.
-func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max int, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer, printall bool) int {
+func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max int, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer, flags uint) int {
if goexitPC == 0 {
gothrow("gentraceback before goexitPC initialization")
}
g := getg()
+ if g == gp && g == g.m.curg {
+ // The starting sp has been passed in as a uintptr, and the caller may
+ // have other uintptr-typed stack references as well.
+ // If during one of the calls that got us here or during one of the
+ // callbacks below the stack must be grown, all these uintptr references
+ // to the stack will not be updated, and gentraceback will continue
+ // to inspect the old stack memory, which may no longer be valid.
+ // Even if all the variables were updated correctly, it is not clear that
+ // we want to expose a traceback that begins on one stack and ends
+ // on another stack. That could confuse callers quite a bit.
+ // Instead, we require that gentraceback and any other function that
+ // accepts an sp for the current goroutine (typically obtained by
+ // calling getcallersp) must not run on that goroutine's stack but
+ // instead on the g0 stack.
+ gothrow("gentraceback cannot trace user goroutine on its own stack")
+ }
gotraceback := gotraceback(nil)
if pc0 == ^uintptr(0) && sp0 == ^uintptr(0) { // Signal to fetch saved values from gp.
if gp.syscallsp != 0 {
@@ -297,13 +313,13 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
}
}
if printing {
- if printall || showframe(f, gp) {
+ if (flags&_TraceRuntimeFrames) != 0 || showframe(f, gp) {
// Print during crash.
// main(0x1, 0x2, 0x3)
// /home/rsc/go/src/runtime/x.go:23 +0xf
//
tracepc := frame.pc // back up to CALL instruction for funcline.
- if n > 0 && frame.pc > f.entry && !waspanic {
+ if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry && !waspanic {
tracepc--
}
print(gofuncname(f), "(")
@@ -475,17 +491,32 @@ func printcreatedby(gp *g) {
}
func traceback(pc uintptr, sp uintptr, lr uintptr, gp *g) {
+ traceback1(pc, sp, lr, gp, 0)
+}
+
+// tracebacktrap is like traceback but expects that the PC and SP were obtained
+// from a trap, not from gp->sched or gp->syscallpc/gp->syscallsp or getcallerpc/getcallersp.
+// Because they are from a trap instead of from a saved pair,
+// the initial PC must not be rewound to the previous instruction.
+// (All the saved pairs record a PC that is a return address, so we
+// rewind it into the CALL instruction.)
+func tracebacktrap(pc uintptr, sp uintptr, lr uintptr, gp *g) {
+ traceback1(pc, sp, lr, gp, _TraceTrap)
+}
+
+func traceback1(pc uintptr, sp uintptr, lr uintptr, gp *g, flags uint) {
var n int
if readgstatus(gp)&^_Gscan == _Gsyscall {
- // Override signal registers if blocked in system call.
+ // Override registers if blocked in system call.
pc = gp.syscallpc
sp = gp.syscallsp
+ flags &^= _TraceTrap
}
// Print traceback. By default, omits runtime frames.
// If that means we print nothing at all, repeat forcing all frames printed.
- n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, false)
- if n == 0 {
- n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, true)
+ n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, flags)
+ if n == 0 && (flags&_TraceRuntimeFrames) == 0 {
+ n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, flags|_TraceRuntimeFrames)
}
if n == _TracebackMaxFrames {
print("...additional frames elided...\n")
@@ -496,11 +527,15 @@ func traceback(pc uintptr, sp uintptr, lr uintptr, gp *g) {
func callers(skip int, pcbuf *uintptr, m int) int {
sp := getcallersp(unsafe.Pointer(&skip))
pc := uintptr(getcallerpc(unsafe.Pointer(&skip)))
- return gentraceback(pc, sp, 0, getg(), skip, pcbuf, m, nil, nil, false)
+ var n int
+ onM(func() {
+ n = gentraceback(pc, sp, 0, getg(), skip, pcbuf, m, nil, nil, 0)
+ })
+ return n
}
func gcallers(gp *g, skip int, pcbuf *uintptr, m int) int {
- return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, pcbuf, m, nil, nil, false)
+ return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, pcbuf, m, nil, nil, 0)
}
func showframe(f *_func, gp *g) bool {