aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/sys_darwin.go
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2018-07-16 14:39:40 -0700
committerKeith Randall <khr@golang.org>2018-07-24 21:06:55 +0000
commitfe68ab3bcde97e3a325e4aa3c70f5f9172540453 (patch)
tree2181dfee533b37de34b2bab525c88f4104c34942 /src/runtime/sys_darwin.go
parent5fc70b6fac0664f3f9d2c2948ba78db420ba70c5 (diff)
downloadgo-fe68ab3bcde97e3a325e4aa3c70f5f9172540453.tar.gz
go-fe68ab3bcde97e3a325e4aa3c70f5f9172540453.zip
runtime: traceback from outermost libc call
If we're in a libc call and get a trap, don't try to traceback the libc call. Start from the state we had at entry to libc. If there are multiple libc calls outstanding, remember the outermost one. Fixes #26393 Change-Id: Icfe8794b95bf3bfd1a0679b456dcde2481dcabf3 Reviewed-on: https://go-review.googlesource.com/124195 Reviewed-by: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/runtime/sys_darwin.go')
-rw-r--r--src/runtime/sys_darwin.go20
1 files changed, 19 insertions, 1 deletions
diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go
index f0d0815903..7efbef746c 100644
--- a/src/runtime/sys_darwin.go
+++ b/src/runtime/sys_darwin.go
@@ -18,12 +18,30 @@ func libcCall(fn, arg unsafe.Pointer) int32 {
if gp != nil {
mp = gp.m
}
- if mp != nil {
+ if mp != nil && mp.libcallsp == 0 {
mp.libcallg.set(gp)
mp.libcallpc = getcallerpc()
// sp must be the last, because once async cpu profiler finds
// all three values to be non-zero, it will use them
mp.libcallsp = getcallersp()
+ } else {
+ // Make sure we don't reset libcallsp. This makes
+ // libcCall reentrant; We remember the g/pc/sp for the
+ // first call on an M, until that libcCall instance
+ // returns. Reentrance only matters for signals, as
+ // libc never calls back into Go. The tricky case is
+ // where we call libcX from an M and record g/pc/sp.
+ // Before that call returns, a signal arrives on the
+ // same M and the signal handling code calls another
+ // libc function. We don't want that second libcCall
+ // from within the handler to be recorded, and we
+ // don't want that call's completion to zero
+ // libcallsp.
+ // We don't need to set libcall* while we're in a sighandler
+ // (even if we're not currently in libc) because we block all
+ // signals while we're handling a signal. That includes the
+ // profile signal, which is the one that uses the libcall* info.
+ mp = nil
}
res := asmcgocall(fn, arg)
if mp != nil {