Re: [PATCH 1/4] alpha: fix stale user_stack_pointer()
From: Magnus Lindholm
Date: Mon Oct 12 2026 - 12:42:29 EST
Hi Matt,
On Sun, Oct 11, 2026 at 10:16 PM Matt Turner <mattst88@xxxxxxxxx> wrote:
>
> PALcode keeps the user stack pointer in the PCB, not the trap frame, so
> pt_regs->usp is only valid where entry code stores it: entSys,
> do_entArith() and do_entIF(). Interrupts, page faults and unaligned
> traps leave it stale, and ptrace and /proc/<pid>/syscall read it
> through user_stack_pointer().
>
> A user-mode pt_regs is at the top of its task's stack, so find the
> thread_info from it and use rdusp() for current or pcb.usp otherwise,
> as KSTK_ESP() and the regset code already do.
>
> Fixes: 8a2857bc2b30 ("alpha: enable regset-based ptrace and core dumps")
> Assisted-by: Claude:claude-opus-5-5
> Signed-off-by: Matt Turner <mattst88@xxxxxxxxx>
> ---
> arch/alpha/include/asm/ptrace.h | 7 +------
> arch/alpha/kernel/ptrace.c | 12 ++++++++++++
> 2 files changed, 13 insertions(+), 6 deletions(-)
>
> diff --git a/arch/alpha/include/asm/ptrace.h b/arch/alpha/include/asm/ptrace.h
> index 430e8dc27ff7..45d1229344b6 100644
> --- a/arch/alpha/include/asm/ptrace.h
> +++ b/arch/alpha/include/asm/ptrace.h
> @@ -26,12 +26,7 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)
> return regs->r0;
> }
>
> -/* Helpers for working with the user stack pointer */
> -static inline unsigned long user_stack_pointer(struct pt_regs *regs)
> -{
> - /* Valid for user-mode regs */
> - return regs->usp;
> -}
> +unsigned long user_stack_pointer(struct pt_regs *regs);
>
> static __always_inline bool regs_irqs_disabled(struct pt_regs *regs)
> {
> diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
> index e1d8c2f69688..dba7e9905cfa 100644
> --- a/arch/alpha/kernel/ptrace.c
> +++ b/arch/alpha/kernel/ptrace.c
> @@ -440,6 +440,18 @@ ptrace_cancel_bpt(struct task_struct * child)
> return (nsaved != 0);
> }
>
> +/*
> + * PALcode keeps the user stack pointer in the PCB, not the trap frame.
> + * A user-mode pt_regs sits at the top of its task's stack, so the
> + * thread_info is at the base.
> + */
> +unsigned long user_stack_pointer(struct pt_regs *regs)
> +{
> + struct thread_info *ti = (void *)((unsigned long)regs & -THREAD_SIZE);
> +
> + return ti == current_thread_info() ? rdusp() : ti->pcb.usp;
> +}
> +
> void user_enable_single_step(struct task_struct *child)
> {
> /* Mark single stepping. */
>
> --
> 2.55.0
>
Nice work!
Reviewed-by: Magnus Lindholm <linmag7@xxxxxxxxx>
Tested-by: Magnus Lindholm <linmag7@xxxxxxxxx>