alpha: fix stale user_stack_pointer()

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: 8a2857bc2b ("alpha: enable regset-based ptrace and core dumps")
Assisted-by: Claude:claude-opus-5-5
Reviewed-by: Magnus Lindholm <linmag7@gmail.com>
Tested-by: Magnus Lindholm <linmag7@gmail.com>
Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Matt Turner <mattst88@gmail.com>
Link: https://lore.kernel.org/r/20261018-alpha-perf-regs-v3-v3-1-52be85332c57@gmail.com
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
This commit is contained in:
Matt Turner 2026-10-18 10:22:01 -04:00 committed by Magnus Lindholm
parent b9fad53a62
commit bceba446fa
2 changed files with 13 additions and 6 deletions

View File

@ -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)
{

View File

@ -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. */