]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: traceback from outermost libc call
authorKeith Randall <khr@golang.org>
Mon, 16 Jul 2018 21:39:40 +0000 (14:39 -0700)
committerKeith Randall <khr@golang.org>
Tue, 24 Jul 2018 21:06:55 +0000 (21:06 +0000)
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>

src/runtime/os_solaris.go
src/runtime/os_windows.go
src/runtime/sys_darwin.go
src/runtime/traceback.go

index 703a2e54301e92cc482e646e1b4ee8fe44b562ee..4575b5e641c150f28df522aa447418395bc8eed9 100644 (file)
@@ -37,12 +37,14 @@ func sysvicall0(fn *libcFunc) uintptr {
        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 {
+               mp = nil // See comment in sys_darwin.go:libcCall
        }
 
        var libcall libcall
@@ -64,12 +66,14 @@ func sysvicall1(fn *libcFunc, a1 uintptr) uintptr {
        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 {
+               mp = nil
        }
 
        var libcall libcall
@@ -92,12 +96,14 @@ func sysvicall2(fn *libcFunc, a1, a2 uintptr) uintptr {
        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 {
+               mp = nil
        }
 
        var libcall libcall
@@ -119,12 +125,14 @@ func sysvicall3(fn *libcFunc, a1, a2, a3 uintptr) uintptr {
        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 {
+               mp = nil
        }
 
        var libcall libcall
@@ -146,12 +154,14 @@ func sysvicall4(fn *libcFunc, a1, a2, a3, a4 uintptr) uintptr {
        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 {
+               mp = nil
        }
 
        var libcall libcall
@@ -173,12 +183,14 @@ func sysvicall5(fn *libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr {
        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 {
+               mp = nil
        }
 
        var libcall libcall
@@ -200,12 +212,14 @@ func sysvicall6(fn *libcFunc, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
        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 {
+               mp = nil
        }
 
        var libcall libcall
index 6180dd3a60aa5391e77eebc8e0d241fd8ece963d..5607bf95c1d59f093765126ef3dbeecc74c34c53 100644 (file)
@@ -734,17 +734,20 @@ func stdcall(fn stdFunction) uintptr {
        gp := getg()
        mp := gp.m
        mp.libcall.fn = uintptr(unsafe.Pointer(fn))
-
-       if mp.profilehz != 0 {
+       resetLibcall := false
+       if mp.profilehz != 0 && mp.libcallsp == 0 {
                // leave pc/sp for cpu profiler
                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()
+               resetLibcall = true // See comment in sys_darwin.go:libcCall
        }
        asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
-       mp.libcallsp = 0
+       if resetLibcall {
+               mp.libcallsp = 0
+       }
        return mp.libcall.r1
 }
 
index f0d0815903fe9b6057af514d56891fcd3c4c5485..7efbef746cd83867e7dbf0c75f043b20e6e075f2 100644 (file)
@@ -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 {
index 495365390087bd446cfbb1113fb764606ea96285..d8c225d975fa28ed535d20bf0d8db6625683cf4e 100644 (file)
@@ -679,7 +679,14 @@ func traceback(pc, sp, lr uintptr, gp *g) {
 // 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.)
+// If gp.m.libcall{g,pc,sp} information is available, it uses that information in preference to
+// the pc/sp/lr passed in.
 func tracebacktrap(pc, sp, lr uintptr, gp *g) {
+       if gp.m.libcallsp != 0 {
+               // We're in C code somewhere, traceback from the saved position.
+               traceback1(gp.m.libcallpc, gp.m.libcallsp, 0, gp.m.libcallg.ptr(), 0)
+               return
+       }
        traceback1(pc, sp, lr, gp, _TraceTrap)
 }