git: 1db0c9fa7a32 - main - hwpmc(4): stop overwalking past _start on amd64 user callchains

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Wed, 02 Sep 2026 14:30:30 UTC
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=1db0c9fa7a32255c452c2536d657e63b55e30e03

commit 1db0c9fa7a32255c452c2536d657e63b55e30e03
Author:     Nick Banks <nickbanks@netflix.com>
AuthorDate: 2026-09-02 14:28:54 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2026-09-02 14:29:08 +0000

    hwpmc(4): stop overwalking past _start on amd64 user callchains
    
    pmc_save_user_callchain() emits the pc it just loaded before checking
    whether fp is the ABI's zero frame-chain terminator. At the bottom of
    a well-formed chain under _start, fp comes back 0 as expected, but the
    paired pc is stale rtld data left on the stack -- a legal userspace VA
    that still passes PMC_IN_USERSPACE(), so it gets emitted as a bogus
    extra frame. This shows up in flame graphs as a spurious hex-valued
    root frame below _start.
    
    Check fp == 0 alongside the existing checks before emitting, matching
    how arm/arm64/powerpc already load the next fp before their check.
    
    Measured via 1kHz hwpmc sampling on an OCA: stacks with any unresolved
    hex frame drop from 23.9% to 1.3%, and stacks with hex at the root drop
    from 5.5% to 0.3%.
    
    Reviewed by:    mhorne, Ali Mashtizadeh <ali@mashtizadeh.com>, gallatin
    MFC after:      3 days
    Sponsored by:   Netflix
    Differential Revision:  https://reviews.freebsd.org/D59229
---
 sys/dev/hwpmc/hwpmc_x86.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/dev/hwpmc/hwpmc_x86.c b/sys/dev/hwpmc/hwpmc_x86.c
index 2903c25ef5c9..c32242a2bbb9 100644
--- a/sys/dev/hwpmc/hwpmc_x86.c
+++ b/sys/dev/hwpmc/hwpmc_x86.c
@@ -107,7 +107,8 @@ pmc_save_user_callchain(uintptr_t *cc, int nframes, struct trapframe *tf)
 		return (n);
 
 	for (; n < nframes;) {
-		if (pc == 0 || !PMC_IN_USERSPACE(pc))
+		/* fp == 0 is the ABI frame-chain sentinel below _start. */
+		if (pc == 0 || !PMC_IN_USERSPACE(pc) || fp == 0)
 			break;
 
 		*cc++ = pc; n++;