From: eric fang Date: Fri, 17 Dec 2021 06:13:46 +0000 (+0000) Subject: runtime: support cgo traceback on linux arm64 X-Git-Tag: go1.19beta1~1169 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=81767e23c2f0e3edf0a329d9f00f5683c9851692;p=gostls13.git runtime: support cgo traceback on linux arm64 Code essentially mirrors AMD64 implementation. Change-Id: Ie97627a3041d1858fb1a30d2fc500302ab4011b3 Reviewed-on: https://go-review.googlesource.com/c/go/+/373363 Trust: Eric Fang Run-TryBot: Eric Fang TryBot-Result: Gopher Robot Reviewed-by: Ian Lance Taylor --- diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go index c9c9406a15..37509b1292 100644 --- a/src/runtime/crash_cgo_test.go +++ b/src/runtime/crash_cgo_test.go @@ -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) @@ -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) @@ -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) diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s index 5f05afb743..ca362ed552 100644 --- a/src/runtime/sys_linux_arm64.s +++ b/src/runtime/sys_linux_arm64.s @@ -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 . @@ -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 diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 73bd0e11a9..0cdd53cc93 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -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