Skip to contentSkip to conversation

x86: Enable the deferred unwinding infrastructure

PATCH Applied Steven Rostedt 3 participants 9 messages Aug 27, 2025 – Oct 29, 2025

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

v2 cover x86: Enable the deferred unwinding infrastructure

This enables deferred unwinding for x86.

Changes since v1: https://lore.kernel.org/linux-trace-kernel/[email protected]

- Added #include <linux/compat.h> to use user_64bit_mode() in unwind_user.h. When adding this to the ftrace code, it failed to build due to the missing header.

Josh Poimboeuf (1):
unwind_user/x86: Enable frame pointer unwinding on x86

Steven Rostedt (1):
unwind deferred/x86: Do not defer stack tracing for compat tasks

----

 arch/x86/Kconfig                   |  1 +
 arch/x86/include/asm/unwind_user.h | 23 +++++++++++++++++++++++
 include/linux/unwind_deferred.h    |  5 +++++
 kernel/unwind/deferred.c           |  3 +++
 4 files changed, 32 insertions(+)
 create mode 100644 arch/x86/include/asm/unwind_user.h
#1 lore raw

PATCH v2 1/2 unwind_user/x86: Enable frame pointer unwinding on x86

From: Josh Poimboeuf <[email protected]>

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.

---
 arch/x86/Kconfig                   |  1 +
 arch/x86/include/asm/unwind_user.h | 11 +++++++++++
 2 files changed, 12 insertions(+)
 create mode 100644 arch/x86/include/asm/unwind_user.h
arch/x86/Kconfig +1 -0
index 58d890fe2100..8f94c58d4de8 100644
@@ -299,6 +299,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
arch/x86/include/asm/unwind_user.h new file +11 -0
new file mode 100644
index 000000000000..8597857bf896
@@ -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	= (s32)sizeof(long) *  2,				\
+	.ra_off		= (s32)sizeof(long) * -1,				\
+	.fp_off		= (s32)sizeof(long) * -2,				\
+	.use_fp		= true,
+
+#endif /* _ASM_X86_UNWIND_USER_H */
Signature · 1 line
2.50.1
maintainer
#2 lore raw

Re: [PATCH v2 1/2] unwind_user/x86: Enable frame pointer unwinding on x86

Quoted 33 lines · Steven Rostedt

From: Josh Poimboeuf <[email protected]>

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.

---
 arch/x86/Kconfig                   |  1 +
 arch/x86/include/asm/unwind_user.h | 11 +++++++++++
 2 files changed, 12 insertions(+)
 create mode 100644 arch/x86/include/asm/unwind_user.h
arch/x86/Kconfig +1 -0
index 58d890fe2100..8f94c58d4de8 100644
@@ -299,6 +299,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
arch/x86/include/asm/unwind_user.h new file +1 -0
new file mode 100644
index 000000000000..8597857bf896
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */

arch/x86/include/asm/unwind_user.h line 11

Quoted 10 lines
arch/x86/include/asm/unwind_user.h new file +10 -0
+#ifndef _ASM_X86_UNWIND_USER_H
+#define _ASM_X86_UNWIND_USER_H
+
+#define ARCH_INIT_USER_FP_FRAME							\
+	.cfa_off	= (s32)sizeof(long) *  2,				\
+	.ra_off		= (s32)sizeof(long) * -1,				\
+	.fp_off		= (s32)sizeof(long) * -2,				\
+	.use_fp		= true,
+
+#endif /* _ASM_X86_UNWIND_USER_H */

Moo, and now you have me look at unwind/user.c:

        /* Make sure that the address is word aligned */
        shift = sizeof(long) == 4 ? 2 : 3;
        if (cfa & ((1 << shift) - 1))
                return -EINVAL;

Isn't that just:

	if (cfa & (sizeof(long) - 1))

?

Let me go add a patch to clean that up...

#3 lore raw

Re: [PATCH v2 1/2] unwind_user/x86: Enable frame pointer unwinding on x86

Quoted 7 lines · On Tue, 23 Sep 2025 12:51:30 +0200 Peter Zijlstra <[email protected]> wrote:

Moo, and now you have me look at unwind/user.c:

        /* Make sure that the address is word aligned */
        shift = sizeof(long) == 4 ? 2 : 3;
        if (cfa & ((1 << shift) - 1))
                return -EINVAL;
Quoted 7 lines

Isn't that just:

	if (cfa & (sizeof(long) - 1))

?

Let me go add a patch to clean that up...

Sure, as long as it's commented.

Thanks,

-- Steve

merge bot Applied
#4 lore raw

[tip: perf/core] unwind_user/x86: Enable frame pointer unwinding on x86

In reply to Steven Rostedt
The following commit has been merged into the perf/core branch of tip:

