[PATCH v11 08/15] unwind_user/sframe: Wire up unwind_user to sframe
From: Jens Remus <hidden>
Date: 2025-10-22 14:44:38
Also in:
bpf, linux-mm, lkml
Subsystem:
the rest, userspace stack unwinding · Maintainers:
Linus Torvalds, Josh Poimboeuf, Steven Rostedt
From: Josh Poimboeuf <jpoimboe@kernel.org> Now that the sframe infrastructure is fully in place, make it work by hooking it up to the unwind_user interface. Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Arnaldo Carvalho de Melo <acme@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Thomas Gleixner <redacted> Cc: Andrii Nakryiko <andrii@kernel.org> Cc: Indu Bhagat <redacted> Cc: "Jose E. Marchesi" <redacted> Cc: Beau Belgrave <redacted> Cc: Jens Remus <redacted> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Florian Weimer <redacted> Cc: Sam James <redacted> Cc: Kees Cook <kees@kernel.org> Cc: "Carlos O'Donell" <redacted> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org> Signed-off-by: Jens Remus <redacted> --- arch/Kconfig | 1 + include/linux/unwind_user_types.h | 4 ++- kernel/unwind/user.c | 41 +++++++++++++++++++++++++++---- 3 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/arch/Kconfig b/arch/Kconfig
index 69fcabf53088..277b87af949f 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig@@ -453,6 +453,7 @@ config HAVE_UNWIND_USER_FP config HAVE_UNWIND_USER_SFRAME bool + select UNWIND_USER config HAVE_PERF_REGS bool
diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_types.h
index 938f7e623332..ee0ce855e045 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_SFRAME_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_SFRAME = BIT(UNWIND_USER_TYPE_SFRAME_BIT), UNWIND_USER_TYPE_FP = BIT(UNWIND_USER_TYPE_FP_BIT), };
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index 696004ee956a..f6c543cb255b 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c@@ -7,6 +7,7 @@ #include <linux/sched/task_stack.h> #include <linux/unwind_user.h> #include <linux/uaccess.h> +#include <linux/sframe.h> #define for_each_user_frame(state) \ for (unwind_user_start(state); !(state)->done; unwind_user_next(state))
@@ -26,12 +27,10 @@ get_user_word(unsigned long *word, unsigned long base, int off, unsigned int ws) return get_user(*word, addr); } -static int unwind_user_next_fp(struct unwind_user_state *state) +static int unwind_user_next_common(struct unwind_user_state *state, + const struct unwind_user_frame *frame, + struct pt_regs *regs) { - const struct unwind_user_frame fp_frame = { - ARCH_INIT_USER_FP_FRAME(state->ws) - }; - const struct unwind_user_frame *frame = &fp_frame; unsigned long cfa, fp, ra; if (frame->use_fp) {
@@ -67,6 +66,26 @@ static int unwind_user_next_fp(struct unwind_user_state *state) return 0; } +static int unwind_user_next_sframe(struct unwind_user_state *state) +{ + struct unwind_user_frame _frame, *frame; + + /* sframe expects the frame to be local storage */ + frame = &_frame; + if (sframe_find(state->ip, frame)) + return -ENOENT; + return unwind_user_next_common(state, frame, task_pt_regs(current)); +} + +static int unwind_user_next_fp(struct unwind_user_state *state) +{ + const struct unwind_user_frame fp_frame = { + ARCH_INIT_USER_FP_FRAME(state->ws) + }; + + return unwind_user_next_common(state, &fp_frame, task_pt_regs(current)); +} + static int unwind_user_next(struct unwind_user_state *state) { unsigned long iter_mask = state->available_types;
@@ -80,6 +99,16 @@ static int unwind_user_next(struct unwind_user_state *state) state->current_type = type; switch (type) { + case UNWIND_USER_TYPE_SFRAME: + switch (unwind_user_next_sframe(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;
@@ -108,6 +137,8 @@ static int unwind_user_start(struct unwind_user_state *state) return -EINVAL; } + if (current_has_sframe()) + state->available_types |= UNWIND_USER_TYPE_SFRAME; if (IS_ENABLED(CONFIG_HAVE_UNWIND_USER_FP)) state->available_types |= UNWIND_USER_TYPE_FP;
--
2.48.1