Re: [PATCH v4 4/7] alpha/perf: do not report user registers from the entry code

From: Magnus Lindholm

Date: Tue Nov 03 2026 - 03:11:02 EST


Hi Matt,

On Tue, Nov 3, 2026 at 4:02 AM Matt Turner <mattst88@xxxxxxxxx> wrote:
>
> perf_get_regs_user() returns task_pt_regs() whenever a sample of a user
> task lands in the kernel. But exception entry runs with interrupts
> enabled, so the sample can land before the entry code has saved the user
> registers. Only the part PALcode pushed is valid then. An interrupt
> taken on the first instruction of entUna, say, pushes its own frame on
> top of PALcode's, which overlaps the rest of the user frame, so r7 and r8
> read as the interrupt's r23 and r24.
>
> Report no user registers while the interrupted PC is in the entry code.
> Such a sample also gets no user stack dump. The range is all of the entry
> code from entInt to the end of the save in entSys, so it also drops the
> registers of samples that land after they were saved there.
>
> An interrupt that nests on one taken in the entry code still reads the
> incomplete frame, as its own PC has left the entry code.
>
> Fixes: 9280e99d87dd ("alpha: add HAVE_PERF_REGS and HAVE_PERF_USER_STACK_DUMP support")
> Assisted-by: Claude:claude-opus-5-5
> Signed-off-by: Matt Turner <mattst88@xxxxxxxxx>
> ---
> arch/alpha/include/asm/ptrace.h | 12 ++++++++++++
> arch/alpha/kernel/entry.S | 9 +++++++++
> arch/alpha/kernel/perf_regs.c | 13 +++++++++++++
> 3 files changed, 34 insertions(+)
>
> diff --git a/arch/alpha/include/asm/ptrace.h b/arch/alpha/include/asm/ptrace.h
> index 45d1229344b6..1400ba3e7d43 100644
> --- a/arch/alpha/include/asm/ptrace.h
> +++ b/arch/alpha/include/asm/ptrace.h
> @@ -14,6 +14,18 @@
> #define task_pt_regs(task) \
> ((struct pt_regs *) (task_stack_page(task) + 2*PAGE_SIZE) - 1)
>
> +/*
> + * Whether pc is in entry code that may not have completed the frame at
> + * task_pt_regs(). See entry.S.
> + */
> +static inline bool in_entry_save_code(unsigned long pc)
> +{
> + extern char __entry_save_start[], __entry_save_end[];
> +
> + return pc >= (unsigned long)__entry_save_start &&
> + pc < (unsigned long)__entry_save_end;
> +}
> +
> #define current_pt_regs() \
> ((struct pt_regs *) ((char *)current_thread_info() + 2*PAGE_SIZE) - 1)
>
> diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
> index 790389a15c3c..b8d7804e5aa3 100644
> --- a/arch/alpha/kernel/entry.S
> +++ b/arch/alpha/kernel/entry.S
> @@ -186,8 +186,14 @@
>
> /*
> * Non-syscall kernel entry points.
> + *
> + * Between __entry_save_start and __entry_save_end the frame at task_pt_regs()
> + * may not be complete. perf uses these to avoid reading it.
> */
>
> + .globl __entry_save_start
> +__entry_save_start:
> +
> CFI_START_OSF_FRAME entInt
> SAVE_ALL
> lda $8, 0x3fff
> @@ -479,9 +485,12 @@ entSys:
> lda $8, 0x3fff
> bic $sp, $8, $8
>
> + /* PAL_callsys does not save these, unlike the other entries. */
> stq $16, SP_OFF+24($sp)
> stq $17, SP_OFF+32($sp)
> stq $18, SP_OFF+40($sp)
> + .globl __entry_save_end
> +__entry_save_end:
>
> mov $0, $1
> lda $16, 7
> diff --git a/arch/alpha/kernel/perf_regs.c b/arch/alpha/kernel/perf_regs.c
> index 33ea2e831ba0..894683851b30 100644
> --- a/arch/alpha/kernel/perf_regs.c
> +++ b/arch/alpha/kernel/perf_regs.c
> @@ -59,6 +59,19 @@ u64 perf_reg_abi(struct task_struct *task)
> void perf_get_regs_user(struct perf_regs *regs_user,
> struct pt_regs *regs)
> {
> + /*
> + * Exception entry runs with interrupts enabled, so a sample can land
> + * before the entry code has saved the user registers. PALcode has
> + * pushed only its part of the frame, and the rest may hold an
> + * interrupt's frame. An interrupt that nests on top of one taken here
> + * is not caught, as its PC has left the entry code.
> + */
> + if (in_entry_save_code(regs->pc)) {
> + regs_user->regs = NULL;
> + regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
> + return;
> + }
> +
> regs_user->regs = task_pt_regs(current);
> regs_user->abi = perf_reg_abi(current);
> }
>
> --
> 2.55.0
>

Tested on my AlphaServer ES40. Across all three CPUs, the syscall
probe sampled the newly protected part of entSys 180 times. Every
sample correctly omitted the user registers and stack. I also saw
this in all 173 hits from separate perf recordings.

Reviewed-by: Magnus Lindholm <linmag7@xxxxxxxxx>
Tested-by: Magnus Lindholm <linmag7@xxxxxxxxx>