The following commit has been merged into the perf/core branch of tip:

Commit-ID:     49cf34c0815f93fb2ea3ab5cfbac1124bd9b45d0
Gitweb:        https://git.kernel.org/tip/49cf34c0815f93fb2ea3ab5cfbac1124bd9b45d0
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Wed, 27 Aug 2025 15:36:45 -04:00
Committer:     Peter Zijlstra <[email protected]>
CommitterDate: Wed, 29 Oct 2025 10:29:58 +01:00

unwind_user/x86: Enable frame pointer unwinding on x86

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.

---
 arch/x86/Kconfig                   |  1 +
 arch/x86/include/asm/unwind_user.h | 25 +++++++++++++++++++++++++
 2 files changed, 26 insertions(+)
 create mode 100644 arch/x86/include/asm/unwind_user.h
arch/x86/Kconfig +1 -0
index fa3b616..5cf1afc 100644
@@ -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
arch/x86/include/asm/unwind_user.h new file +25 -0
new file mode 100644
index 0000000..b166e10
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_UNWIND_USER_H
+#define _ASM_X86_UNWIND_USER_H
+
+#include <asm/ptrace.h>
+
+#define ARCH_INIT_USER_FP_FRAME(ws)			\
+	.cfa_off	=  2*(ws),			\
+	.ra_off		= -1*(ws),			\
+	.fp_off		= -2*(ws),			\
+	.use_fp		= true,
+
+static inline int unwind_user_word_size(struct pt_regs *regs)
+{
+	/* We can't unwind VM86 stacks */
+	if (regs->flags & X86_VM_MASK)
+		return 0;
+#ifdef CONFIG_X86_64
+	if (!user_64bit_mode(regs))
+		return sizeof(int);
+#endif
+	return sizeof(long);
+}
+
+#endif /* _ASM_X86_UNWIND_USER_H */
#5 lore raw

PATCH v2 2/2 unwind deferred/x86: Do not defer stack tracing for compat tasks

In reply to Steven Rostedt

From: Steven Rostedt <[email protected]>

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.

---
Changes since v1: https://lore.kernel.org/[email protected]

- Added #include <linux/compat.h> to use user_64bit_mode() in unwind_user.h. When adding this to the ftrace code, it failed to build due to the missing header.

 arch/x86/include/asm/unwind_user.h | 12 ++++++++++++
 include/linux/unwind_deferred.h    |  5 +++++
 kernel/unwind/deferred.c           |  3 +++
 3 files changed, 20 insertions(+)
arch/x86/include/asm/unwind_user.h +12 -0
index 8597857bf896..0cef2e3b08c8 100644
@@ -2,6 +2,18 @@
 #ifndef _ASM_X86_UNWIND_USER_H
 #define _ASM_X86_UNWIND_USER_H
 
+#ifdef CONFIG_IA32_EMULATION
+#include <linux/compat.h>
+/* Currently compat mode is not supported for deferred stack trace */
+static inline bool arch_unwind_can_defer(void)
+{
+	struct pt_regs *regs = task_pt_regs(current);
+
+	return user_64bit_mode(regs);
+}
+# define arch_unwind_can_defer	arch_unwind_can_defer
+#endif /* CONFIG_IA32_EMULATION */
+
 #define ARCH_INIT_USER_FP_FRAME							\
 	.cfa_off	= (s32)sizeof(long) *  2,				\
 	.ra_off		= (s32)sizeof(long) * -1,				\
include/linux/unwind_deferred.h +5 -0
index 26122d00708a..0124865aaab4 100644
@@ -16,6 +16,11 @@ struct unwind_work {
 	int				bit;
 };
 
+/* Architectures can add a test to not defer unwinding */
+#ifndef arch_unwind_can_defer
+# define arch_unwind_can_defer()	(true)
+#endif
+
 #ifdef CONFIG_UNWIND_USER
 
 enum {
kernel/unwind/deferred.c +3 -0
index dc6040aae3ee..3601b2efe48d 100644
@@ -237,6 +237,9 @@ int unwind_deferred_request(struct unwind_work *work, u64 *cookie)
 
 	*cookie = 0;
 
+	if (!arch_unwind_can_defer())
+		return -EINVAL;
+
 	if ((current->flags & (PF_KTHREAD | PF_EXITING)) ||
 	    !user_mode(task_pt_regs(current)))
 		return -EINVAL;
Signature · 1 line
2.50.1
maintainer
#6 lore raw

Re: [PATCH v2 2/2] unwind deferred/x86: Do not defer stack tracing for compat tasks

Quoted 7 lines · Steven Rostedt

From: Steven Rostedt <[email protected]>

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).

Quoted 5 lines

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?

