runtime: set libcall values for Solaris system calls

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>
This commit is contained in:
Ian Lance Taylor 2018-03-08 12:37:01 -08:00
parent 8e427a3878
commit 4902778607
2 changed files with 120 additions and 1 deletions

View 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
}

View 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)