aboutsummaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
Diffstat (limited to 'libgo')
-rw-r--r--libgo/go/runtime/cgo_gccgo.go4
-rw-r--r--libgo/go/runtime/proc.go3
-rw-r--r--libgo/go/runtime/runtime2.go1
-rw-r--r--libgo/go/runtime/stubs.go4
-rw-r--r--libgo/runtime/go-unwind.c62
5 files changed, 58 insertions, 16 deletions
diff --git a/libgo/go/runtime/cgo_gccgo.go b/libgo/go/runtime/cgo_gccgo.go
index aff8130..e4d27e8 100644
--- a/libgo/go/runtime/cgo_gccgo.go
+++ b/libgo/go/runtime/cgo_gccgo.go
@@ -80,6 +80,10 @@ func CgocallBack() {
gp = getg()
mp := gp.m
mp.dropextram = true
+
+ // This is a C-created stack.
+ // Record the outermost Go frame to help stack scan.
+ gp.entrysp = getcallersp()
}
lockOSThread()
diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go
index e937563..1c944d6 100644
--- a/libgo/go/runtime/proc.go
+++ b/libgo/go/runtime/proc.go
@@ -1192,6 +1192,9 @@ func kickoff() {
gp.param = nil
}
+ // Record the entry SP to help stack scan.
+ gp.entrysp = getsp()
+
fv(param)
goexit1()
}
diff --git a/libgo/go/runtime/runtime2.go b/libgo/go/runtime/runtime2.go
index 4cd68da..4f823e0 100644
--- a/libgo/go/runtime/runtime2.go
+++ b/libgo/go/runtime/runtime2.go
@@ -433,6 +433,7 @@ type g struct {
entry func(unsafe.Pointer) // goroutine function to run
entryfn uintptr // function address passed to __go_go
+ entrysp uintptr // the stack pointer of the outermost Go frame
fromgogo bool // whether entered from gogo function
scanningself bool // whether goroutine is scanning its own stack
diff --git a/libgo/go/runtime/stubs.go b/libgo/go/runtime/stubs.go
index 9f5191b..dfdb38e 100644
--- a/libgo/go/runtime/stubs.go
+++ b/libgo/go/runtime/stubs.go
@@ -231,6 +231,10 @@ func getcallerpc() uintptr
//go:noescape
func getcallersp() uintptr // implemented as an intrinsic on all platforms
+// getsp returns the stack pointer (SP) of the caller of getsp.
+//go:noinline
+func getsp() uintptr { return getcallersp() }
+
func asmcgocall(fn, arg unsafe.Pointer) int32 {
throw("asmcgocall")
return 0
diff --git a/libgo/runtime/go-unwind.c b/libgo/runtime/go-unwind.c
index 158cbd0..9fd9596 100644
--- a/libgo/runtime/go-unwind.c
+++ b/libgo/runtime/go-unwind.c
@@ -649,6 +649,19 @@ findstackmaps (struct _Unwind_Context *context, _Unwind_Ptr *ip, _Unwind_Ptr *sp
_sleb128_t index;
int size;
+#ifdef HAVE_GETIPINFO
+ ip1 = _Unwind_GetIPInfo (context, &ip_before_insn);
+#else
+ ip1 = _Unwind_GetIP (context);
+#endif
+ if (! ip_before_insn)
+ --ip1;
+
+ if (ip != NULL)
+ *ip = ip1;
+ if (sp != NULL)
+ *sp = _Unwind_GetCFA (context);
+
#ifdef __ARM_EABI_UNWINDER__
{
_Unwind_Control_Block *ucbp;
@@ -672,14 +685,6 @@ findstackmaps (struct _Unwind_Context *context, _Unwind_Ptr *ip, _Unwind_Ptr *sp
if (info.TType == NULL)
return NOTFOUND_OK;
-#ifdef HAVE_GETIPINFO
- ip1 = _Unwind_GetIPInfo (context, &ip_before_insn);
-#else
- ip1 = _Unwind_GetIP (context);
-#endif
- if (! ip_before_insn)
- --ip1;
-
size = value_size (info.ttype_encoding);
action_record = NULL;
@@ -738,15 +743,16 @@ findstackmaps (struct _Unwind_Context *context, _Unwind_Ptr *ip, _Unwind_Ptr *sp
if (stackmap1 == NULL)
return NOTFOUND_BAD;
- if (ip != NULL)
- *ip = ip1;
- if (sp != NULL)
- *sp = _Unwind_GetCFA (context);
if (stackmap != NULL)
*stackmap = stackmap1;
return FOUND;
}
+struct scanstate {
+ void* gcw; // the GC worker, passed into scanstackwithmap_callback
+ uintptr lastsp; // the last (outermost) SP of Go function seen in a traceback, set by the callback
+};
+
// Callback function to scan a stack frame with stack maps.
// It skips non-Go functions.
static _Unwind_Reason_Code
@@ -755,7 +761,11 @@ scanstackwithmap_callback (struct _Unwind_Context *context, void *arg)
struct _stackmap *stackmap;
_Unwind_Ptr ip, sp;
G* gp;
- void *gcw = arg;
+ struct scanstate* state = (struct scanstate*) arg;
+ void *gcw;
+
+ gp = runtime_g ();
+ gcw = state->gcw;
switch (findstackmaps (context, &ip, &sp, &stackmap))
{
@@ -767,7 +777,6 @@ scanstackwithmap_callback (struct _Unwind_Context *context, void *arg)
// No stack map found.
// If we're scanning from the signal stack, the goroutine
// may be not stopped at a safepoint. Allow this case.
- gp = runtime_g ();
if (gp != gp->m->gsignal)
{
// TODO: print gp, pc, sp
@@ -781,6 +790,7 @@ scanstackwithmap_callback (struct _Unwind_Context *context, void *arg)
abort ();
}
+ state->lastsp = sp;
runtime_scanstackblockwithmap (ip, sp, (uintptr)(stackmap->len) * sizeof(uintptr), stackmap->data, gcw);
return _URC_NO_REASON;
@@ -792,10 +802,30 @@ bool
scanstackwithmap (void *gcw)
{
_Unwind_Reason_Code code;
+ bool ret;
+ struct scanstate state;
+ G* gp;
+ G* curg;
+
+ state.gcw = gcw;
+ state.lastsp = 0;
+ gp = runtime_g ();
+ curg = gp->m->curg;
+
runtime_xadd (&__go_runtime_in_callers, 1);
- code = _Unwind_Backtrace (scanstackwithmap_callback, gcw);
+ code = _Unwind_Backtrace (scanstackwithmap_callback, (void*)&state);
runtime_xadd (&__go_runtime_in_callers, -1);
- return code == _URC_END_OF_STACK;
+ ret = (code == _URC_END_OF_STACK);
+ if (ret && gp == gp->m->gsignal)
+ {
+ // For signal-triggered scan, the unwinder may not be able to unwind
+ // the whole stack while it still reports _URC_END_OF_STACK (e.g.
+ // signal is delivered in vdso). Check that we actually reached the
+ // the end of the stack, that is, the SP on entry.
+ if (state.lastsp != curg->entrysp)
+ ret = false;
+ }
+ return ret;
}
// Returns whether stack map is enabled.