[RFC PATCH 1/2] perf/core: Let an arch prepare the user stack before it is dumped

From: Stian Halseth

Date: Tue Sep 22 2026 - 10:07:18 EST


PERF_SAMPLE_STACK_USER copies the user stack as it is in memory, which
assumes the whole call chain is there. On sparc the sampled window's
%l and %i registers, including the frame pointer and return address an
unwinder starts from, may still be in the register file: they only
reach the stack when a window spills. perf_callchain_user() already
handles this for the callchain by calling flushw_user() first; the user
stack dump has no equivalent arch entry point.

Add perf_arch_prepare_ustack(), a no-op by default, called from
perf_prepare_sample() before the dump size is computed, so an arch can
write back whatever part of the user's stack state it still holds in
registers. Doing this in the arch PMU interrupt handler would not do:
software events such as cpu-clock reach perf_event_overflow() without
passing through it.

Signed-off-by: Stian Halseth <stian@xxxxxx>
---
include/linux/perf_event.h | 7 +++++++
kernel/events/core.c | 2 ++
2 files changed, 9 insertions(+)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 5842552294c1..758b98b75346 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1815,6 +1815,13 @@ extern unsigned long perf_instruction_pointer(struct perf_event *event,
#ifndef perf_arch_bpf_user_pt_regs
# define perf_arch_bpf_user_pt_regs(regs) regs
#endif
+/*
+ * Called before the user stack of the current task is dumped, for an arch
+ * that still holds part of the user's stack state in registers.
+ */
+#ifndef perf_arch_prepare_ustack
+static inline void perf_arch_prepare_ustack(void) { }
+#endif

#ifndef perf_arch_guest_misc_flags
static inline unsigned long perf_arch_guest_misc_flags(struct pt_regs *regs)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index db7b76d6b68a..90fb35c7d279 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -8718,6 +8718,8 @@ void perf_prepare_sample(struct perf_sample_data *data,
u16 header_size = perf_sample_data_size(data, event);
u16 size = sizeof(u64);

+ if (data->regs_user.regs)
+ perf_arch_prepare_ustack();
stack_size = perf_sample_ustack_size(stack_size, header_size,
data->regs_user.regs);

--
2.55.0