]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: support cgo traceback on linux arm64
authoreric fang <eric.fang@arm.com>
Fri, 17 Dec 2021 06:13:46 +0000 (06:13 +0000)
committerEric Fang <eric.fang@arm.com>
Fri, 4 Mar 2022 01:18:57 +0000 (01:18 +0000)
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>
src/runtime/crash_cgo_test.go
src/runtime/sys_linux_arm64.s
src/runtime/traceback.go

index c9c9406a15a48d09773aedf6e2b4ffdd2e1e8c92..37509b129228df26eb579fe9f7463d06eb8e753a 100644 (file)
@@ -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)
index 5f05afb743dba29c803f2eb75e81f772456f5b0d..ca362ed55207c748700726471c482c31b68351ad 100644 (file)
@@ -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
index 73bd0e11a9c9778b7184f1c3a25ca29a9636491d..0cdd53cc936f257c561eab0211d494735636b025 100644 (file)
@@ -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