From: Jens Remus <jremus@linux.ibm.com>
To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
bpf@vger.kernel.org, x86@kernel.org,
Steven Rostedt <rostedt@kernel.org>
Cc: Jens Remus <jremus@linux.ibm.com>,
Heiko Carstens <hca@linux.ibm.com>,
Vasily Gorbik <gor@linux.ibm.com>,
Ilya Leoshkevich <iii@linux.ibm.com>,
Masami Hiramatsu <mhiramat@kernel.org>,
Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
Josh Poimboeuf <jpoimboe@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@kernel.org>, Jiri Olsa <jolsa@kernel.org>,
Namhyung Kim <namhyung@kernel.org>,
Thomas Gleixner <tglx@linutronix.de>,
Andrii Nakryiko <andrii@kernel.org>,
Indu Bhagat <indu.bhagat@oracle.com>,
"Jose E. Marchesi" <jemarch@gnu.org>,
Beau Belgrave <beaub@linux.microsoft.com>,
Linus Torvalds <torvalds@linux-foundation.org>,
Andrew Morton <akpm@linux-foundation.org>,
Jens Axboe <axboe@kernel.dk>, Florian Weimer <fweimer@redhat.com>,
Sam James <sam@gentoo.org>
Subject: [RFC PATCH v1 08/16] unwind_user: Enable archs that save RA/FP in other registers
Date: Thu, 10 Jul 2025 18:35:14 +0200 [thread overview]
Message-ID: <20250710163522.3195293-9-jremus@linux.ibm.com> (raw)
In-Reply-To: <20250710163522.3195293-1-jremus@linux.ibm.com>
Enable unwinding of user space for architectures, such as s390, that
save the return address (RA) and/or frame pointer (FP) in other
registers. This is only valid in the topmost frame, for instance when
in a leaf function.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
arch/Kconfig | 7 ++++
arch/x86/include/asm/unwind_user.h | 24 +++++++++---
include/asm-generic/unwind_user.h | 20 ++++++++++
include/asm-generic/unwind_user_sframe.h | 24 ++++++++++++
include/linux/unwind_user_types.h | 18 ++++++++-
kernel/unwind/sframe.c | 4 +-
kernel/unwind/user.c | 47 ++++++++++++++++++++----
7 files changed, 126 insertions(+), 18 deletions(-)
diff --git a/arch/Kconfig b/arch/Kconfig
index 367eaf7e62e0..9e28dffe42cb 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -455,6 +455,13 @@ config HAVE_USER_RA_REG
help
The arch passes the return address (RA) in user space in a register.
+config HAVE_UNWIND_USER_LOC_REG
+ bool
+ help
+ The arch potentially saves the return address (RA) and/or frame
+ pointer (FP) register values in user space in other registers, when
+ in the topmost frame (e.g. in leaf function).
+
config SFRAME_VALIDATION
bool "Enable .sframe section debugging"
depends on HAVE_UNWIND_USER_SFRAME
diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h
index c2881840adf4..925d208aa39d 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -5,18 +5,30 @@
#include <linux/unwind_user_types.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, \
+ .cfa_off = (s32)sizeof(long) * 2, \
+ .ra = { \
+ .loc = UNWIND_USER_LOC_STACK, \
+ .frame_off = (s32)sizeof(long) * -1, \
+ }, \
+ .fp = { \
+ .loc = UNWIND_USER_LOC_STACK, \
+ .frame_off = (s32)sizeof(long) * -2, \
+ }, \
.sp_val_off = (s32)0, \
.use_fp = true,
#ifdef CONFIG_IA32_EMULATION
#define ARCH_INIT_USER_COMPAT_FP_FRAME \
- .cfa_off = (s32)sizeof(u32) * 2, \
- .ra_off = (s32)sizeof(u32) * -1, \
- .fp_off = (s32)sizeof(u32) * -2, \
+ .cfa_off = (s32)sizeof(u32) * 2, \
+ .ra = { \
+ .loc = UNWIND_USER_LOC_STACK, \
+ .frame_off = (s32)sizeof(u32) * -1, \
+ }, \
+ .fp = { \
+ .loc = UNWIND_USER_LOC_STACK, \
+ .frame_off = (s32)sizeof(u32) * -2, \
+ }, \
.sp_val_off = (s32)0, \
.use_fp = true,
diff --git a/include/asm-generic/unwind_user.h b/include/asm-generic/unwind_user.h
index b8882b909944..3891b7cfe3b8 100644
--- a/include/asm-generic/unwind_user.h
+++ b/include/asm-generic/unwind_user.h
@@ -2,4 +2,24 @@
#ifndef _ASM_GENERIC_UNWIND_USER_H
#define _ASM_GENERIC_UNWIND_USER_H
+#include <asm/unwind_user_types.h>
+
+#ifndef unwind_user_get_reg
+
+/**
+ * generic_unwind_user_get_reg - Get register value.
+ * @val: Register value.
+ * @regnum: DWARF register number to obtain the value from.
+ *
+ * Returns zero if successful. Otherwise -EINVAL.
+ */
+static inline int generic_unwind_user_get_reg(unsigned long *val, int regnum)
+{
+ return -EINVAL;
+}
+
+#define unwind_user_get_reg generic_unwind_user_get_reg
+
+#endif /* !unwind_user_get_reg */
+
#endif /* _ASM_GENERIC_UNWIND_USER_H */
diff --git a/include/asm-generic/unwind_user_sframe.h b/include/asm-generic/unwind_user_sframe.h
index 6c87a7f29861..8cef3e0857b6 100644
--- a/include/asm-generic/unwind_user_sframe.h
+++ b/include/asm-generic/unwind_user_sframe.h
@@ -2,8 +2,31 @@
#ifndef _ASM_GENERIC_UNWIND_USER_SFRAME_H
#define _ASM_GENERIC_UNWIND_USER_SFRAME_H
+#include <linux/unwind_user_types.h>
#include <linux/types.h>
+/**
+ * generic_sframe_set_frame_reginfo - Populate info to unwind FP/RA register
+ * from SFrame offset.
+ * @reginfo: Unwind info for FP/RA register.
+ * @offset: SFrame offset value.
+ *
+ * A non-zero offset value denotes a stack offset from CFA and indicates
+ * that the register is saved on the stack. A zero offset value indicates
+ * that the register is not saved.
+ */
+static inline void generic_sframe_set_frame_reginfo(
+ struct unwind_user_reginfo *reginfo,
+ s32 offset)
+{
+ if (offset) {
+ reginfo->loc = UNWIND_USER_LOC_STACK;
+ reginfo->frame_off = offset;
+ } else {
+ reginfo->loc = UNWIND_USER_LOC_NONE;
+ }
+}
+
/**
* generic_sframe_sp_val_off - Get generic SP value offset from CFA.
*
@@ -25,6 +48,7 @@ static inline s32 generic_sframe_sp_val_off(void)
return 0;
}
+#define sframe_set_frame_reginfo generic_sframe_set_frame_reginfo
#define sframe_sp_val_off generic_sframe_sp_val_off
#endif /* _ASM_GENERIC_UNWIND_USER_SFRAME_H */
diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_types.h
index adef01698bb3..57fd16e314cf 100644
--- a/include/linux/unwind_user_types.h
+++ b/include/linux/unwind_user_types.h
@@ -21,10 +21,24 @@ struct unwind_stacktrace {
unsigned long *entries;
};
+enum unwind_user_loc {
+ UNWIND_USER_LOC_NONE,
+ UNWIND_USER_LOC_STACK,
+ UNWIND_USER_LOC_REG,
+};
+
+struct unwind_user_reginfo {
+ enum unwind_user_loc loc;
+ union {
+ s32 frame_off;
+ int regnum;
+ };
+};
+
struct unwind_user_frame {
s32 cfa_off;
- s32 ra_off;
- s32 fp_off;
+ struct unwind_user_reginfo ra;
+ struct unwind_user_reginfo fp;
s32 sp_val_off;
bool use_fp;
};
diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index 5bfaf06e6cd2..43ef3a8c4c26 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c
@@ -314,8 +314,8 @@ static __always_inline int __find_fre(struct sframe_section *sec,
}
frame->cfa_off = fre->cfa_off;
- frame->ra_off = fre->ra_off;
- frame->fp_off = fre->fp_off;
+ sframe_set_frame_reginfo(&frame->ra, fre->ra_off);
+ sframe_set_frame_reginfo(&frame->fp, fre->fp_off);
frame->use_fp = SFRAME_FRE_CFA_BASE_REG_ID(fre->info) == SFRAME_BASE_REG_FP;
frame->sp_val_off = sframe_sp_val_off();
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index 03a6da36192f..ee00d39d2a8e 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -98,26 +98,57 @@ static int unwind_user_next(struct unwind_user_state *state)
/* Get the Return Address (RA) */
- if (frame->ra_off) {
+ switch (frame->ra.loc) {
+ case UNWIND_USER_LOC_NONE:
+ if (!IS_ENABLED(CONFIG_HAVE_USER_RA_REG) || !topmost)
+ goto done;
+ ra = user_return_address(task_pt_regs(current));
+ break;
+ case UNWIND_USER_LOC_STACK:
+ if (!frame->ra.frame_off)
+ goto done;
/* Make sure that the address is word aligned */
shift = sizeof(long) == 4 || compat_fp_state(state) ? 2 : 3;
- if ((cfa + frame->ra_off) & ((1 << shift) - 1))
+ if ((cfa + frame->ra.frame_off) & ((1 << shift) - 1))
goto done;
- if (unwind_get_user_long(ra, cfa + frame->ra_off, state))
+ if (unwind_get_user_long(ra, cfa + frame->ra.frame_off, state))
goto done;
- } else {
- if (!IS_ENABLED(CONFIG_HAVE_USER_RA_REG) || !topmost)
+ break;
+ case UNWIND_USER_LOC_REG:
+ if (!IS_ENABLED(CONFIG_HAVE_UNWIND_USER_LOC_REG) || !topmost)
goto done;
- ra = user_return_address(task_pt_regs(current));
+ if (unwind_user_get_reg(&ra, frame->ra.regnum))
+ goto done;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ goto done;
}
/* Get the Frame Pointer (FP) */
- if (frame->fp_off && unwind_get_user_long(fp, cfa + frame->fp_off, state))
+ switch (frame->fp.loc) {
+ case UNWIND_USER_LOC_NONE:
+ break;
+ case UNWIND_USER_LOC_STACK:
+ if (!frame->fp.frame_off)
+ goto done;
+ if (unwind_get_user_long(fp, cfa + frame->fp.frame_off, state))
+ goto done;
+ break;
+ case UNWIND_USER_LOC_REG:
+ if (!IS_ENABLED(CONFIG_HAVE_UNWIND_USER_LOC_REG) || !topmost)
+ goto done;
+ if (unwind_user_get_reg(&fp, frame->fp.regnum))
+ goto done;
+ break;
+ default:
+ WARN_ON_ONCE(1);
goto done;
+ }
state->ip = ra;
state->sp = sp;
- if (frame->fp_off)
+ if (frame->fp.loc != UNWIND_USER_LOC_NONE)
state->fp = fp;
arch_unwind_user_next(state);
--
2.48.1
next prev parent reply other threads:[~2025-07-10 16:36 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-10 16:35 [RFC PATCH v1 00/16] s390: SFrame user space unwinding Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 01/16] fixup! unwind_user: Add frame pointer support Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 02/16] s390: asm/dwarf.h should only be included in assembly files Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 03/16] s390/vdso: Avoid emitting DWARF CFI for non-vDSO Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 04/16] s390/vdso: Enable SFrame generation in vDSO Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 05/16] s390/vdso: Keep function symbols " Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 06/16] unwind_user: Enable archs that define CFA = SP_callsite + offset Jens Remus
2025-07-16 21:32 ` Josh Poimboeuf
2025-07-17 9:27 ` Jens Remus
2025-07-18 4:51 ` Josh Poimboeuf
2025-07-10 16:35 ` [RFC PATCH v1 07/16] unwind_user: Enable archs that do not necessarily save RA Jens Remus
2025-07-16 23:01 ` Josh Poimboeuf
2025-07-17 11:09 ` Jens Remus
2025-07-18 8:28 ` Jens Remus
2025-07-18 16:59 ` Josh Poimboeuf
2025-07-21 14:25 ` Jens Remus
2025-07-10 16:35 ` Jens Remus [this message]
2025-07-17 2:01 ` [RFC PATCH v1 08/16] unwind_user: Enable archs that save RA/FP in other registers Josh Poimboeuf
2025-07-17 2:50 ` Josh Poimboeuf
2025-07-17 12:07 ` Jens Remus
2025-07-18 4:52 ` Josh Poimboeuf
2025-07-17 3:57 ` Steven Rostedt
2025-07-17 7:24 ` Josh Poimboeuf
2025-07-17 12:05 ` Steven Rostedt
2025-07-17 11:28 ` Jens Remus
2025-07-17 12:10 ` Steven Rostedt
2025-07-18 4:51 ` Josh Poimboeuf
2025-07-10 16:35 ` [RFC PATCH v1 09/16] unwind_user/sframe: Enable archs with encoded SFrame CFA offsets Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 10/16] s390/ptrace: Enable HAVE_USER_RA_REG Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 11/16] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME Jens Remus
2025-08-01 12:53 ` Heiko Carstens
2025-08-01 15:46 ` Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 12/16] unwind_user/backchain: Introduce back chain user space unwinding Jens Remus
2025-07-17 2:06 ` Josh Poimboeuf
2025-07-17 12:20 ` Jens Remus
2025-07-18 5:19 ` Josh Poimboeuf
2025-08-01 12:36 ` Heiko Carstens
2025-08-01 15:49 ` Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 13/16] s390/unwind_user/backchain: Enable HAVE_UNWIND_USER_BACKCHAIN Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 14/16] PREREQ: x86/asm: Avoid emitting DWARF CFI for non-VDSO Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 15/16] PREREQ: x86/vdso: Enable sframe generation in VDSO Jens Remus
2025-07-10 16:35 ` [RFC PATCH v1 16/16] WIP: fixup! s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME Jens Remus
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250710163522.3195293-9-jremus@linux.ibm.com \
--to=jremus@linux.ibm.com \
--cc=akpm@linux-foundation.org \
--cc=andrii@kernel.org \
--cc=axboe@kernel.dk \
--cc=beaub@linux.microsoft.com \
--cc=bpf@vger.kernel.org \
--cc=fweimer@redhat.com \
--cc=gor@linux.ibm.com \
--cc=hca@linux.ibm.com \
--cc=iii@linux.ibm.com \
--cc=indu.bhagat@oracle.com \
--cc=jemarch@gnu.org \
--cc=jolsa@kernel.org \
--cc=jpoimboe@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=mhiramat@kernel.org \
--cc=mingo@kernel.org \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
--cc=rostedt@kernel.org \
--cc=sam@gentoo.org \
--cc=tglx@linutronix.de \
--cc=torvalds@linux-foundation.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.