diff options
author | Keith Randall <khr@golang.org> | 2018-07-16 14:39:40 -0700 |
---|---|---|
committer | Keith Randall <khr@golang.org> | 2018-07-24 21:06:55 +0000 |
commit | fe68ab3bcde97e3a325e4aa3c70f5f9172540453 (patch) | |
tree | 2181dfee533b37de34b2bab525c88f4104c34942 /src/runtime/sys_darwin.go | |
parent | 5fc70b6fac0664f3f9d2c2948ba78db420ba70c5 (diff) | |
download | go-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.go | 20 |
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 { |