[RFC PATCH v1 11/25] unwind_user/eh_frame: Wire up unwind_user to eh_frame
From: Jens Remus <hidden>
Date: 2026-08-18 14:50:40
Also in:
linux-s390, lkml
Subsystem:
the rest, userspace stack unwinding · Maintainers:
Linus Torvalds, Josh Poimboeuf, Steven Rostedt
Now that the eh_frame infrastructure is fully in place, make it work by hooking it up to the unwind_user interface. Based on Josh Poimboeuf's, Steven Rostedt's, and my unwind user sframe implementation. Signed-off-by: Jens Remus <redacted> --- arch/Kconfig | 1 + include/linux/unwind_user_types.h | 4 +++- kernel/unwind/user.c | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/arch/Kconfig b/arch/Kconfig
index 60542d5e5731..ea969811f798 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig@@ -488,6 +488,7 @@ config UNWIND_USER config HAVE_UNWIND_USER_EH_FRAME bool + select UNWIND_USER config HAVE_UNWIND_USER_FP bool
diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_types.h
index 4da058096259..88fc2fee8534 100644
--- a/include/linux/unwind_user_types.h
+++ b/include/linux/unwind_user_types.h@@ -9,7 +9,8 @@ * available. */ enum unwind_user_type_bits { - UNWIND_USER_TYPE_FP_BIT = 0, + UNWIND_USER_TYPE_EH_FRAME_BIT = 0, + UNWIND_USER_TYPE_FP_BIT = 1, NR_UNWIND_USER_TYPE_BITS, };
@@ -17,6 +18,7 @@ enum unwind_user_type_bits { enum unwind_user_type { /* Type "none" for the start of stack walk iteration. */ UNWIND_USER_TYPE_NONE = 0, + UNWIND_USER_TYPE_EH_FRAME = BIT(UNWIND_USER_TYPE_EH_FRAME_BIT), UNWIND_USER_TYPE_FP = BIT(UNWIND_USER_TYPE_FP_BIT), };
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index 830c620fe453..85fc82252af1 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c@@ -10,6 +10,7 @@ #include <linux/sched/task_stack.h> #include <linux/unwind_user.h> #include <linux/uaccess.h> +#include <linux/eh_frame.h> #ifdef CONFIG_DYNAMIC_DEBUG
@@ -173,6 +174,16 @@ static int unwind_user_next_fp(struct unwind_user_state *state) return unwind_user_next_common(state, &fp_frame); } +static int unwind_user_next_eh_frame(struct unwind_user_state *state) +{ + struct unwind_user_frame frame; + + /* eh_frame expects the frame to be local storage */ + if (eh_frame_find(state->ip, &frame)) + return -ENOENT; + return unwind_user_next_common(state, &frame); +} + static int unwind_user_next(struct unwind_user_state *state) { unsigned long iter_mask = state->available_types;
@@ -186,6 +197,16 @@ static int unwind_user_next(struct unwind_user_state *state) state->current_type = type; switch (type) { + case UNWIND_USER_TYPE_EH_FRAME: + switch (unwind_user_next_eh_frame(state)) { + case 0: + return 0; + case -ENOENT: + continue; /* Try next method. */ + default: + state->done = true; + } + break; case UNWIND_USER_TYPE_FP: if (!unwind_user_next_fp(state)) return 0;
@@ -214,6 +235,8 @@ static int unwind_user_start(struct unwind_user_state *state) return -EINVAL; } + if (current_has_eh_frame()) + state->available_types |= UNWIND_USER_TYPE_EH_FRAME; if (IS_ENABLED(CONFIG_HAVE_UNWIND_USER_FP)) state->available_types |= UNWIND_USER_TYPE_FP;
--
2.53.0