mirror of
https://github.com/golang/go
synced 2024-11-23 14:00:03 -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
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
// +build darwin linux
|
||||
|
||||
package cgo
|
||||
|
||||
|
@ -2,17 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build cgo
|
||||
// +build linux
|
||||
// +build cgo,darwin cgo,linux
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct cgoTracebackArg {
|
||||
uintptr_t Context;
|
||||
uintptr_t SigContext;
|
||||
uintptr_t* Buf;
|
||||
uintptr_t Max;
|
||||
};
|
||||
#include "libcgo.h"
|
||||
|
||||
// Call the user's traceback function and then call sigtramp.
|
||||
// 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*);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* CGO_CFLAGS="-fsanitize=thread" CGO_LDFLAGS="-fsanitize=thread" go install
|
||||
|
@ -239,8 +239,12 @@ func TestCgoCCodeSIGPROF(t *testing.T) {
|
||||
|
||||
func TestCgoCrashTraceback(t *testing.T) {
|
||||
t.Parallel()
|
||||
if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") {
|
||||
t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
|
||||
case "darwin/amd64":
|
||||
case "linux/amd64":
|
||||
case "linux/ppc64le":
|
||||
default:
|
||||
t.Skipf("not yet supported on %s", platform)
|
||||
}
|
||||
got := runTestProg(t, "testprogcgo", "CrashTraceback")
|
||||
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_mask = ^uint32(0)
|
||||
if fn == funcPC(sighandler) {
|
||||
fn = funcPC(sigtramp)
|
||||
if iscgo {
|
||||
fn = funcPC(cgoSigtramp)
|
||||
} else {
|
||||
fn = funcPC(sigtramp)
|
||||
}
|
||||
}
|
||||
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
|
||||
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.
|
||||
// It is called with the C calling convention.
|
||||
func sigtramp()
|
||||
func cgoSigtramp()
|
||||
|
||||
//go:nosplit
|
||||
//go:nowritebarrierrec
|
||||
|
@ -326,6 +326,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
|
||||
ADDL $28, SP
|
||||
RET
|
||||
|
||||
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
|
||||
JMP runtime·sigtramp(SB)
|
||||
|
||||
TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
|
||||
PUSHL BP
|
||||
MOVL SP, BP
|
||||
|
@ -215,6 +215,82 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
|
||||
POPQ BP
|
||||
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
|
||||
PUSHQ BP // make a frame; keep stack aligned
|
||||
MOVQ SP, BP
|
||||
|
@ -227,6 +227,9 @@ nog:
|
||||
|
||||
RET
|
||||
|
||||
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
|
||||
JMP runtime·sigtramp(SB)
|
||||
|
||||
TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
|
||||
MOVW 4(R0), R1 // arg 2 new
|
||||
MOVW 8(R0), R2 // arg 3 old
|
||||
|
@ -223,6 +223,9 @@ nog:
|
||||
|
||||
RET
|
||||
|
||||
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
|
||||
JMP runtime·sigtramp(SB)
|
||||
|
||||
TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
|
||||
MOVD 8(R0), R1 // arg 2 new
|
||||
MOVD 16(R0), R2 // arg 3 old
|
||||
|
Loading…
Reference in New Issue
Block a user