Also, these two patches are in the wrong order, first you enable things, including compat tasks, and then you go 'whoopsie, no compats'.

Quoted 57 lines

---
Changes since v1: https://lore.kernel.org/[email protected]

- Added #include <linux/compat.h> to use user_64bit_mode() in unwind_user.h. When adding this to the ftrace code, it failed to build due to the missing header.

 arch/x86/include/asm/unwind_user.h | 12 ++++++++++++
 include/linux/unwind_deferred.h    |  5 +++++
 kernel/unwind/deferred.c           |  3 +++
 3 files changed, 20 insertions(+)
arch/x86/include/asm/unwind_user.h +12 -0
index 8597857bf896..0cef2e3b08c8 100644
@@ -2,6 +2,18 @@
 #ifndef _ASM_X86_UNWIND_USER_H
 #define _ASM_X86_UNWIND_USER_H
 
+#ifdef CONFIG_IA32_EMULATION
+#include <linux/compat.h>
+/* Currently compat mode is not supported for deferred stack trace */
+static inline bool arch_unwind_can_defer(void)
+{
+	struct pt_regs *regs = task_pt_regs(current);
+
+	return user_64bit_mode(regs);
+}
+# define arch_unwind_can_defer	arch_unwind_can_defer
+#endif /* CONFIG_IA32_EMULATION */
+
 #define ARCH_INIT_USER_FP_FRAME							\
 	.cfa_off	= (s32)sizeof(long) *  2,				\
 	.ra_off		= (s32)sizeof(long) * -1,				\
include/linux/unwind_deferred.h +5 -0
index 26122d00708a..0124865aaab4 100644
@@ -16,6 +16,11 @@ struct unwind_work {
 	int				bit;
 };
 
+/* Architectures can add a test to not defer unwinding */
+#ifndef arch_unwind_can_defer
+# define arch_unwind_can_defer()	(true)
+#endif
+
 #ifdef CONFIG_UNWIND_USER
 
 enum {
kernel/unwind/deferred.c +0 -0
index dc6040aae3ee..3601b2efe48d 100644

kernel/unwind/deferred.c int unwind_deferred_request(struct unwind_work *work, u64 *cookie) · line 245

Quoted 9 lines
kernel/unwind/deferred.c +3 -0
@@ -237,6 +237,9 @@ int unwind_deferred_request(struct unwind_work *work, u64 *cookie)
 
 	*cookie = 0;
 
+	if (!arch_unwind_can_defer())
+		return -EINVAL;
+
 	if ((current->flags & (PF_KTHREAD | PF_EXITING)) ||
 	    !user_mode(task_pt_regs(current)))
 		return -EINVAL;

Should not this arch hook be after all the 'normal' early exits?

maintainer
#7 lore raw

Re: [PATCH v2 2/2] unwind deferred/x86: Do not defer stack tracing for compat tasks

Quoted 14 lines · Peter Zijlstra
Quoted 7 lines · Steven Rostedt

From: Steven Rostedt <[email protected]>

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).

Quoted 5 lines

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.

Quoted 4 lines

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 <[email protected]>
Date: Tue Sep 23 13:27:34 CEST 2025

---
 include/linux/unwind_user_types.h |    1 +
 kernel/unwind/user.c              |   25 +++++++++++++++++++++----
 2 files changed, 22 insertions(+), 4 deletions(-)
include/linux/unwind_user_types.h +1 -0
@@ -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;
kernel/unwind/user.c +21 -4
@@ -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 <[email protected]>
Date: Wed, 27 Aug 2025 15:36:45 -0400

From: Josh Poimboeuf <[email protected]>

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.

---
 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
arch/x86/Kconfig +1 -0
@@ -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
arch/x86/include/asm/ptrace.h +9 -0
@@ -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
arch/x86/include/asm/unwind_user.h new file +11 -0
@@ -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 */
#8 lore raw

Re: [PATCH v2 2/2] unwind deferred/x86: Do not defer stack tracing for compat tasks

In reply to Peter Zijlstra
Quoted 7 lines · On Tue, 23 Sep 2025 12:45:15 +0200 Peter Zijlstra <[email protected]> wrote:

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?

Also, these two patches are in the wrong order, first you enable things, including compat tasks, and then you go 'whoopsie, no compats'.

Sure, we can swap it. Yes, we had patches to support it, but they were a bit complicated and when I tested them, they didn't work. But then I also noticed that the current stack tracing didn't work on compat either. Instead of adding complicated code that wasn't working on my machine, I decided to remove the patches. But after I did that, I realized I needed to make sure it wasn't even tried, which is this patch.

I'm not sure who needs profiling on compat code, and I figured we can not add the new deferred work to it if it's not needed. If in the future we need it, we can add it then.

-- Steve