]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: set libcall values for Solaris system calls
authorIan Lance Taylor <iant@golang.org>
Thu, 8 Mar 2018 20:37:01 +0000 (12:37 -0800)
committerIan Lance Taylor <iant@golang.org>
Fri, 9 Mar 2018 19:27:20 +0000 (19:27 +0000)
This lets SIGPROF signals get a useful traceback.
Without it we just see sysvicallN calling asmcgocall.

Updates #24142

Change-Id: I5dfe3add51f0c3a4cb1c98acb7738be6396214bc
Reviewed-on: https://go-review.googlesource.com/99617
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
src/runtime/os_solaris.go
src/runtime/proc.go

index 0c3971576cc2cd4d3857348d696b1e222311912e..d698e09e7d5fa2dd3ce62bbefe182ef196f646fd 100644 (file)
@@ -31,71 +31,190 @@ var asmsysvicall6 libcFunc
 
 //go:nosplit
 func sysvicall0(fn *libcFunc) uintptr {
+       // Leave caller's PC/SP around for traceback.
+       gp := getg()
+       var mp *m
+       if gp != nil {
+               mp = gp.m
+       }
+       if mp != nil {
+               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(unsafe.Pointer(&fn))
+       }
+
        var libcall libcall
        libcall.fn = uintptr(unsafe.Pointer(fn))
        libcall.n = 0
        libcall.args = uintptr(unsafe.Pointer(fn)) // it's unused but must be non-nil, otherwise crashes
        asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&libcall))
+       if mp != nil {
+               mp.libcallsp = 0
+       }
        return libcall.r1
 }
 
 //go:nosplit
 func sysvicall1(fn *libcFunc, a1 uintptr) uintptr {
+       // Leave caller's PC/SP around for traceback.
+       gp := getg()
+       var mp *m
+       if gp != nil {
+               mp = gp.m
+       }
+       if mp != nil {
+               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(unsafe.Pointer(&fn))
+       }
+
        var libcall libcall
        libcall.fn = uintptr(unsafe.Pointer(fn))
        libcall.n = 1
        // TODO(rsc): Why is noescape necessary here and below?
        libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
        asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&libcall))
+       if mp != nil {
+               mp.libcallsp = 0
+       }
        return libcall.r1
 }
 
 //go:nosplit
 func sysvicall2(fn *libcFunc, a1, a2 uintptr) uintptr {
+       // Leave caller's PC/SP around for traceback.
+       gp := getg()
+       var mp *m
+       if gp != nil {
+               mp = gp.m
+       }
+       if mp != nil {
+               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(unsafe.Pointer(&fn))
+       }
+
        var libcall libcall
        libcall.fn = uintptr(unsafe.Pointer(fn))
        libcall.n = 2
        libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
        asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&libcall))
+       if mp != nil {
+               mp.libcallsp = 0
+       }
        return libcall.r1
 }
 
 //go:nosplit
 func sysvicall3(fn *libcFunc, a1, a2, a3 uintptr) uintptr {
+       // Leave caller's PC/SP around for traceback.
+       gp := getg()
+       var mp *m
+       if gp != nil {
+               mp = gp.m
+       }
+       if mp != nil {
+               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(unsafe.Pointer(&fn))
+       }
+
        var libcall libcall
        libcall.fn = uintptr(unsafe.Pointer(fn))
        libcall.n = 3
        libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
        asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&libcall))
+       if mp != nil {
+               mp.libcallsp = 0
+       }
        return libcall.r1
 }
 
 //go:nosplit
 func sysvicall4(fn *libcFunc, a1, a2, a3, a4 uintptr) uintptr {
+       // Leave caller's PC/SP around for traceback.
+       gp := getg()
+       var mp *m
+       if gp != nil {
+               mp = gp.m
+       }
+       if mp != nil {
+               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(unsafe.Pointer(&fn))
+       }
+
        var libcall libcall
        libcall.fn = uintptr(unsafe.Pointer(fn))
        libcall.n = 4
        libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
        asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&libcall))
+       if mp != nil {
+               mp.libcallsp = 0
+       }
        return libcall.r1
 }
 
 //go:nosplit
 func sysvicall5(fn *libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr {
+       // Leave caller's PC/SP around for traceback.
+       gp := getg()
+       var mp *m
+       if gp != nil {
+               mp = gp.m
+       }
+       if mp != nil {
+               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(unsafe.Pointer(&fn))
+       }
+
        var libcall libcall
        libcall.fn = uintptr(unsafe.Pointer(fn))
        libcall.n = 5
        libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
        asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&libcall))
+       if mp != nil {
+               mp.libcallsp = 0
+       }
        return libcall.r1
 }
 
 //go:nosplit
 func sysvicall6(fn *libcFunc, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
+       // Leave caller's PC/SP around for traceback.
+       gp := getg()
+       var mp *m
+       if gp != nil {
+               mp = gp.m
+       }
+       if mp != nil {
+               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(unsafe.Pointer(&fn))
+       }
+
        var libcall libcall
        libcall.fn = uintptr(unsafe.Pointer(fn))
        libcall.n = 6
        libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
        asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&libcall))
+       if mp != nil {
+               mp.libcallsp = 0
+       }
        return libcall.r1
 }
index 9ed8c14e7a5e69f92eb437b181ceabe3d1d4ba54..008bd244e06089017a7cff65d145796c7e22f761 100644 (file)
@@ -3697,7 +3697,7 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
                // Normal traceback is impossible or has failed.
                // See if it falls into several common cases.
                n = 0
-               if GOOS == "windows" && mp.libcallg != 0 && mp.libcallpc != 0 && mp.libcallsp != 0 {
+               if (GOOS == "windows" || GOOS == "solaris") && mp.libcallg != 0 && mp.libcallpc != 0 && mp.libcallsp != 0 {
                        // Libcall, i.e. runtime syscall on windows.
                        // Collect Go stack that leads to the call.
                        n = gentraceback(mp.libcallpc, mp.libcallsp, 0, mp.libcallg.ptr(), 0, &stk[0], len(stk), nil, nil, 0)