1
0
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:
Nikhil Benesch 2018-03-24 18:51:01 -04:00 committed by Ian Lance Taylor
parent ad4e6370fe
commit 5929ead6fb
9 changed files with 110 additions and 13 deletions

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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++ {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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