[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250710163522.3195293-12-jremus@linux.ibm.com>
Date: Thu, 10 Jul 2025 18:35:17 +0200
From: Jens Remus <jremus@...ux.ibm.com>
To: linux-kernel@...r.kernel.org, linux-trace-kernel@...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>,
Masami Hiramatsu <mhiramat@...nel.org>,
Mathieu Desnoyers <mathieu.desnoyers@...icios.com>,
Josh Poimboeuf <jpoimboe@...nel.org>,
Peter Zijlstra <peterz@...radead.org>, Ingo Molnar <mingo@...nel.org>,
Jiri Olsa <jolsa@...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>,
Jens Axboe <axboe@...nel.dk>, Florian Weimer <fweimer@...hat.com>,
Sam James <sam@...too.org>
Subject: [RFC PATCH v1 11/16] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME
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 + 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 first
unwinding step for 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. Therefore DWARF
register numbers may be encoded in the SFrame FP/RA offsets.
- To make use of the signed 8-bit SFrame offset 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 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.
[1]: s390x ELF ABI,
https://github.com/IBM/s390x-abi/releases
Signed-off-by: Jens Remus <jremus@...ux.ibm.com>
---
arch/s390/Kconfig | 2 +
arch/s390/include/asm/unwind_user.h | 83 ++++++++++++++++++++++
arch/s390/include/asm/unwind_user_sframe.h | 37 ++++++++++
3 files changed, 122 insertions(+)
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 f4ea52c1f0ba..8b29a8f0f9c3 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -239,6 +239,8 @@ config S390
select HAVE_SETUP_PER_CPU_AREA
select HAVE_SOFTIRQ_ON_OWN_STACK
select HAVE_SYSCALL_TRACEPOINTS
+ select HAVE_UNWIND_USER_LOC_REG
+ select HAVE_UNWIND_USER_SFRAME
select HAVE_USER_RA_REG
select HAVE_VIRT_CPU_ACCOUNTING
select HAVE_VIRT_CPU_ACCOUNTING_IDLE
diff --git a/arch/s390/include/asm/unwind_user.h b/arch/s390/include/asm/unwind_user.h
new file mode 100644
index 000000000000..daae1545e203
--- /dev/null
+++ b/arch/s390/include/asm/unwind_user.h
@@ -0,0 +1,83 @@
+/* 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-insn.h>
+
+static inline void __s390_get_dwarf_fpr(unsigned long *val, int regnum)
+{
+ switch (regnum) {
+ case 16:
+ fpu_std(0, (freg_t *)val);
+ break;
+ case 17:
+ fpu_std(2, (freg_t *)val);
+ break;
+ case 18:
+ fpu_std(4, (freg_t *)val);
+ break;
+ case 19:
+ fpu_std(6, (freg_t *)val);
+ break;
+ case 20:
+ fpu_std(1, (freg_t *)val);
+ break;
+ case 21:
+ fpu_std(3, (freg_t *)val);
+ break;
+ case 22:
+ fpu_std(5, (freg_t *)val);
+ break;
+ case 23:
+ fpu_std(7, (freg_t *)val);
+ break;
+ case 24:
+ fpu_std(8, (freg_t *)val);
+ break;
+ case 25:
+ fpu_std(10, (freg_t *)val);
+ break;
+ case 26:
+ fpu_std(12, (freg_t *)val);
+ break;
+ case 27:
+ fpu_std(14, (freg_t *)val);
+ break;
+ case 28:
+ fpu_std(9, (freg_t *)val);
+ break;
+ case 29:
+ fpu_std(11, (freg_t *)val);
+ break;
+ case 30:
+ fpu_std(13, (freg_t *)val);
+ break;
+ case 31:
+ fpu_std(15, (freg_t *)val);
+ break;
+ default:
+ *val = 0;
+ }
+}
+
+static inline int s390_unwind_user_get_reg(unsigned long *val, int regnum)
+{
+ if (0 <= regnum && regnum <= 15) {
+ struct pt_regs *regs = task_pt_regs(current);
+ *val = regs->gprs[regnum];
+ } else if (16 <= regnum && regnum <= 31) {
+ __s390_get_dwarf_fpr(val, regnum);
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#define unwind_user_get_reg s390_unwind_user_get_reg
+
+#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..2216e6921fd8
--- /dev/null
+++ b/arch/s390/include/asm/unwind_user_sframe.h
@@ -0,0 +1,37 @@
+/* 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>
+
+static inline s32 arch_sframe_cfa_offset_decode(s32 offset)
+{
+ return (offset << 3) + 160;
+}
+
+static inline void arch_sframe_set_frame_reginfo(
+ struct unwind_user_reginfo *reginfo,
+ s32 offset)
+{
+ if (offset & 1) {
+ reginfo->loc = UNWIND_USER_LOC_REG;
+ reginfo->regnum = offset >> 1;
+ } else if (offset) {
+ reginfo->loc = UNWIND_USER_LOC_STACK;
+ reginfo->frame_off = offset;
+ } else {
+ reginfo->loc = UNWIND_USER_LOC_NONE;
+ }
+}
+
+static inline s32 arch_sframe_sp_val_off(void)
+{
+ return -160;
+}
+
+#define sframe_cfa_offset_decode arch_sframe_cfa_offset_decode
+#define sframe_set_frame_reginfo arch_sframe_set_frame_reginfo
+#define sframe_sp_val_off arch_sframe_sp_val_off
+
+#endif /* _ASM_S390_UNWIND_USER_SFRAME_H */
--
2.48.1
Powered by blists - more mailing lists