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:
quoted
From: Steven Rostedt <rostedt@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 <peterz@infradead.org>
Date: Tue Sep 23 13:27:34 CEST 2025
Signed-off-by: Peter Zijlstra (Intel) <peterz@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 <jpoimboe@kernel.org>
Date: Wed, 27 Aug 2025 15:36:45 -0400
From: Josh Poimboeuf <jpoimboe@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 <jpoimboe@kernel.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@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 */