On Tue, Sep 23, 2025 at 12:45:15PM +0200, Peter Zijlstra wrote: > On Wed, Aug 27, 2025 at 03:36:46PM -0400, Steven Rostedt wrote: > > From: Steven Rostedt <rost...@goodmis.org> > > > > Currently compat tasks are not supported. If a deferred user space stack > > trace is requested on a compat task, it should fail and return an error so > > that the profiler can use an alternative approach (whatever it uses > > today). > > > > Add a arch_unwind_can_defer() macro that is called in > > unwind_deferred_request(). Have x86 define it to a function that makes > > sure that the current task is running in 64bit mode, and if it is not, it > > returns false. This will cause unwind_deferred_request() to error out and > > the caller can use the current method of user space stack tracing. > > Changelog seems to forget mentioning *why* we can't unwind compat. > > I'm sure I've seen compat FP unwind support at some point in this > series. Did that go missing somewhere?
I'm thinking something like the below ought to work. That's just about as complicated as not supporting compat. --- Subject: unwind: Implement compat fp unwind From: Peter Zijlstra <pet...@infradead.org> Date: Tue Sep 23 13:27:34 CEST 2025 Signed-off-by: Peter Zijlstra (Intel) <pet...@infradead.org> --- include/linux/unwind_user_types.h | 1 + kernel/unwind/user.c | 25 +++++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) --- a/include/linux/unwind_user_types.h +++ b/include/linux/unwind_user_types.h @@ -36,6 +36,7 @@ struct unwind_user_state { unsigned long ip; unsigned long sp; unsigned long fp; + unsigned int ws; enum unwind_user_type current_type; unsigned int available_types; bool done; --- a/kernel/unwind/user.c +++ b/kernel/unwind/user.c @@ -15,6 +15,20 @@ static const struct unwind_user_frame fp #define for_each_user_frame(state) \ for (unwind_user_start(state); !(state)->done; unwind_user_next(state)) +static __always_inline int +get_user_word(unsigned long *word, unsigned long __user *addr, int size) +{ +#ifdef CONFIG_COMPAT + if (size == sizeof(int)) { + unsigned int data; + int ret = get_user(data, (unsigned int __user *)addr); + *word = data; + return ret; + } +#endif + return get_user(*word, addr); +} + static int unwind_user_next_fp(struct unwind_user_state *state) { const struct unwind_user_frame *frame = &fp_frame; @@ -29,21 +43,23 @@ static int unwind_user_next_fp(struct un } /* Get the Canonical Frame Address (CFA) */ - cfa += frame->cfa_off; + cfa += state->ws * frame->cfa_off; /* stack going in wrong direction? */ if (cfa <= state->sp) return -EINVAL; /* Make sure that the address is word aligned */ - if (cfa & (sizeof(long) - 1)) + if (cfa & (state->ws - 1)) return -EINVAL; /* Find the Return Address (RA) */ - if (get_user(ra, (unsigned long *)(cfa + frame->ra_off))) + if (get_user_word(&ra, (void __user *)cfa + (state->ws * frame->ra_off), + state->ws)) return -EINVAL; - if (frame->fp_off && get_user(fp, (unsigned long __user *)(cfa + frame->fp_off))) + if (frame->fp_off && get_user_word(&fp, (void __user *)cfa + + (state->ws * frame->fp_off), state->ws)) return -EINVAL; state->ip = ra; @@ -100,6 +116,7 @@ static int unwind_user_start(struct unwi state->ip = instruction_pointer(regs); state->sp = user_stack_pointer(regs); state->fp = frame_pointer(regs); + state->ws = compat_user_mode(regs) ? sizeof(int) : sizeof(long); return 0; } --- Subject: unwind_user/x86: Enable frame pointer unwinding on x86 From: Josh Poimboeuf <jpoim...@kernel.org> Date: Wed, 27 Aug 2025 15:36:45 -0400 From: Josh Poimboeuf <jpoim...@kernel.org> Use ARCH_INIT_USER_FP_FRAME to describe how frame pointers are unwound on x86, and enable CONFIG_HAVE_UNWIND_USER_FP accordingly so the unwind_user interfaces can be used. Signed-off-by: Josh Poimboeuf <jpoim...@kernel.org> Signed-off-by: Steven Rostedt (Google) <rost...@goodmis.org> Signed-off-by: Peter Zijlstra (Intel) <pet...@infradead.org> --- arch/x86/Kconfig | 1 + arch/x86/include/asm/ptrace.h | 9 +++++++++ arch/x86/include/asm/unwind_user.h | 11 +++++++++++ 3 files changed, 21 insertions(+) create mode 100644 arch/x86/include/asm/unwind_user.h --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -297,6 +297,7 @@ config X86 select HAVE_SYSCALL_TRACEPOINTS select HAVE_UACCESS_VALIDATION if HAVE_OBJTOOL select HAVE_UNSTABLE_SCHED_CLOCK + select HAVE_UNWIND_USER_FP if X86_64 select HAVE_USER_RETURN_NOTIFIER select HAVE_GENERIC_VDSO select VDSO_GETRANDOM if X86_64 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -255,6 +255,15 @@ static inline bool any_64bit_mode(struct #endif } +static inline bool compat_user_mode(struct pt_regs *regs) +{ +#ifdef CONFIG_X86_64 + return !user_64bit_mode(regs); +#else + return false; +#endif +} + #ifdef CONFIG_X86_64 #define current_user_stack_pointer() current_pt_regs()->sp #define compat_user_stack_pointer() current_pt_regs()->sp --- /dev/null +++ b/arch/x86/include/asm/unwind_user.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_UNWIND_USER_H +#define _ASM_X86_UNWIND_USER_H + +#define ARCH_INIT_USER_FP_FRAME \ + .cfa_off = 2, \ + .ra_off = -1, \ + .fp_off = -2, \ + .use_fp = true, + +#endif /* _ASM_X86_UNWIND_USER_H */