Skip to content

Commit

Permalink
runtime: support cgo traceback on linux arm64
Browse files Browse the repository at this point in the history
Code essentially mirrors AMD64 implementation.

Change-Id: Ie97627a3041d1858fb1a30d2fc500302ab4011b3
Reviewed-on: https://go-review.googlesource.com/c/go/+/373363
Trust: Eric Fang <eric.fang@arm.com>
Run-TryBot: Eric Fang <eric.fang@arm.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
  • Loading branch information
eric fang committed Mar 4, 2022
1 parent 1eb1f62 commit 81767e2
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 7 deletions.
4 changes: 3 additions & 1 deletion src/runtime/crash_cgo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ func TestCgoCrashTraceback(t *testing.T) {
switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
case "darwin/amd64":
case "linux/amd64":
case "linux/arm64":
case "linux/ppc64le":
default:
t.Skipf("not yet supported on %s", platform)
Expand All @@ -251,6 +252,7 @@ func TestCgoCrashTracebackGo(t *testing.T) {
switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
case "darwin/amd64":
case "linux/amd64":
case "linux/arm64":
case "linux/ppc64le":
default:
t.Skipf("not yet supported on %s", platform)
Expand Down Expand Up @@ -284,7 +286,7 @@ func TestCgoTracebackContextPreemption(t *testing.T) {

func testCgoPprof(t *testing.T, buildArg, runArg, top, bottom string) {
t.Parallel()
if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") {
if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le" && runtime.GOARCH != "arm64") {
t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
}
testenv.MustHaveGoRun(t)
Expand Down
144 changes: 141 additions & 3 deletions src/runtime/sys_linux_arm64.s
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
BL (R11)
RET

// Called from c-abi, R0: sig, R1: info, R2: cxt
TEXT runtime·sigtramp(SB),NOSPLIT,$192
// Save callee-save registers in the case of signal forwarding.
// Please refer to https://golang.org/issue/31827 .
Expand Down Expand Up @@ -502,9 +503,146 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$192

RET

TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
MOVD $runtime·sigtramp(SB), R3
B (R3)
// Called from c-abi, R0: sig, R1: info, R2: cxt
TEXT runtime·sigprofNonGoWrapper<>(SB),NOSPLIT,$192
// TODO(eric): In multiple places we need to save and restore the
// callee-saved registers, we can define a macro for this.
// Save callee-save registers because it's a callback from c code.
MOVD R19, 8*4(RSP)
MOVD R20, 8*5(RSP)
MOVD R21, 8*6(RSP)
MOVD R22, 8*7(RSP)
MOVD R23, 8*8(RSP)
MOVD R24, 8*9(RSP)
MOVD R25, 8*10(RSP)
MOVD R26, 8*11(RSP)
MOVD R27, 8*12(RSP)
MOVD g, 8*13(RSP)
MOVD R29, 8*14(RSP)
FMOVD F8, 8*15(RSP)
FMOVD F9, 8*16(RSP)
FMOVD F10, 8*17(RSP)
FMOVD F11, 8*18(RSP)
FMOVD F12, 8*19(RSP)
FMOVD F13, 8*20(RSP)
FMOVD F14, 8*21(RSP)
FMOVD F15, 8*22(RSP)

MOVW R0, 8(RSP) // sig
MOVD R1, 16(RSP) // info
MOVD R2, 24(RSP) // ctx
CALL runtime·sigprofNonGo(SB)

// Restore callee-save registers.
MOVD 8*4(RSP), R19
MOVD 8*5(RSP), R20
MOVD 8*6(RSP), R21
MOVD 8*7(RSP), R22
MOVD 8*8(RSP), R23
MOVD 8*9(RSP), R24
MOVD 8*10(RSP), R25
MOVD 8*11(RSP), R26
MOVD 8*12(RSP), R27
MOVD 8*13(RSP), g
MOVD 8*14(RSP), R29
FMOVD 8*15(RSP), F8
FMOVD 8*16(RSP), F9
FMOVD 8*17(RSP), F10
FMOVD 8*18(RSP), F11
FMOVD 8*19(RSP), F12
FMOVD 8*20(RSP), F13
FMOVD 8*21(RSP), F14
FMOVD 8*22(RSP), F15
RET

// Called from c-abi, R0: sig, R1: info, R2: cxt
TEXT runtime·cgoSigtramp(SB),NOSPLIT|NOFRAME,$0
// The stack unwinder, presumably written in C, may not be able to
// handle Go frame correctly. So, this function is NOFRAME, and we
// save/restore LR manually.
MOVD LR, R10
// Save R27, g because they will be clobbered,
// we need to restore them before jump to sigtramp.
MOVD R27, R11
MOVD g, R12

// If no traceback function, do usual sigtramp.
MOVD runtime·cgoTraceback(SB), R6
CBZ R6, sigtramp

// If no traceback support function, which means that
// runtime/cgo was not linked in, do usual sigtramp.
MOVD _cgo_callers(SB), R7
CBZ R7, sigtramp

// Figure out if we are currently in a cgo call.
// If not, just do usual sigtramp.
// first save R0, because runtime·load_g will clobber it.
MOVD R0, R8
// Set up g register.
CALL runtime·load_g(SB)
MOVD R8, R0

CBZ g, sigtrampnog // g == nil
MOVD g_m(g), R6
CBZ R6, sigtramp // g.m == nil
MOVW m_ncgo(R6), R7
CBZW R7, sigtramp // g.m.ncgo = 0
MOVD m_curg(R6), R8
CBZ R8, sigtramp // g.m.curg == nil
MOVD g_syscallsp(R8), R7
CBZ R7, sigtramp // g.m.curg.syscallsp == 0
MOVD m_cgoCallers(R6), R4 // R4 is the fifth arg in C calling convention.
CBZ R4, sigtramp // g.m.cgoCallers == nil
MOVW m_cgoCallersUse(R6), R8
CBNZW R8, 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.
MOVD runtime·cgoTraceback(SB), R3
MOVD $runtime·sigtramp(SB), R5
MOVD _cgo_callers(SB), R13
MOVD R10, LR // restore
MOVD R11, R27
MOVD R12, g
B (R13)

sigtramp:
MOVD R10, LR // restore
MOVD R11, R27
MOVD R12, g
B runtime·sigtramp(SB)

sigtrampnog:
// Signal arrived on a non-Go thread. If this is SIGPROF, get a
// stack trace.
CMPW $27, R0 // 27 == SIGPROF
BNE sigtramp

// Lock sigprofCallersUse (cas from 0 to 1).
MOVW $1, R7
MOVD $runtime·sigprofCallersUse(SB), R8
load_store_loop:
LDAXRW (R8), R9
CBNZW R9, sigtramp // Skip stack trace if already locked.
STLXRW R7, (R8), R9
CBNZ R9, load_store_loop

// 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.
MOVD runtime·cgoTraceback(SB), R3
MOVD $runtime·sigprofCallers(SB), R4
MOVD $runtime·sigprofNonGoWrapper<>(SB), R5
MOVD _cgo_callers(SB), R13
MOVD R10, LR // restore
MOVD R11, R27
MOVD R12, g
B (R13)

TEXT runtime·sysMmap(SB),NOSPLIT|NOFRAME,$0
MOVD addr+0(FP), R0
Expand Down
6 changes: 3 additions & 3 deletions src/runtime/traceback.go
Original file line number Diff line number Diff line change
Expand Up @@ -1229,9 +1229,9 @@ func isSystemGoroutine(gp *g, fixed bool) bool {
//
// On all platforms, the traceback function is invoked when a call from
// Go to C to Go requests a stack trace. On linux/amd64, linux/ppc64le,
// and freebsd/amd64, the traceback function is also invoked when a
// signal is received by a thread that is executing a cgo call. The
// traceback function should not make assumptions about when it is
// linux/arm64, and freebsd/amd64, the traceback function is also invoked
// when a signal is received by a thread that is executing a cgo call.
// The traceback function should not make assumptions about when it is
// called, as future versions of Go may make additional calls.
//
// The symbolizer function will be called with a single argument, a
Expand Down

0 comments on commit 81767e2

Please sign in to comment.