]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: clear frame pointer at thread entry points
authorNick Ripley <nick.ripley@datadoghq.com>
Mon, 17 Nov 2025 16:47:20 +0000 (11:47 -0500)
committerGopher Robot <gobot@golang.org>
Mon, 17 Nov 2025 20:06:42 +0000 (12:06 -0800)
There are a few places in the runtime where new threads enter Go code
with a possibly invalid frame pointer. mstart is the entry point for new
Ms, and rt0_go is the entrypoint for the program. As we try to introduce
frame pointer unwinding in more places (e.g. for heap profiling in CL
540476 or for execution trace events on the system stack in CL 593835),
we see these functions on the stack. We need to ensure that they have
valid frame pointers. These functions are both considered the "top"
(first) frame frame of the call stack, so this CL sets the frame pointer
register to 0 in these functions.

Updates #63630

Change-Id: I6a6a6964a9ebc6f68ba23d2616e5fb6f19677f97
Reviewed-on: https://go-review.googlesource.com/c/go/+/721020
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Michael Knyszek <mknyszek@google.com>

src/runtime/asm_amd64.s
src/runtime/asm_arm64.s

index a4c6c53a900ce00ae993bf803630cb0f2563f265..f4244f6e06c173e56ec8f45da60a621e630a8df7 100644 (file)
@@ -181,6 +181,14 @@ TEXT runtime·rt0_go(SB),NOSPLIT|NOFRAME|TOPFRAME,$0
        MOVQ    AX, 24(SP)
        MOVQ    BX, 32(SP)
 
+       // This is typically the entry point for Go programs.
+       // Call stack unwinding must not proceed past this frame.
+       // Set the frame pointer register to 0 so that frame pointer-based unwinders
+       // (which don't use debug info for performance reasons)
+       // won't attempt to unwind past this function.
+       // See go.dev/issue/63630
+       MOVQ    $0, BP
+
        // create istack out of the given (operating system) stack.
        // _cgo_init may update stackguard.
        MOVQ    $runtime·g0(SB), DI
@@ -408,6 +416,13 @@ TEXT runtime·asminit(SB),NOSPLIT,$0-0
        RET
 
 TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME|NOFRAME,$0
+       // This is the root frame of new Go-created OS threads.
+       // Call stack unwinding must not proceed past this frame.
+       // Set the frame pointer register to 0 so that frame pointer-based unwinders
+       // (which don't use debug info for performance reasons)
+       // won't attempt to unwind past this function.
+       // See go.dev/issue/63630
+       MOVD    $0, BP
        CALL    runtime·mstart0(SB)
        RET // not reached
 
index 902a7066aaa113e81949a30d477ba3b083644fd4..01f2690f4e2b1710327df16d6b8f01fef51151a1 100644 (file)
@@ -109,6 +109,14 @@ TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0
        MOVW    R0, 8(RSP) // argc
        MOVD    R1, 16(RSP) // argv
 
+       // This is typically the entry point for Go programs.
+       // Call stack unwinding must not proceed past this frame.
+       // Set the frame pointer register to 0 so that frame pointer-based unwinders
+       // (which don't use debug info for performance reasons)
+       // won't attempt to unwind past this function.
+       // See go.dev/issue/63630
+       MOVD    $0, R29
+
 #ifdef TLS_darwin
        // Initialize TLS.
        MOVD    ZR, g // clear g, make sure it's not junk.
@@ -248,6 +256,13 @@ TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0
        RET
 
 TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0
+       // This is the root frame of new Go-created OS threads.
+       // Call stack unwinding must not proceed past this frame.
+       // Set the frame pointer register to 0 so that frame pointer-based unwinders
+       // (which don't use debug info for performance reasons)
+       // won't attempt to unwind past this function.
+       // See go.dev/issue/63630
+       MOVD    $0, R29
        BL      runtime·mstart0(SB)
        RET // not reached