[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260127151926.2805123-10-jremus@linux.ibm.com>
Date: Tue, 27 Jan 2026 16:19:22 +0100
From: Jens Remus <jremus@...ux.ibm.com>
To: linux-kernel@...r.kernel.org, linux-trace-kernel@...r.kernel.org,
linux-s390@...r.kernel.org, bpf@...r.kernel.org, x86@...nel.org,
Steven Rostedt <rostedt@...nel.org>
Cc: Jens Remus <jremus@...ux.ibm.com>, Heiko Carstens <hca@...ux.ibm.com>,
Vasily Gorbik <gor@...ux.ibm.com>,
Ilya Leoshkevich <iii@...ux.ibm.com>,
Josh Poimboeuf <jpoimboe@...nel.org>,
Masami Hiramatsu <mhiramat@...nel.org>,
Mathieu Desnoyers <mathieu.desnoyers@...icios.com>,
Peter Zijlstra <peterz@...radead.org>, Ingo Molnar <mingo@...nel.org>,
Jiri Olsa <jolsa@...nel.org>,
Arnaldo Carvalho de Melo <acme@...nel.org>,
Namhyung Kim <namhyung@...nel.org>,
Thomas Gleixner <tglx@...utronix.de>,
Andrii Nakryiko <andrii@...nel.org>,
Indu Bhagat <indu.bhagat@...cle.com>,
"Jose E. Marchesi" <jemarch@....org>,
Beau Belgrave <beaub@...ux.microsoft.com>,
Linus Torvalds <torvalds@...ux-foundation.org>,
Andrew Morton <akpm@...ux-foundation.org>,
Florian Weimer <fweimer@...hat.com>, Kees Cook <kees@...nel.org>,
"Carlos O'Donell" <codonell@...hat.com>, Sam James <sam@...too.org>,
Dylan Hatch <dylanbhatch@...gle.com>
Subject: [PATCH v4 09/12] s390/unwind_user/sframe: Enable sframe unwinding on s390
Add s390 support for unwinding of user space using SFrame. This
leverages the previous commits to address the following s390
particularities:
- The CFA is defined as the value of the stack pointer (SP) at call
site in the previous frame plus 160. Therefore the SP unwinds as
SP = CFA - 160. Therefore use a SP value offset from CFA of -160.
- The return address (RA) is not saved on the stack at function entry.
It is also not saved in the function prologue, when in leaf functions.
Therefore the RA does not necessarily need to be unwound in the
topmost frame.
- The frame pointer (FP) and/or return address (RA) may be saved in
other registers when in leaf functions. GCC effectively uses
floating-point registers (FPR) for this purpose. In SFrame V3 this
is represented using flexible FDEs, where the CFA, FP, and RA recovery
rules may specify a DWARF register number.
- To make use of the signed 8-bit SFrame data word size and effectively
reduce the .sframe section size the SFrame CFA offset values are
encoded as (CFA - 160) / 8. This is because the lowest CFA offset
value on s390 is by definition +160 (= value at function entry),
which does not fit into a signed 8-bit SFrame data word / offset.
Therefore the CFA offset values are stored adjusted by -160.
Additionally they are scaled by the s390-specific DWARF data scaling
factor of 8. The s390x ELF ABI [1] guarantees that the CFA offset
values are always aligned on an 8-byte boundary.
Add s390-specific SFrame format definitions.
Include <asm/unwind_user_sframe.h> after "sframe.h" to make those
s390-specific definitions available to architecture-specific unwind
user sframe code, particularly the s390-specific one.
[1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases
Signed-off-by: Jens Remus <jremus@...ux.ibm.com>
---
Notes (jremus):
Changes in v4:
- Fix __s390_get_dwarf_fpr() access of user FPR. (Heiko)
- Use __s390_dwarf_fpr_to_fpr() helper instead of large switch/case
block. (Heiko)
- Use unsigned int for DWARF register numbers, as DWARF defines them
as unsigned LEB128.
- SFrame V3 support:
- Remove now unused arch_sframe_init_reginfo().
- Remove now unused SFRAME_V2_S390X_OFFSET_IS_REGNUM() and
SFRAME_V2_S390X_OFFSET_DECODE_REGNUM() macros.
- Rename SFRAME_V2_*() macros to SFRAME_V3_*().
- Add architecture-specific defines SFRAME_REG_SP and SFRAME_REG_FP.
Changes in RFC v3:
- Adjust to rename of UNWIND_USER_LOC_NONE to UNWIND_USER_LOC_RETAIN.
- Adjust s390-specific unwind_user_word_size() to changes in the
x86-specific (see patch 4).
Changes in RFC v2:
- Provide unwind_user_word_size() to satisfy new unwind user need. Note
that support for COMPAT has not been implemented as s390 support for
COMPAT is expected to be removed with v6.19:
https://lore.kernel.org/all/20251201102713.22472A5b-hca@linux.ibm.com/
- Adjust to changes in preceding patches in this series that enable
support in unwind user (sframe) for s390 particularities.
Alternatively the s390-specific definitions could also be added to the
s390-specific unwind user sframe header. The current implementation
follows Binutils approach to have all SFrame format definitions in one
central header file.
arch/s390/Kconfig | 1 +
arch/s390/include/asm/unwind_user.h | 70 ++++++++++++++++++++++
arch/s390/include/asm/unwind_user_sframe.h | 21 +++++++
kernel/unwind/sframe.c | 2 +-
kernel/unwind/sframe.h | 11 ++++
5 files changed, 104 insertions(+), 1 deletion(-)
create mode 100644 arch/s390/include/asm/unwind_user.h
create mode 100644 arch/s390/include/asm/unwind_user_sframe.h
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 0e5fad5f06ca..063f0c857600 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -250,6 +250,7 @@ config S390
select HAVE_SOFTIRQ_ON_OWN_STACK
select HAVE_STACKPROTECTOR if CC_HAS_STACKPROTECTOR_GLOBAL
select HAVE_SYSCALL_TRACEPOINTS
+ select HAVE_UNWIND_USER_SFRAME
select HAVE_VIRT_CPU_ACCOUNTING
select HAVE_VIRT_CPU_ACCOUNTING_IDLE
select HOTPLUG_SMT
diff --git a/arch/s390/include/asm/unwind_user.h b/arch/s390/include/asm/unwind_user.h
new file mode 100644
index 000000000000..941aa3f0f70f
--- /dev/null
+++ b/arch/s390/include/asm/unwind_user.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_S390_UNWIND_USER_H
+#define _ASM_S390_UNWIND_USER_H
+
+#include <linux/sched/task_stack.h>
+#include <linux/types.h>
+#include <asm/fpu.h>
+
+#ifdef CONFIG_UNWIND_USER
+
+static inline int unwind_user_word_size(struct pt_regs *regs)
+{
+ return 8;
+}
+
+static inline int arch_unwind_user_get_ra_reg(unsigned long *val)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ *val = regs->gprs[14];
+ return 0;
+}
+#define unwind_user_get_ra_reg arch_unwind_user_get_ra_reg
+
+static inline unsigned long __s390_dwarf_fpr_to_fpr(unsigned int regnum)
+{
+ unsigned int fpr;
+
+ /*
+ * Convert from s390 DWARF floating-point register number (16..31)
+ * to floating-point register number (0..15): left rotate the least
+ * significant three bits and then return the least significant four
+ * bits.
+ */
+ fpr = (regnum & 3) << 1;
+ fpr |= (regnum & 4) >> 2;
+ fpr |= (regnum & 8);
+ return fpr;
+}
+
+static inline unsigned long __s390_get_dwarf_fpr(unsigned int regnum)
+{
+ struct fpu *fpu = ¤t->thread.ufpu;
+
+ save_user_fpu_regs();
+ return fpu->vxrs[__s390_dwarf_fpr_to_fpr(regnum)].high;
+}
+
+static inline int arch_unwind_user_get_reg(unsigned long *val,
+ unsigned int regnum)
+{
+ if (regnum <= 15) {
+ /* DWARF register numbers 0..15 */
+ struct pt_regs *regs = task_pt_regs(current);
+ *val = regs->gprs[regnum];
+ return 0;
+ } else if (regnum <= 31) {
+ /* DWARF register numbers 16..31 */
+ *val = __s390_get_dwarf_fpr(regnum);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+#define unwind_user_get_reg arch_unwind_user_get_reg
+
+#endif /* CONFIG_UNWIND_USER */
+
+#include <asm-generic/unwind_user.h>
+
+#endif /* _ASM_S390_UNWIND_USER_H */
diff --git a/arch/s390/include/asm/unwind_user_sframe.h b/arch/s390/include/asm/unwind_user_sframe.h
new file mode 100644
index 000000000000..91eea28c8a48
--- /dev/null
+++ b/arch/s390/include/asm/unwind_user_sframe.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_S390_UNWIND_USER_SFRAME_H
+#define _ASM_S390_UNWIND_USER_SFRAME_H
+
+#include <linux/unwind_user.h>
+#include <linux/types.h>
+
+#define SFRAME_SP_OFFSET SFRAME_S390X_SP_VAL_OFFSET
+
+#define SFRAME_REG_SP 15
+#define SFRAME_REG_FP 11 /* "preferred" FP register */
+
+static inline s32 arch_sframe_cfa_offset_decode(s32 offset)
+{
+ return SFRAME_V3_S390X_CFA_OFFSET_DECODE(offset);
+}
+#define sframe_cfa_offset_decode arch_sframe_cfa_offset_decode
+
+#include <asm-generic/unwind_user_sframe.h>
+
+#endif /* _ASM_S390_UNWIND_USER_SFRAME_H */
diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index 5ac502f16bad..21283e3bda42 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c
@@ -12,11 +12,11 @@
#include <linux/mm.h>
#include <linux/string_helpers.h>
#include <linux/sframe.h>
-#include <asm/unwind_user_sframe.h>
#include <linux/unwind_user_types.h>
#include "sframe.h"
#include "sframe_debug.h"
+#include <asm/unwind_user_sframe.h>
struct sframe_fde_internal {
unsigned long func_addr;
diff --git a/kernel/unwind/sframe.h b/kernel/unwind/sframe.h
index 5b6112945b6c..8a5322e95403 100644
--- a/kernel/unwind/sframe.h
+++ b/kernel/unwind/sframe.h
@@ -19,6 +19,7 @@
#define SFRAME_ABI_AARCH64_ENDIAN_BIG 1
#define SFRAME_ABI_AARCH64_ENDIAN_LITTLE 2
#define SFRAME_ABI_AMD64_ENDIAN_LITTLE 3
+#define SFRAME_ABI_S390X_ENDIAN_BIG 4 /* s390 64-bit (s390x) */
struct sframe_preamble {
u16 magic;
@@ -84,4 +85,14 @@ struct sframe_fda_v3 {
#define SFRAME_V3_FLEX_FDE_CTLWORD_DEREF_P(data) (((data) >> 1) & 0x1)
#define SFRAME_V3_FLEX_FDE_CTLWORD_REG_P(data) ((data) & 0x1)
+/* s390 64-bit (s390x) */
+
+#define SFRAME_S390X_SP_VAL_OFFSET (-160)
+
+#define SFRAME_S390X_CFA_OFFSET_ADJUSTMENT SFRAME_S390X_SP_VAL_OFFSET
+#define SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR 8
+#define SFRAME_V3_S390X_CFA_OFFSET_DECODE(offset) \
+ (((offset) * SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR) \
+ - SFRAME_S390X_CFA_OFFSET_ADJUSTMENT)
+
#endif /* _SFRAME_H */
--
2.51.0
Powered by blists - more mailing lists