Skip to content

Commit 5929ead

Browse files
beneschianlancetaylor
authored andcommitted
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 <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent ad4e637 commit 5929ead

9 files changed

+110
-13
lines changed

src/runtime/cgo/callbacks_traceback.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
// +build linux
5+
// +build darwin linux
66

77
package cgo
88

src/runtime/cgo/gcc_traceback.c

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,10 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
// +build cgo
6-
// +build linux
5+
// +build cgo,darwin cgo,linux
76

87
#include <stdint.h>
9-
10-
struct cgoTracebackArg {
11-
uintptr_t Context;
12-
uintptr_t SigContext;
13-
uintptr_t* Buf;
14-
uintptr_t Max;
15-
};
8+
#include "libcgo.h"
169

1710
// Call the user's traceback function and then call sigtramp.
1811
// The runtime signal handler will jump to this code.

src/runtime/cgo/libcgo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,16 @@ struct context_arg {
9696
};
9797
extern void (*(_cgo_get_context_function(void)))(struct context_arg*);
9898

99+
/*
100+
* The argument for the cgo traceback callback. See runtime.SetCgoTraceback.
101+
*/
102+
struct cgoTracebackArg {
103+
uintptr_t Context;
104+
uintptr_t SigContext;
105+
uintptr_t* Buf;
106+
uintptr_t Max;
107+
};
108+
99109
/*
100110
* TSAN support. This is only useful when building with
101111
* CGO_CFLAGS="-fsanitize=thread" CGO_LDFLAGS="-fsanitize=thread" go install

src/runtime/crash_cgo_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,12 @@ func TestCgoCCodeSIGPROF(t *testing.T) {
239239

240240
func TestCgoCrashTraceback(t *testing.T) {
241241
t.Parallel()
242-
if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") {
243-
t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
242+
switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
243+
case "darwin/amd64":
244+
case "linux/amd64":
245+
case "linux/ppc64le":
246+
default:
247+
t.Skipf("not yet supported on %s", platform)
244248
}
245249
got := runTestProg(t, "testprogcgo", "CrashTraceback")
246250
for i := 1; i <= 3; i++ {

src/runtime/os_darwin.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,11 @@ func setsig(i uint32, fn uintptr) {
274274
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
275275
sa.sa_mask = ^uint32(0)
276276
if fn == funcPC(sighandler) {
277-
fn = funcPC(sigtramp)
277+
if iscgo {
278+
fn = funcPC(cgoSigtramp)
279+
} else {
280+
fn = funcPC(sigtramp)
281+
}
278282
}
279283
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
280284
sigaction(i, &sa, nil)
@@ -283,6 +287,7 @@ func setsig(i uint32, fn uintptr) {
283287
// sigtramp is the callback from libc when a signal is received.
284288
// It is called with the C calling convention.
285289
func sigtramp()
290+
func cgoSigtramp()
286291

287292
//go:nosplit
288293
//go:nowritebarrierrec

src/runtime/sys_darwin_386.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
326326
ADDL $28, SP
327327
RET
328328

329+
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
330+
JMP runtime·sigtramp(SB)
331+
329332
TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
330333
PUSHL BP
331334
MOVL SP, BP

src/runtime/sys_darwin_amd64.s

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,82 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
215215
POPQ BP
216216
RET
217217

218+
// Used instead of sigtramp in programs that use cgo.
219+
// Arguments from kernel are in DI, SI, DX.
220+
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
221+
// If no traceback function, do usual sigtramp.
222+
MOVQ runtime·cgoTraceback(SB), AX
223+
TESTQ AX, AX
224+
JZ sigtramp
225+
226+
// If no traceback support function, which means that
227+
// runtime/cgo was not linked in, do usual sigtramp.
228+
MOVQ _cgo_callers(SB), AX
229+
TESTQ AX, AX
230+
JZ sigtramp
231+
232+
// Figure out if we are currently in a cgo call.
233+
// If not, just do usual sigtramp.
234+
get_tls(CX)
235+
MOVQ g(CX),AX
236+
TESTQ AX, AX
237+
JZ sigtrampnog // g == nil
238+
MOVQ g_m(AX), AX
239+
TESTQ AX, AX
240+
JZ sigtramp // g.m == nil
241+
MOVL m_ncgo(AX), CX
242+
TESTL CX, CX
243+
JZ sigtramp // g.m.ncgo == 0
244+
MOVQ m_curg(AX), CX
245+
TESTQ CX, CX
246+
JZ sigtramp // g.m.curg == nil
247+
MOVQ g_syscallsp(CX), CX
248+
TESTQ CX, CX
249+
JZ sigtramp // g.m.curg.syscallsp == 0
250+
MOVQ m_cgoCallers(AX), R8
251+
TESTQ R8, R8
252+
JZ sigtramp // g.m.cgoCallers == nil
253+
MOVL m_cgoCallersUse(AX), CX
254+
TESTL CX, CX
255+
JNZ sigtramp // g.m.cgoCallersUse != 0
256+
257+
// Jump to a function in runtime/cgo.
258+
// That function, written in C, will call the user's traceback
259+
// function with proper unwind info, and will then call back here.
260+
// The first three arguments, and the fifth, are already in registers.
261+
// Set the two remaining arguments now.
262+
MOVQ runtime·cgoTraceback(SB), CX
263+
MOVQ $runtime·sigtramp(SB), R9
264+
MOVQ _cgo_callers(SB), AX
265+
JMP AX
266+
267+
sigtramp:
268+
JMP runtime·sigtramp(SB)
269+
270+
sigtrampnog:
271+
// Signal arrived on a non-Go thread. If this is SIGPROF, get a
272+
// stack trace.
273+
CMPL DI, $27 // 27 == SIGPROF
274+
JNZ sigtramp
275+
276+
// Lock sigprofCallersUse.
277+
MOVL $0, AX
278+
MOVL $1, CX
279+
MOVQ $runtime·sigprofCallersUse(SB), R11
280+
LOCK
281+
CMPXCHGL CX, 0(R11)
282+
JNZ sigtramp // Skip stack trace if already locked.
283+
284+
// Jump to the traceback function in runtime/cgo.
285+
// It will call back to sigprofNonGo, which will ignore the
286+
// arguments passed in registers.
287+
// First three arguments to traceback function are in registers already.
288+
MOVQ runtime·cgoTraceback(SB), CX
289+
MOVQ $runtime·sigprofCallers(SB), R8
290+
MOVQ $runtime·sigprofNonGo(SB), R9
291+
MOVQ _cgo_callers(SB), AX
292+
JMP AX
293+
218294
TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
219295
PUSHQ BP // make a frame; keep stack aligned
220296
MOVQ SP, BP

src/runtime/sys_darwin_arm.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ nog:
227227

228228
RET
229229

230+
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
231+
JMP runtime·sigtramp(SB)
232+
230233
TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
231234
MOVW 4(R0), R1 // arg 2 new
232235
MOVW 8(R0), R2 // arg 3 old

src/runtime/sys_darwin_arm64.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ nog:
223223

224224
RET
225225

226+
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
227+
JMP runtime·sigtramp(SB)
228+
226229
TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
227230
MOVD 8(R0), R1 // arg 2 new
228231
MOVD 16(R0), R2 // arg 3 old

0 commit comments

Comments
 (0)