mirror of
https://github.com/golang/go
synced 2024-11-06 07:26:10 -07:00
runtime: support capturing C backtrace from signal handler on darwin/amd64
The implementation is mostly copied from the commit that added linux/amd64 support for this feature (https://golang.org/cl/17761). Change-Id: I3f482167620a7a3daf50a48087f8849a30d713bd Reviewed-on: https://go-review.googlesource.com/102438 Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
ad4e6370fe
commit
5929ead6fb
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build linux
|
// +build darwin linux
|
||||||
|
|
||||||
package cgo
|
package cgo
|
||||||
|
|
||||||
|
@ -2,17 +2,10 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build cgo
|
// +build cgo,darwin cgo,linux
|
||||||
// +build linux
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "libcgo.h"
|
||||||
struct cgoTracebackArg {
|
|
||||||
uintptr_t Context;
|
|
||||||
uintptr_t SigContext;
|
|
||||||
uintptr_t* Buf;
|
|
||||||
uintptr_t Max;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Call the user's traceback function and then call sigtramp.
|
// Call the user's traceback function and then call sigtramp.
|
||||||
// The runtime signal handler will jump to this code.
|
// The runtime signal handler will jump to this code.
|
||||||
|
@ -96,6 +96,16 @@ struct context_arg {
|
|||||||
};
|
};
|
||||||
extern void (*(_cgo_get_context_function(void)))(struct context_arg*);
|
extern void (*(_cgo_get_context_function(void)))(struct context_arg*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The argument for the cgo traceback callback. See runtime.SetCgoTraceback.
|
||||||
|
*/
|
||||||
|
struct cgoTracebackArg {
|
||||||
|
uintptr_t Context;
|
||||||
|
uintptr_t SigContext;
|
||||||
|
uintptr_t* Buf;
|
||||||
|
uintptr_t Max;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TSAN support. This is only useful when building with
|
* TSAN support. This is only useful when building with
|
||||||
* CGO_CFLAGS="-fsanitize=thread" CGO_LDFLAGS="-fsanitize=thread" go install
|
* CGO_CFLAGS="-fsanitize=thread" CGO_LDFLAGS="-fsanitize=thread" go install
|
||||||
|
@ -239,8 +239,12 @@ func TestCgoCCodeSIGPROF(t *testing.T) {
|
|||||||
|
|
||||||
func TestCgoCrashTraceback(t *testing.T) {
|
func TestCgoCrashTraceback(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") {
|
switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
|
||||||
t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
|
case "darwin/amd64":
|
||||||
|
case "linux/amd64":
|
||||||
|
case "linux/ppc64le":
|
||||||
|
default:
|
||||||
|
t.Skipf("not yet supported on %s", platform)
|
||||||
}
|
}
|
||||||
got := runTestProg(t, "testprogcgo", "CrashTraceback")
|
got := runTestProg(t, "testprogcgo", "CrashTraceback")
|
||||||
for i := 1; i <= 3; i++ {
|
for i := 1; i <= 3; i++ {
|
||||||
|
@ -274,7 +274,11 @@ func setsig(i uint32, fn uintptr) {
|
|||||||
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
|
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
|
||||||
sa.sa_mask = ^uint32(0)
|
sa.sa_mask = ^uint32(0)
|
||||||
if fn == funcPC(sighandler) {
|
if fn == funcPC(sighandler) {
|
||||||
fn = funcPC(sigtramp)
|
if iscgo {
|
||||||
|
fn = funcPC(cgoSigtramp)
|
||||||
|
} else {
|
||||||
|
fn = funcPC(sigtramp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
|
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
|
||||||
sigaction(i, &sa, nil)
|
sigaction(i, &sa, nil)
|
||||||
@ -283,6 +287,7 @@ func setsig(i uint32, fn uintptr) {
|
|||||||
// sigtramp is the callback from libc when a signal is received.
|
// sigtramp is the callback from libc when a signal is received.
|
||||||
// It is called with the C calling convention.
|
// It is called with the C calling convention.
|
||||||
func sigtramp()
|
func sigtramp()
|
||||||
|
func cgoSigtramp()
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
//go:nowritebarrierrec
|
//go:nowritebarrierrec
|
||||||
|
@ -326,6 +326,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
|
|||||||
ADDL $28, SP
|
ADDL $28, SP
|
||||||
RET
|
RET
|
||||||
|
|
||||||
|
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
|
||||||
|
JMP runtime·sigtramp(SB)
|
||||||
|
|
||||||
TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
|
TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
|
||||||
PUSHL BP
|
PUSHL BP
|
||||||
MOVL SP, BP
|
MOVL SP, BP
|
||||||
|
@ -215,6 +215,82 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
|
|||||||
POPQ BP
|
POPQ BP
|
||||||
RET
|
RET
|
||||||
|
|
||||||
|
// Used instead of sigtramp in programs that use cgo.
|
||||||
|
// Arguments from kernel are in DI, SI, DX.
|
||||||
|
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
|
||||||
|
// If no traceback function, do usual sigtramp.
|
||||||
|
MOVQ runtime·cgoTraceback(SB), AX
|
||||||
|
TESTQ AX, AX
|
||||||
|
JZ sigtramp
|
||||||
|
|
||||||
|
// If no traceback support function, which means that
|
||||||
|
// runtime/cgo was not linked in, do usual sigtramp.
|
||||||
|
MOVQ _cgo_callers(SB), AX
|
||||||
|
TESTQ AX, AX
|
||||||
|
JZ sigtramp
|
||||||
|
|
||||||
|
// Figure out if we are currently in a cgo call.
|
||||||
|
// If not, just do usual sigtramp.
|
||||||
|
get_tls(CX)
|
||||||
|
MOVQ g(CX),AX
|
||||||
|
TESTQ AX, AX
|
||||||
|
JZ sigtrampnog // g == nil
|
||||||
|
MOVQ g_m(AX), AX
|
||||||
|
TESTQ AX, AX
|
||||||
|
JZ sigtramp // g.m == nil
|
||||||
|
MOVL m_ncgo(AX), CX
|
||||||
|
TESTL CX, CX
|
||||||
|
JZ sigtramp // g.m.ncgo == 0
|
||||||
|
MOVQ m_curg(AX), CX
|
||||||
|
TESTQ CX, CX
|
||||||
|
JZ sigtramp // g.m.curg == nil
|
||||||
|
MOVQ g_syscallsp(CX), CX
|
||||||
|
TESTQ CX, CX
|
||||||
|
JZ sigtramp // g.m.curg.syscallsp == 0
|
||||||
|
MOVQ m_cgoCallers(AX), R8
|
||||||
|
TESTQ R8, R8
|
||||||
|
JZ sigtramp // g.m.cgoCallers == nil
|
||||||
|
MOVL m_cgoCallersUse(AX), CX
|
||||||
|
TESTL CX, CX
|
||||||
|
JNZ sigtramp // g.m.cgoCallersUse != 0
|
||||||
|
|
||||||
|
// Jump to a function in runtime/cgo.
|
||||||
|
// That function, written in C, will call the user's traceback
|
||||||
|
// function with proper unwind info, and will then call back here.
|
||||||
|
// The first three arguments, and the fifth, are already in registers.
|
||||||
|
// Set the two remaining arguments now.
|
||||||
|
MOVQ runtime·cgoTraceback(SB), CX
|
||||||
|
MOVQ $runtime·sigtramp(SB), R9
|
||||||
|
MOVQ _cgo_callers(SB), AX
|
||||||
|
JMP AX
|
||||||
|
|
||||||
|
sigtramp:
|
||||||
|
JMP runtime·sigtramp(SB)
|
||||||
|
|
||||||
|
sigtrampnog:
|
||||||
|
// Signal arrived on a non-Go thread. If this is SIGPROF, get a
|
||||||
|
// stack trace.
|
||||||
|
CMPL DI, $27 // 27 == SIGPROF
|
||||||
|
JNZ sigtramp
|
||||||
|
|
||||||
|
// Lock sigprofCallersUse.
|
||||||
|
MOVL $0, AX
|
||||||
|
MOVL $1, CX
|
||||||
|
MOVQ $runtime·sigprofCallersUse(SB), R11
|
||||||
|
LOCK
|
||||||
|
CMPXCHGL CX, 0(R11)
|
||||||
|
JNZ sigtramp // Skip stack trace if already locked.
|
||||||
|
|
||||||
|
// Jump to the traceback function in runtime/cgo.
|
||||||
|
// It will call back to sigprofNonGo, which will ignore the
|
||||||
|
// arguments passed in registers.
|
||||||
|
// First three arguments to traceback function are in registers already.
|
||||||
|
MOVQ runtime·cgoTraceback(SB), CX
|
||||||
|
MOVQ $runtime·sigprofCallers(SB), R8
|
||||||
|
MOVQ $runtime·sigprofNonGo(SB), R9
|
||||||
|
MOVQ _cgo_callers(SB), AX
|
||||||
|
JMP AX
|
||||||
|
|
||||||
TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
|
TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
|
||||||
PUSHQ BP // make a frame; keep stack aligned
|
PUSHQ BP // make a frame; keep stack aligned
|
||||||
MOVQ SP, BP
|
MOVQ SP, BP
|
||||||
|
@ -227,6 +227,9 @@ nog:
|
|||||||
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
|
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
|
||||||
|
JMP runtime·sigtramp(SB)
|
||||||
|
|
||||||
TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
|
TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
|
||||||
MOVW 4(R0), R1 // arg 2 new
|
MOVW 4(R0), R1 // arg 2 new
|
||||||
MOVW 8(R0), R2 // arg 3 old
|
MOVW 8(R0), R2 // arg 3 old
|
||||||
|
@ -223,6 +223,9 @@ nog:
|
|||||||
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
|
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
|
||||||
|
JMP runtime·sigtramp(SB)
|
||||||
|
|
||||||
TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
|
TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
|
||||||
MOVD 8(R0), R1 // arg 2 new
|
MOVD 8(R0), R1 // arg 2 new
|
||||||
MOVD 16(R0), R2 // arg 3 old
|
MOVD 16(R0), R2 // arg 3 old
|
||||||
|
Loading…
Reference in New Issue
Block a user