[RFC PATCH v3 16/17] unwind_user/fp: Use arch-specific helper to initialize FP frame
From: Jens Remus <hidden>
Date: 2025-12-08 17:16:47
Also in:
bpf, linux-s390, lkml
Subsystem:
the rest, userspace stack unwinding, x86 architecture (32-bit and 64-bit), x86 stack unwinding · Maintainers:
Linus Torvalds, Josh Poimboeuf, Steven Rostedt, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, Peter Zijlstra
This enables more sophisticated initialization of the FP frame, for
instance to implement support for unwinding of user space using back
chain on s390 with a subsequent commit.
Signed-off-by: Jens Remus <redacted>
---
Notes (jremus):
Changes in RFC v3:
- New patch. Prerequirement to implement unwind user fp using back
chain on s390.
arch/x86/include/asm/unwind_user.h | 20 +++++++++++++++++---
include/linux/unwind_user.h | 20 +++++++-------------
kernel/unwind/user.c | 16 ++++------------
3 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h
index 2480d86a405e..ca581edecb9d 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h@@ -46,11 +46,25 @@ static inline int unwind_user_word_size(struct pt_regs *regs) .use_fp = false, \ .outermost = false, -static inline bool unwind_user_at_function_start(struct pt_regs *regs) +static inline int unwind_user_fp_get_frame(struct unwind_user_state *state, + struct unwind_user_frame *frame) { - return is_uprobe_at_func_entry(regs); + struct pt_regs *regs = task_pt_regs(current); + + if (state->topmost && is_uprobe_at_func_entry(regs)) { + const struct unwind_user_frame fp_entry_frame = { + ARCH_INIT_USER_FP_ENTRY_FRAME(state->ws) + }; + *frame = fp_entry_frame; + } else { + const struct unwind_user_frame fp_frame = { + ARCH_INIT_USER_FP_FRAME(state->ws) + }; + *frame = fp_frame; + } + return 0; } -#define unwind_user_at_function_start unwind_user_at_function_start +#define unwind_user_fp_get_frame unwind_user_fp_get_frame #endif /* CONFIG_HAVE_UNWIND_USER_FP */
diff --git a/include/linux/unwind_user.h b/include/linux/unwind_user.h
index 61fd5c05d0f0..4adab1a612a6 100644
--- a/include/linux/unwind_user.h
+++ b/include/linux/unwind_user.h@@ -7,21 +7,15 @@ #ifndef CONFIG_HAVE_UNWIND_USER_FP -#define ARCH_INIT_USER_FP_FRAME(ws) - -#endif - -#ifndef ARCH_INIT_USER_FP_ENTRY_FRAME -#define ARCH_INIT_USER_FP_ENTRY_FRAME(ws) -#endif - -#ifndef unwind_user_at_function_start -static inline bool unwind_user_at_function_start(struct pt_regs *regs) +static inline int unwind_user_fp_get_frame(struct unwind_user_state *state, + struct unwind_user_frame *frame) { - return false; + WARN_ON_ONCE(1); + return -EINVAL; } -#define unwind_user_at_function_start unwind_user_at_function_start -#endif +#define unwind_user_fp_get_frame unwind_user_fp_get_frame + +#endif /* CONFIG_HAVE_UNWIND_USER_FP */ #ifndef unwind_user_get_ra_reg static inline int unwind_user_get_ra_reg(unsigned long *val)
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index 7d06bdbc7f0d..6877242ceae3 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c@@ -111,19 +111,11 @@ static int unwind_user_next_common(struct unwind_user_state *state, static int unwind_user_next_fp(struct unwind_user_state *state) { - struct pt_regs *regs = task_pt_regs(current); - - if (state->topmost && unwind_user_at_function_start(regs)) { - const struct unwind_user_frame fp_entry_frame = { - ARCH_INIT_USER_FP_ENTRY_FRAME(state->ws) - }; - return unwind_user_next_common(state, &fp_entry_frame); - } + struct unwind_user_frame frame; - const struct unwind_user_frame fp_frame = { - ARCH_INIT_USER_FP_FRAME(state->ws) - }; - return unwind_user_next_common(state, &fp_frame); + if (unwind_user_fp_get_frame(state, &frame)) + return -ENOENT; + return unwind_user_next_common(state, &frame); } static int unwind_user_next_sframe(struct unwind_user_state *state)
--
2.51.0