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 <[email protected]> --- 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
