* [RFC PATCH v2 00/15] s390: SFrame user space unwinding
@ 2025-12-05 17:14 Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 01/15] unwind_user: Enhance comments on get CFA, FP, and RA Jens Remus
` (14 more replies)
0 siblings, 15 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
This RFC series adds s390 support for unwinding of user space using
SFrame. It is based on Josh's, Steven's, and my work (see prerequisites
below). The generic unwind user (sframe) frameworks are extended to
enable support for a few s390-particularities (see patches 8-11),
including unwinding of user space using back chain (see patch 12).
The latter could be broken apart as a separate patch series.
Changes in RFC v2:
- Rebased on latest "unwind user" enhancements from Peter Zijlstra and
my latest "unwind user sframe" series v12.
- Incorporated RFC v1 review feedback.
- No new config options (except for unwind user backchain).
Motivation:
On s390 unwinding using frame pointer (FP) is unsupported, because of
lack of proper s390 64-bit (s390x) ABI specification and compiler
support. The ABI does only specify a "preferred" FP register. Both GCC
and Clang, regardless of compiler option -fno-omit-frame-pointer, setup
the preferred FP register as late as possible, which usually is after
static stack allocation, so that the CFA cannot be deduced from the FP
without any further data, such as provided by DWARF CFI or SFrame.
In theory there is a s390-specific alternative of unwinding using
back chain (compiler option -mbackchain), but this has its own
limitations. Ubuntu is currently the only distribution that that
builds user space with back chain.
As a consequence the Kernel stack tracer cannot unwind user space
(except if it is built with back chain). Recording call graphs of user
space using perf is limited to stack dump sampling (i.e. perf record
--call-graph dwarf), which generates a fairly large amount of data and
has limitations.
Initial testing of recording call graphs using perf using the s390
support for SFrame provided by RFC v1 of this series shows that
data size notably improves:
perf record data size is greatly reduced (smaller perf.data):
SFrame (--call-graph fp):
# perf record -F 9999 --call-graph fp objdump -wdWF objdump
[ perf record: Woken up 9 times to write data ]
[ perf record: Captured and wrote 2.498 MB perf.data (10891 samples) ]
Stack sampling (--call-graph dwarf) with a default stack size of 8192:
# perf record -F 9999 --call-graph dwarf objdump -wdWF objdump
[ perf record: Woken up 270 times to write data ]
[ perf record: Captured and wrote 67.467 MB perf.data (8241 samples) ]
Prerequirements:
This RFC series applies on top of the latest unwind user sframe series
"[PATCH v12 00/13] unwind_deferred: Implement sframe handling":
https://lore.kernel.org/all/20251119132323.1281768-1-jremus@linux.ibm.com/
It depends on binutils 2.45 to build executables and libraries
(e.g. vDSO) with SFrame on s390, including the latest SFrame V2 with
PC-relative FDE encoding. Optionally a binutils mainline build is
required for SFrame V2 with outermost frame indication.
The unwind user sframe series depends on a Glibc patch from Josh, that
adds support for the prctls introduced in the Kernel:
https://lore.kernel.org/all/20250122023517.lmztuocecdjqzfhc@jpoimboe/
Note that Josh's Glibc patch needs to be adjusted for the updated prctl
numbers from "[PATCH v12 13/13] unwind_user/sframe: Add prctl()
interface for registering .sframe sections":
https://lore.kernel.org/all/20251119132323.1281768-14-jremus@linux.ibm.com/
Overview:
Patches 1-3 originate from my "[PATCH v3 0/3] unwind_user: Cleanups"
series and can be ignored here (please review in the respective series):
https://lore.kernel.org/all/20251202150814.3505869-1-jremus@linux.ibm.com/
Patch 4 aligns asm/dwarf.h to x86 asm/dwarf2.h.
Patch 5 replicates Josh's x86 patch "x86/asm: Avoid emitting DWARF
CFI for non-VDSO" for s390.
Patch 6 changes the build of the vDSO on s390 to keep the function
symbols for stack tracing purposes.
Patch 7 replicates Josh's patch "x86/vdso: Enable sframe generation
in VDSO" for s390. It enables generation of SFrame stack trace
information (.sframe section) for the vDSO if the assembler supports it.
Patches 8-11 enable Josh's generic unwind user (sframe) frameworks to
support the following s390 particularities:
- Patch 8 adds support for architectures that define their CFA as SP at
callsite + offset.
- Patch 9 adds support support for architectures that pass the return
address (RA) in a register instead of on the stack and that do not
necessarily save the RA on the stack (or in another register) in the
topmost frame (e.g. in the prologue or in leaf functions).
- Patch 10 adds support for architectures that save RA/FP in other
registers instead of on the stack, e.g. in leaf functions.
- Patch 11 adds support for architectures that store the CFA offset
from CFA base register (e.g. SP or FP) in SFrame encoded. For
instance on s390 the CFA offset is stored adjusted by -160 and
then scaled down by 8 to enable and improve the use of signed 8-bit
SFrame offsets (i.e. CFA, RA, and FP offset).
Patch 12 introduces frame_pointer() in ptrace on s390, which is a
prerequisite for enabling unwind user.
Patch 13 adds support for unwinding of user space using SFrame on
s390. It leverages the extensions of the generic unwind user (sframe)
frameworks from patches 8-11.
Patch 14 introduces unwind user backchain to perform unwinding of user
space using back chain, such as on s390.
Patch 15 adds support for unwinding of user space using back chain on
s390. Main reasons to support back chain on s390 are:
- With Ubuntu there is a major distribution that builds user space with
back chain.
- Java JREs, such as OpenJDK, do maintain the back chain in jitted code.
Limitations:
Unwinding of user space using back chain cannot - by design - restore
the FP. Therefore unwinding of subsequent frames using e.g. SFrame may
fail, if the FP is the CFA base register.
Thanks and regards,
Jens
Jens Remus (15):
unwind_user: Enhance comments on get CFA, FP, and RA
unwind_user/fp: Use dummies instead of ifdef
x86/unwind_user: Guard unwind_user_word_size() by UNWIND_USER
s390: asm/dwarf.h should only be included in assembly files
s390/vdso: Avoid emitting DWARF CFI for non-vDSO
s390/vdso: Keep function symbols in vDSO
s390/vdso: Enable SFrame generation in vDSO
unwind_user: Enable archs that define CFA = SP_callsite + offset
unwind_user: Enable archs that pass RA in a register
unwind_user: Enable archs that save RA/FP in other registers
unwind_user/sframe: Enable archs with encoded SFrame CFA offsets
s390/ptrace: Provide frame_pointer()
s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME
unwind_user/backchain: Introduce back chain user space unwinding
s390/unwind_user/backchain: Enable HAVE_UNWIND_USER_BACKCHAIN
arch/Kconfig | 9 ++
arch/s390/Kconfig | 2 +
arch/s390/include/asm/dwarf.h | 53 ++++++----
arch/s390/include/asm/ptrace.h | 18 +++-
arch/s390/include/asm/unwind_user.h | 100 ++++++++++++++++++
arch/s390/include/asm/unwind_user_sframe.h | 33 ++++++
arch/s390/kernel/Makefile | 2 +
arch/s390/kernel/unwind_user_backchain.c | 112 +++++++++++++++++++++
arch/s390/kernel/vdso64/Makefile | 9 +-
arch/s390/kernel/vdso64/vdso64.lds.S | 9 ++
arch/x86/include/asm/unwind_user.h | 50 ++++++---
include/asm-generic/Kbuild | 1 +
include/asm-generic/unwind_user_sframe.h | 35 +++++++
include/linux/unwind_user.h | 36 ++++++-
include/linux/unwind_user_backchain.h | 20 ++++
include/linux/unwind_user_types.h | 21 +++-
kernel/unwind/sframe.c | 13 +--
kernel/unwind/sframe.h | 14 +++
kernel/unwind/user.c | 75 ++++++++++----
19 files changed, 548 insertions(+), 64 deletions(-)
create mode 100644 arch/s390/include/asm/unwind_user.h
create mode 100644 arch/s390/include/asm/unwind_user_sframe.h
create mode 100644 arch/s390/kernel/unwind_user_backchain.c
create mode 100644 include/asm-generic/unwind_user_sframe.h
create mode 100644 include/linux/unwind_user_backchain.h
--
2.51.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC PATCH v2 01/15] unwind_user: Enhance comments on get CFA, FP, and RA
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 02/15] unwind_user/fp: Use dummies instead of ifdef Jens Remus
` (13 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
Move the comment "Get the Canonical Frame Address (CFA)" to the top
of the sequence of statements that actually get the CFA. Reword the
comment "Find the Return Address (RA)" to "Get ...", as the statements
actually get the RA. Add a respective comment to the statements that
get the FP. This will be useful once future commits extend the logic
to get the RA and FP.
While at it align the comment on the "stack going in wrong direction"
check to the following one on the "address is word aligned" check.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
kernel/unwind/user.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index d053295b1f7e..f81c36ab2861 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -38,6 +38,7 @@ static int unwind_user_next_common(struct unwind_user_state *state,
return 0;
}
+ /* Get the Canonical Frame Address (CFA) */
if (frame->use_fp) {
if (state->fp < state->sp)
return -EINVAL;
@@ -45,11 +46,9 @@ static int unwind_user_next_common(struct unwind_user_state *state,
} else {
cfa = state->sp;
}
-
- /* Get the Canonical Frame Address (CFA) */
cfa += frame->cfa_off;
- /* stack going in wrong direction? */
+ /* Make sure that stack is not going in wrong direction */
if (cfa <= state->sp)
return -EINVAL;
@@ -57,10 +56,11 @@ static int unwind_user_next_common(struct unwind_user_state *state,
if (cfa & (state->ws - 1))
return -EINVAL;
- /* Find the Return Address (RA) */
+ /* Get the Return Address (RA) */
if (get_user_word(&ra, cfa, frame->ra_off, state->ws))
return -EINVAL;
+ /* Get the Frame Pointer (FP) */
if (frame->fp_off && get_user_word(&fp, cfa, frame->fp_off, state->ws))
return -EINVAL;
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 02/15] unwind_user/fp: Use dummies instead of ifdef
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 01/15] unwind_user: Enhance comments on get CFA, FP, and RA Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 03/15] x86/unwind_user: Guard unwind_user_word_size() by UNWIND_USER Jens Remus
` (12 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
This simplifies the code. unwind_user_next_fp() does not need to
return -EINVAL if config option HAVE_UNWIND_USER_FP is disabled, as
unwind_user_start() will then not select this unwind method and
unwind_user_next() will therefore not call it.
Provide (1) a dummy definition of ARCH_INIT_USER_FP_FRAME, if the unwind
user method HAVE_UNWIND_USER_FP is not enabled, (2) a common fallback
definition of unwind_user_at_function_start() which returns false, and
(3) a common dummy definition of ARCH_INIT_USER_FP_ENTRY_FRAME.
Note that enabling the config option HAVE_UNWIND_USER_FP without
defining ARCH_INIT_USER_FP_FRAME triggers a compile error, which is
helpful when implementing support for this unwind user method in an
architecture. Enabling the config option when providing an arch-
specific unwind_user_at_function_start() definition makes it necessary
to also provide an arch-specific ARCH_INIT_USER_FP_ENTRY_FRAME
definition.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
Notes (jremus):
Changes in v3:
- Remove comment on #endif. (Ingo)
Changes in v2:
- Add parameter ws to ARCH_INIT_USER_{FP_FRAME|FP_ENTRY_FRAME}.
- Provide common fallback of unwind_user_at_function_start().
- Provide common dummy of ARCH_INIT_USER_FP_ENTRY_FRAME.
- Reword commit message accordingly.
arch/x86/include/asm/unwind_user.h | 1 +
include/linux/unwind_user.h | 18 ++++++++++++++++--
kernel/unwind/user.c | 4 ----
3 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h
index f9a1c460150d..a528eee80dd6 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -37,6 +37,7 @@ static inline bool unwind_user_at_function_start(struct pt_regs *regs)
{
return is_uprobe_at_func_entry(regs);
}
+#define unwind_user_at_function_start unwind_user_at_function_start
#endif /* CONFIG_HAVE_UNWIND_USER_FP */
diff --git a/include/linux/unwind_user.h b/include/linux/unwind_user.h
index 7f7282516bf5..64618618febd 100644
--- a/include/linux/unwind_user.h
+++ b/include/linux/unwind_user.h
@@ -5,8 +5,22 @@
#include <linux/unwind_user_types.h>
#include <asm/unwind_user.h>
-#ifndef ARCH_INIT_USER_FP_FRAME
- #define ARCH_INIT_USER_FP_FRAME
+#ifndef CONFIG_HAVE_UNWIND_USER_FP
+
+#define ARCH_INIT_USER_FP_FRAME(ws)
+
+#endif
+
+#ifndef ARCH_INIT_USER_FP_ENTRY_FRAME
+#define ARCH_INIT_USER_FP_ENTRY_FRAME(ws)
+#endif
+
+#ifndef unwind_user_at_function_start
+static inline bool unwind_user_at_function_start(struct pt_regs *regs)
+{
+ return false;
+}
+#define unwind_user_at_function_start unwind_user_at_function_start
#endif
int unwind_user(struct unwind_stacktrace *trace, unsigned int max_entries);
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index f81c36ab2861..fdb1001e3750 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -74,7 +74,6 @@ static int unwind_user_next_common(struct unwind_user_state *state,
static int unwind_user_next_fp(struct unwind_user_state *state)
{
-#ifdef CONFIG_HAVE_UNWIND_USER_FP
struct pt_regs *regs = task_pt_regs(current);
if (state->topmost && unwind_user_at_function_start(regs)) {
@@ -88,9 +87,6 @@ static int unwind_user_next_fp(struct unwind_user_state *state)
ARCH_INIT_USER_FP_FRAME(state->ws)
};
return unwind_user_next_common(state, &fp_frame);
-#else
- return -EINVAL;
-#endif
}
static int unwind_user_next_sframe(struct unwind_user_state *state)
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 03/15] x86/unwind_user: Guard unwind_user_word_size() by UNWIND_USER
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 01/15] unwind_user: Enhance comments on get CFA, FP, and RA Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 02/15] unwind_user/fp: Use dummies instead of ifdef Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:23 ` Linus Torvalds
2025-12-05 17:14 ` [RFC PATCH v2 04/15] s390: asm/dwarf.h should only be included in assembly files Jens Remus
` (11 subsequent siblings)
14 siblings, 1 reply; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
The unwind user framework in general requires an architecture-specific
implementation of unwind_user_word_size() to be present for any unwind
method, whether that is fp or a future other method, such as potentially
sframe.
Guard unwind_user_word_size() by the availability of the UNWIND_USER
framework instead of the specific HAVE_UNWIND_USER_FP method.
This facilitates to selectively disable HAVE_UNWIND_USER_FP on x86
(e.g. for test purposes) once a new unwind method is added to unwind
user.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
Notes (jremus):
Changes in v3:
- Move includes into more common UNWIND_USER guard at the top of the
source. asm/ptrace.h is required for struct pt_regs.
arch/x86/include/asm/unwind_user.h | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h
index a528eee80dd6..4d699e4954ed 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -2,11 +2,27 @@
#ifndef _ASM_X86_UNWIND_USER_H
#define _ASM_X86_UNWIND_USER_H
-#ifdef CONFIG_HAVE_UNWIND_USER_FP
+#ifdef CONFIG_UNWIND_USER
#include <asm/ptrace.h>
#include <asm/uprobes.h>
+static inline int unwind_user_word_size(struct pt_regs *regs)
+{
+ /* We can't unwind VM86 stacks */
+ if (regs->flags & X86_VM_MASK)
+ return 0;
+#ifdef CONFIG_X86_64
+ if (!user_64bit_mode(regs))
+ return sizeof(int);
+#endif
+ return sizeof(long);
+}
+
+#endif /* CONFIG_UNWIND_USER */
+
+#ifdef CONFIG_HAVE_UNWIND_USER_FP
+
#define ARCH_INIT_USER_FP_FRAME(ws) \
.cfa_off = 2*(ws), \
.ra_off = -1*(ws), \
@@ -21,18 +37,6 @@
.use_fp = false, \
.outermost = false,
-static inline int unwind_user_word_size(struct pt_regs *regs)
-{
- /* We can't unwind VM86 stacks */
- if (regs->flags & X86_VM_MASK)
- return 0;
-#ifdef CONFIG_X86_64
- if (!user_64bit_mode(regs))
- return sizeof(int);
-#endif
- return sizeof(long);
-}
-
static inline bool unwind_user_at_function_start(struct pt_regs *regs)
{
return is_uprobe_at_func_entry(regs);
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 04/15] s390: asm/dwarf.h should only be included in assembly files
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
` (2 preceding siblings ...)
2025-12-05 17:14 ` [RFC PATCH v2 03/15] x86/unwind_user: Guard unwind_user_word_size() by UNWIND_USER Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 05/15] s390/vdso: Avoid emitting DWARF CFI for non-vDSO Jens Remus
` (10 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
Align to x86 and add a compile-time check that asm/dwarf.h is only
included in pure assembly files.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
Notes (jremus):
Changes in RFC v2:
- Adjust to upstream change of __ASSEMBLY__ to __ASSEMBLER__.
arch/s390/include/asm/dwarf.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/s390/include/asm/dwarf.h b/arch/s390/include/asm/dwarf.h
index e3ad6798d0cd..df9f467910f7 100644
--- a/arch/s390/include/asm/dwarf.h
+++ b/arch/s390/include/asm/dwarf.h
@@ -2,7 +2,9 @@
#ifndef _ASM_S390_DWARF_H
#define _ASM_S390_DWARF_H
-#ifdef __ASSEMBLER__
+#ifndef __ASSEMBLER__
+#warning "asm/dwarf.h should be only included in pure assembly files"
+#endif
#define CFI_STARTPROC .cfi_startproc
#define CFI_ENDPROC .cfi_endproc
@@ -33,6 +35,4 @@
.cfi_sections .eh_frame, .debug_frame
#endif
-#endif /* __ASSEMBLER__ */
-
#endif /* _ASM_S390_DWARF_H */
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 05/15] s390/vdso: Avoid emitting DWARF CFI for non-vDSO
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
` (3 preceding siblings ...)
2025-12-05 17:14 ` [RFC PATCH v2 04/15] s390: asm/dwarf.h should only be included in assembly files Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 06/15] s390/vdso: Keep function symbols in vDSO Jens Remus
` (9 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
This replicates Josh's x86 commit TODO ("x86/asm: Avoid emitting DWARF
CFI for non-VDSO") for s390. It also aligns asm/dwarf.h to x86
asm/dwarf2.h.
It was decided years ago that .cfi_* annotations aren't maintainable in
the kernel. For the kernel proper, ensure the CFI_* macros don't do
anything.
On the other hand the vDSO library *does* use them, so user space can
unwind through it.
Make sure these macros only work for vDSO. They aren't actually being
used outside of vDSO anyway, so there's no functional change.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
Notes (jremus):
Link to latest x86 patch:
https://lore.kernel.org/all/20250425024022.477374378@goodmis.org/
arch/s390/include/asm/dwarf.h | 45 ++++++++++++++++++++++-------------
1 file changed, 29 insertions(+), 16 deletions(-)
diff --git a/arch/s390/include/asm/dwarf.h b/arch/s390/include/asm/dwarf.h
index df9f467910f7..6bcf37256feb 100644
--- a/arch/s390/include/asm/dwarf.h
+++ b/arch/s390/include/asm/dwarf.h
@@ -6,6 +6,18 @@
#warning "asm/dwarf.h should be only included in pure assembly files"
#endif
+.macro nocfi args:vararg
+.endm
+
+#ifdef BUILD_VDSO
+
+ /*
+ * For the vDSO, emit both runtime unwind information and debug
+ * symbols for the .dbg file.
+ */
+
+ .cfi_sections .eh_frame, .debug_frame
+
#define CFI_STARTPROC .cfi_startproc
#define CFI_ENDPROC .cfi_endproc
#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset
@@ -16,23 +28,24 @@
#ifdef CONFIG_AS_CFI_VAL_OFFSET
#define CFI_VAL_OFFSET .cfi_val_offset
#else
-#define CFI_VAL_OFFSET #
+#define CFI_VAL_OFFSET nocfi
#endif
-#ifndef BUILD_VDSO
- /*
- * Emit CFI data in .debug_frame sections and not in .eh_frame
- * sections. The .eh_frame CFI is used for runtime unwind
- * information that is not being used. Hence, vmlinux.lds.S
- * can discard the .eh_frame sections.
- */
- .cfi_sections .debug_frame
-#else
- /*
- * For vDSO, emit CFI data in both, .eh_frame and .debug_frame
- * sections.
- */
- .cfi_sections .eh_frame, .debug_frame
-#endif
+#else /* !BUILD_VDSO */
+
+/*
+ * On s390, these macros aren't used outside vDSO. As well they shouldn't be:
+ * they're fragile and very difficult to maintain.
+ */
+
+#define CFI_STARTPROC nocfi
+#define CFI_ENDPROC nocfi
+#define CFI_DEF_CFA_OFFSET nocfi
+#define CFI_ADJUST_CFA_OFFSET nocfi
+#define CFI_RESTORE nocfi
+#define CFI_REL_OFFSET nocfi
+#define CFI_VAL_OFFSET nocfi
+
+#endif /* !BUILD_VDSO */
#endif /* _ASM_S390_DWARF_H */
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 06/15] s390/vdso: Keep function symbols in vDSO
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
` (4 preceding siblings ...)
2025-12-05 17:14 ` [RFC PATCH v2 05/15] s390/vdso: Avoid emitting DWARF CFI for non-vDSO Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 07/15] s390/vdso: Enable SFrame generation " Jens Remus
` (8 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
Keep all function symbols in the vDSO .symtab for stack trace purposes.
This enables a stack tracer, such as perf, to lookup these function
symbols in addition to those already exported in vDSO .dynsym.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
Notes (jremus):
Changes in RFC v2:
- Use objcopy flag "-g" instead of "-S" with the cumbersome filter
"-w -K "__arch_*" -K "__cvdso_*" -K "__s390_vdso_*" to keep the
function symbols, as Josh did in "x86/vdso: Enable sframe
generation in VDSO":
https://lore.kernel.org/all/20250425024023.173709192@goodmis.org/
- Reword commit message.
Note that unlike Josh I did not squash this into the subsequent patch
"s390/vdso: Enable SFrame generation in vDSO", as this change is
unrelated to enabling the use of SFrame. perf report/script do also
benefit from this change when using perf record --call-graph dwarf.
Note that this change does not cause the vDSO build-id to change.
perf record may therefore not dump an updated copy of the vDSO to
~/.debug/[vdso]/<build-id>/vdso, so that perf report/script may
use a stale copy without .symtab. Resolve by deleting ~/.debug/.
arch/s390/kernel/vdso64/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile
index d8f0df742809..8e78dc3ba025 100644
--- a/arch/s390/kernel/vdso64/Makefile
+++ b/arch/s390/kernel/vdso64/Makefile
@@ -53,7 +53,7 @@ $(obj)/vdso64.so.dbg: $(obj)/vdso64.lds $(obj-vdso64) $(obj-cvdso64) FORCE
$(call if_changed,vdso_and_check)
# strip rule for the .so file
-$(obj)/%.so: OBJCOPYFLAGS := -S
+$(obj)/%.so: OBJCOPYFLAGS := -g
$(obj)/%.so: $(obj)/%.so.dbg FORCE
$(call if_changed,objcopy)
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 07/15] s390/vdso: Enable SFrame generation in vDSO
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
` (5 preceding siblings ...)
2025-12-05 17:14 ` [RFC PATCH v2 06/15] s390/vdso: Keep function symbols in vDSO Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 08/15] unwind_user: Enable archs that define CFA = SP_callsite + offset Jens Remus
` (7 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
This replicates Josh's x86 patch "x86/vdso: Enable sframe generation
in VDSO" [1] for s390.
Test whether the assembler supports generating SFrame stack trace
information. Note that it is insufficient to test whether the assembler
supports option --gsframe, as GNU assembler supports that regardless
of whether it is actually capable of generating SFrame stack trace
information for the architecture.
If so enable SFrame stack trace information generation in the vDSO
library so kernel and user space can unwind through it.
[1]: x86/vdso: Enable sframe generation in VDSO,
https://lore.kernel.org/all/20250425024023.173709192@goodmis.org/
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
Notes (jremus):
Changes in RFC v2:
- Introduce config option AS_SFRAME instead of requiring Josh's x86
patch as pre-requisite.
- Reword commit message.
Link to Josh's latest x86 patch:
https://lore.kernel.org/all/20250425024023.173709192@goodmis.org/
arch/Kconfig | 3 +++
arch/s390/include/asm/dwarf.h | 4 ++++
arch/s390/kernel/vdso64/Makefile | 7 ++++++-
arch/s390/kernel/vdso64/vdso64.lds.S | 9 +++++++++
4 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/arch/Kconfig b/arch/Kconfig
index 06c4f909398c..7fa89d70b244 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -482,6 +482,9 @@ config HAVE_HARDLOCKUP_DETECTOR_ARCH
It uses the same command line parameters, and sysctl interface,
as the generic hardlockup detectors.
+config AS_SFRAME
+ def_bool $(as-instr,.cfi_sections .sframe\n.cfi_startproc\n.cfi_endproc)
+
config UNWIND_USER
bool
diff --git a/arch/s390/include/asm/dwarf.h b/arch/s390/include/asm/dwarf.h
index 6bcf37256feb..2f148b15fd7d 100644
--- a/arch/s390/include/asm/dwarf.h
+++ b/arch/s390/include/asm/dwarf.h
@@ -16,7 +16,11 @@
* symbols for the .dbg file.
*/
+#ifdef CONFIG_AS_SFRAME
+ .cfi_sections .eh_frame, .debug_frame, .sframe
+#else
.cfi_sections .eh_frame, .debug_frame
+#endif
#define CFI_STARTPROC .cfi_startproc
#define CFI_ENDPROC .cfi_endproc
diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile
index 8e78dc3ba025..f597f3b863d7 100644
--- a/arch/s390/kernel/vdso64/Makefile
+++ b/arch/s390/kernel/vdso64/Makefile
@@ -20,7 +20,11 @@ targets := $(obj-vdso64) $(obj-cvdso64) vdso64.so vdso64.so.dbg
obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64))
obj-cvdso64 := $(addprefix $(obj)/, $(obj-cvdso64))
-KBUILD_AFLAGS += -DBUILD_VDSO
+ifeq ($(CONFIG_AS_SFRAME),y)
+ SFRAME_CFLAGS := -Wa,--gsframe
+endif
+
+KBUILD_AFLAGS += -DBUILD_VDSO $(SFRAME_CFLAGS)
KBUILD_CFLAGS += -DBUILD_VDSO -DDISABLE_BRANCH_PROFILING
KBUILD_AFLAGS_64 := $(filter-out -m64,$(KBUILD_AFLAGS))
@@ -32,6 +36,7 @@ KBUILD_CFLAGS_64 := $(filter-out -mno-pic-data-is-text-relative,$(KBUILD_CFLAGS_
KBUILD_CFLAGS_64 := $(filter-out -munaligned-symbols,$(KBUILD_CFLAGS_64))
KBUILD_CFLAGS_64 := $(filter-out -fno-asynchronous-unwind-tables,$(KBUILD_CFLAGS_64))
KBUILD_CFLAGS_64 += -m64 -fPIC -fno-common -fno-builtin -fasynchronous-unwind-tables
+KBUILD_CFLAGS_64 += $(SFRAME_CFLAGS)
ldflags-y := -shared -soname=linux-vdso64.so.1 \
--hash-style=both --build-id=sha1 -T
diff --git a/arch/s390/kernel/vdso64/vdso64.lds.S b/arch/s390/kernel/vdso64/vdso64.lds.S
index e4f6551ae898..0205d84369ca 100644
--- a/arch/s390/kernel/vdso64/vdso64.lds.S
+++ b/arch/s390/kernel/vdso64/vdso64.lds.S
@@ -50,6 +50,11 @@ SECTIONS
.eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
.eh_frame : { KEEP (*(.eh_frame)) } :text
+
+#ifdef CONFIG_AS_SFRAME
+ .sframe : { *(.sframe) } :text :sframe
+#endif
+
.gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) }
.rela.dyn ALIGN(8) : { *(.rela.dyn) }
@@ -114,6 +119,7 @@ SECTIONS
* Very old versions of ld do not recognize this name token; use the constant.
*/
#define PT_GNU_EH_FRAME 0x6474e550
+#define PT_GNU_SFRAME 0x6474e554
/*
* We must supply the ELF program headers explicitly to get just one
@@ -125,6 +131,9 @@ PHDRS
dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
note PT_NOTE FLAGS(4); /* PF_R */
eh_frame_hdr PT_GNU_EH_FRAME;
+#ifdef CONFIG_AS_SFRAME
+ sframe PT_GNU_SFRAME;
+#endif
}
/*
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 08/15] unwind_user: Enable archs that define CFA = SP_callsite + offset
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
` (6 preceding siblings ...)
2025-12-05 17:14 ` [RFC PATCH v2 07/15] s390/vdso: Enable SFrame generation " Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 09/15] unwind_user: Enable archs that pass RA in a register Jens Remus
` (6 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
Most architectures define their CFA as the value of the stack pointer
(SP) at the call site in the previous frame, as suggested by the DWARF
standard. Therefore the SP at call site can be unwound using an
implicitly assumed value offset from CFA rule with an offset of zero:
.cfi_val_offset <SP>, 0
As a result the SP at call site computes as follows:
SP = CFA
Enable unwinding of user space for architectures, such as s390, which
define their CFA as the value of the SP at the call site in the previous
frame with an offset. Do so by enabling architectures to override the
default SP value offset from CFA of zero with an architecture-specific
one:
.cfi_val_offset <SP>, offset
So that the SP at call site computes as follows:
SP = CFA + offset
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
Notes (jremus):
Changes in RFC v2:
- Reword commit message. (Josh)
- Use term "sp_off" instead of "sp_val_off". (Josh)
- Move definition, initialization, and setting of sp_off field to
happen right after the cfa_off field.
- Use SFRAME_SP_OFFSET macro instead of sframe_sp_off() function,
which can be overridden by an architecture, such as s390.
- Drop lengthy sframe_sp_[val_]off() comment.
arch/x86/include/asm/unwind_user.h | 2 ++
include/asm-generic/Kbuild | 1 +
include/asm-generic/unwind_user_sframe.h | 12 ++++++++++++
include/linux/unwind_user_types.h | 1 +
kernel/unwind/sframe.c | 2 ++
kernel/unwind/user.c | 11 ++++++-----
6 files changed, 24 insertions(+), 5 deletions(-)
create mode 100644 include/asm-generic/unwind_user_sframe.h
diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h
index 4d699e4954ed..dbdbad0beaf9 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -25,6 +25,7 @@ static inline int unwind_user_word_size(struct pt_regs *regs)
#define ARCH_INIT_USER_FP_FRAME(ws) \
.cfa_off = 2*(ws), \
+ .sp_off = 0, \
.ra_off = -1*(ws), \
.fp_off = -2*(ws), \
.use_fp = true, \
@@ -32,6 +33,7 @@ static inline int unwind_user_word_size(struct pt_regs *regs)
#define ARCH_INIT_USER_FP_ENTRY_FRAME(ws) \
.cfa_off = 1*(ws), \
+ .sp_off = 0, \
.ra_off = -1*(ws), \
.fp_off = 0, \
.use_fp = false, \
diff --git a/include/asm-generic/Kbuild b/include/asm-generic/Kbuild
index 295c94a3ccc1..b1d448ef4a50 100644
--- a/include/asm-generic/Kbuild
+++ b/include/asm-generic/Kbuild
@@ -60,6 +60,7 @@ mandatory-y += topology.h
mandatory-y += trace_clock.h
mandatory-y += uaccess.h
mandatory-y += unwind_user.h
+mandatory-y += unwind_user_sframe.h
mandatory-y += vermagic.h
mandatory-y += vga.h
mandatory-y += video.h
diff --git a/include/asm-generic/unwind_user_sframe.h b/include/asm-generic/unwind_user_sframe.h
new file mode 100644
index 000000000000..8c9ac47bc8bd
--- /dev/null
+++ b/include/asm-generic/unwind_user_sframe.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_GENERIC_UNWIND_USER_SFRAME_H
+#define _ASM_GENERIC_UNWIND_USER_SFRAME_H
+
+#include <linux/types.h>
+
+#ifndef SFRAME_SP_OFFSET
+/* Most archs/ABIs define CFA as SP at call site, so that SP = CFA + 0. */
+#define SFRAME_SP_OFFSET 0
+#endif
+
+#endif /* _ASM_GENERIC_UNWIND_USER_SFRAME_H */
diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_types.h
index 616cc5ee4586..4656aa08a7db 100644
--- a/include/linux/unwind_user_types.h
+++ b/include/linux/unwind_user_types.h
@@ -29,6 +29,7 @@ struct unwind_stacktrace {
struct unwind_user_frame {
s32 cfa_off;
+ s32 sp_off;
s32 ra_off;
s32 fp_off;
bool use_fp;
diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index 6465e7a315bc..7952b041dd23 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c
@@ -12,6 +12,7 @@
#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"
@@ -307,6 +308,7 @@ static __always_inline int __find_fre(struct sframe_section *sec,
fre = prev_fre;
frame->cfa_off = fre->cfa_off;
+ frame->sp_off = SFRAME_SP_OFFSET;
frame->ra_off = fre->ra_off;
frame->fp_off = fre->fp_off;
frame->use_fp = SFRAME_FRE_CFA_BASE_REG_ID(fre->info) == SFRAME_BASE_REG_FP;
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index fdb1001e3750..6c75a7411871 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -30,7 +30,7 @@ get_user_word(unsigned long *word, unsigned long base, int off, unsigned int ws)
static int unwind_user_next_common(struct unwind_user_state *state,
const struct unwind_user_frame *frame)
{
- unsigned long cfa, fp, ra;
+ unsigned long cfa, sp, fp, ra;
/* Stop unwinding when reaching an outermost frame. */
if (frame->outermost) {
@@ -48,12 +48,13 @@ static int unwind_user_next_common(struct unwind_user_state *state,
}
cfa += frame->cfa_off;
+ /* Get the Stack Pointer (SP) */
+ sp = cfa + frame->sp_off;
/* Make sure that stack is not going in wrong direction */
- if (cfa <= state->sp)
+ if (sp <= state->sp)
return -EINVAL;
-
/* Make sure that the address is word aligned */
- if (cfa & (state->ws - 1))
+ if (sp & (state->ws - 1))
return -EINVAL;
/* Get the Return Address (RA) */
@@ -65,7 +66,7 @@ static int unwind_user_next_common(struct unwind_user_state *state,
return -EINVAL;
state->ip = ra;
- state->sp = cfa;
+ state->sp = sp;
if (frame->fp_off)
state->fp = fp;
state->topmost = false;
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 09/15] unwind_user: Enable archs that pass RA in a register
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
` (7 preceding siblings ...)
2025-12-05 17:14 ` [RFC PATCH v2 08/15] unwind_user: Enable archs that define CFA = SP_callsite + offset Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 10/15] unwind_user: Enable archs that save RA/FP in other registers Jens Remus
` (5 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
Not all architectures have the return address (RA) in user space saved
on the stack on function entry, such as x86-64 does due to its CALL
instruction pushing the RA onto the stack. Architectures/ABIs, such as
s390, also do not necessarily enforce to save the RA in user space on
the stack in the function prologue or even at all, for instance in leaf
functions.
Treat a RA offset from CFA of zero as indication that the RA is not
saved (on the stack). For the topmost frame treat it as indication that
the RA is in the link/RA register, such as on arm64 and s390, and obtain
it from there. For non-topmost frames treat it as error, as the RA must
be saved.
Additionally allow the SP to be unchanged in the topmost frame, for
architectures where SP at function entry == SP at call site, such as
arm64 and s390.
Note that treating a RA offset from CFA of zero as indication that
the RA is not saved on the stack additionally allows for architectures,
such as s390, where the frame pointer (FP) may be saved without the RA
being saved as well. Provided that such architectures represent this
in SFrame by encoding the "missing" RA offset using a padding RA offset
with a value of zero.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
Notes (jremus):
Changes in v2:
- Reword commit subject and message.
- Rename config option USER_RA_REG to UNWIND_USER_RA_REG and reword
help text to mention both link and return address register. (Josh)
- Move dummy user_return_address() from linux/ptrace.h to
linux/unwind_user.h, rename to unwind_user_get_ra_reg(),
return -EINVAL, and guard by !CONFIG_HAVE_UNWIND_USER_RA_REG. (Josh)
- Do not check for !IS_ENABLED(CONFIG_HAVE_USER_RA_REG), as the dummy
implementation of user_return_address() returns -EINVAL.
- Drop config option USER_RA_REG / UNWIND_USER_RA_REG, as it is of
no value any longer.
- Drop topmost checks from unwind user sframe, as they are already
done by unwind user. (Josh)
include/linux/unwind_user.h | 9 +++++++++
kernel/unwind/sframe.c | 6 ++----
kernel/unwind/user.c | 17 +++++++++++++----
3 files changed, 24 insertions(+), 8 deletions(-)
diff --git a/include/linux/unwind_user.h b/include/linux/unwind_user.h
index 64618618febd..bc2edae39955 100644
--- a/include/linux/unwind_user.h
+++ b/include/linux/unwind_user.h
@@ -23,6 +23,15 @@ static inline bool unwind_user_at_function_start(struct pt_regs *regs)
#define unwind_user_at_function_start unwind_user_at_function_start
#endif
+#ifndef unwind_user_get_ra_reg
+static inline int unwind_user_get_ra_reg(unsigned long *val)
+{
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+}
+#define unwind_user_get_ra_reg unwind_user_get_ra_reg
+#endif
+
int unwind_user(struct unwind_stacktrace *trace, unsigned int max_entries);
#endif /* _LINUX_UNWIND_USER_H */
diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index 7952b041dd23..38b3577f5253 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c
@@ -228,10 +228,8 @@ static __always_inline int __read_fre(struct sframe_section *sec,
offset_count--;
ra_off = sec->ra_off;
- if (!ra_off) {
- if (!offset_count--)
- return -EFAULT;
-
+ if (!ra_off && offset_count) {
+ offset_count--;
UNSAFE_GET_USER_INC(ra_off, cur, offset_size, Efault);
}
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index 6c75a7411871..58e1549cd9f4 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -50,16 +50,25 @@ static int unwind_user_next_common(struct unwind_user_state *state,
/* Get the Stack Pointer (SP) */
sp = cfa + frame->sp_off;
- /* Make sure that stack is not going in wrong direction */
- if (sp <= state->sp)
+ /*
+ * Make sure that stack is not going in wrong direction. Allow SP
+ * to be unchanged for the topmost frame, by subtracting topmost,
+ * which is either 0 or 1.
+ */
+ if (sp <= state->sp - state->topmost)
return -EINVAL;
/* Make sure that the address is word aligned */
if (sp & (state->ws - 1))
return -EINVAL;
/* Get the Return Address (RA) */
- if (get_user_word(&ra, cfa, frame->ra_off, state->ws))
- return -EINVAL;
+ if (frame->ra_off) {
+ if (get_user_word(&ra, cfa, frame->ra_off, state->ws))
+ return -EINVAL;
+ } else {
+ if (!state->topmost || unwind_user_get_ra_reg(&ra))
+ return -EINVAL;
+ }
/* Get the Frame Pointer (FP) */
if (frame->fp_off && get_user_word(&fp, cfa, frame->fp_off, state->ws))
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 10/15] unwind_user: Enable archs that save RA/FP in other registers
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
` (8 preceding siblings ...)
2025-12-05 17:14 ` [RFC PATCH v2 09/15] unwind_user: Enable archs that pass RA in a register Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 11/15] unwind_user/sframe: Enable archs with encoded SFrame CFA offsets Jens Remus
` (4 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
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>
---
Notes (jremus):
Changes in RFC v2:
- Reword HAVE_UNWIND_USER_LOC_REG help text.
- Rename struct unwind_user_reginfo field frame_off to offset. (Josh)
- Move dummy unwind_user_get_reg() from asm-generic/unwind_user.h
to linux/unwind_user.h, drop its function comment, warn once,
return -EINVAL, and guard by !HAVE_UNWIND_USER_LOC_REG. (Josh)
- Rename generic_sframe_set_frame_reginfo() to sframe_init_reginfo()
and drop its function comment. (Josh)
- Do not check FP/RA offset for zero for UNWIND_USER_LOC_STACK. (Josh)
- Do not check for !IS_ENABLED(CONFIG_HAVE_UNWIND_USER_LOC_REG), as
the dummy implementation of unwind_user_get_reg() returns -EINVAL.
- Drop config option HAVE_UNWIND_USER_LOC_REG, as it is no longer of
any value.
- Keep checking for topmost for UNWIND_USER_LOC_REG. (Jens)
- Explicitly preserve FP if UNWIND_USER_LOC_NONE and drop later test
for frame->fp.loc != UNWIND_USER_LOC_NONE. (Josh)
Would it make sense to rename UNWIND_USER_LOC_NONE to one of the
following to clarify its meaning for the unwinder?
- UNWIND_USER_LOC_UNCHANGED
- UNWIND_USER_LOC_RETAIN
- UNWIND_USER_LOC_PRESERVED
- UNWIND_USER_LOC_IDENTITY
arch/x86/include/asm/unwind_user.h | 21 +++++++++++---
include/asm-generic/unwind_user_sframe.h | 15 ++++++++++
include/linux/unwind_user.h | 9 ++++++
include/linux/unwind_user_types.h | 18 ++++++++++--
kernel/unwind/sframe.c | 4 +--
kernel/unwind/user.c | 37 +++++++++++++++++++-----
6 files changed, 89 insertions(+), 15 deletions(-)
diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h
index dbdbad0beaf9..61a9ae9b07ea 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -26,16 +26,27 @@ static inline int unwind_user_word_size(struct pt_regs *regs)
#define ARCH_INIT_USER_FP_FRAME(ws) \
.cfa_off = 2*(ws), \
.sp_off = 0, \
- .ra_off = -1*(ws), \
- .fp_off = -2*(ws), \
+ .ra = { \
+ .loc = UNWIND_USER_LOC_STACK,\
+ .offset = -1*(ws), \
+ }, \
+ .fp = { \
+ .loc = UNWIND_USER_LOC_STACK,\
+ .offset = -2*(ws), \
+ }, \
.use_fp = true, \
.outermost = false,
#define ARCH_INIT_USER_FP_ENTRY_FRAME(ws) \
.cfa_off = 1*(ws), \
.sp_off = 0, \
- .ra_off = -1*(ws), \
- .fp_off = 0, \
+ .ra = { \
+ .loc = UNWIND_USER_LOC_STACK,\
+ .offset = -1*(ws), \
+ }, \
+ .fp = { \
+ .loc = UNWIND_USER_LOC_NONE, \
+ }, \
.use_fp = false, \
.outermost = false,
@@ -47,4 +58,6 @@ static inline bool unwind_user_at_function_start(struct pt_regs *regs)
#endif /* CONFIG_HAVE_UNWIND_USER_FP */
+#include <asm-generic/unwind_user.h>
+
#endif /* _ASM_X86_UNWIND_USER_H */
diff --git a/include/asm-generic/unwind_user_sframe.h b/include/asm-generic/unwind_user_sframe.h
index 8c9ac47bc8bd..163961ca5252 100644
--- a/include/asm-generic/unwind_user_sframe.h
+++ b/include/asm-generic/unwind_user_sframe.h
@@ -2,6 +2,7 @@
#ifndef _ASM_GENERIC_UNWIND_USER_SFRAME_H
#define _ASM_GENERIC_UNWIND_USER_SFRAME_H
+#include <linux/unwind_user_types.h>
#include <linux/types.h>
#ifndef SFRAME_SP_OFFSET
@@ -9,4 +10,18 @@
#define SFRAME_SP_OFFSET 0
#endif
+#ifndef sframe_init_reginfo
+static inline void
+sframe_init_reginfo(struct unwind_user_reginfo *reginfo, s32 offset)
+{
+ if (offset) {
+ reginfo->loc = UNWIND_USER_LOC_STACK;
+ reginfo->offset = offset;
+ } else {
+ reginfo->loc = UNWIND_USER_LOC_NONE;
+ }
+}
+#define sframe_init_reginfo sframe_init_reginfo
+#endif
+
#endif /* _ASM_GENERIC_UNWIND_USER_SFRAME_H */
diff --git a/include/linux/unwind_user.h b/include/linux/unwind_user.h
index bc2edae39955..61fd5c05d0f0 100644
--- a/include/linux/unwind_user.h
+++ b/include/linux/unwind_user.h
@@ -32,6 +32,15 @@ static inline int unwind_user_get_ra_reg(unsigned long *val)
#define unwind_user_get_ra_reg unwind_user_get_ra_reg
#endif
+#ifndef unwind_user_get_reg
+static inline int unwind_user_get_reg(unsigned long *val, int regnum)
+{
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+}
+#define unwind_user_get_reg unwind_user_get_reg
+#endif
+
int unwind_user(struct unwind_stacktrace *trace, unsigned int max_entries);
#endif /* _LINUX_UNWIND_USER_H */
diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_types.h
index 4656aa08a7db..6efc12b6e831 100644
--- a/include/linux/unwind_user_types.h
+++ b/include/linux/unwind_user_types.h
@@ -27,11 +27,25 @@ 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 offset;
+ int regnum;
+ };
+};
+
struct unwind_user_frame {
s32 cfa_off;
s32 sp_off;
- s32 ra_off;
- s32 fp_off;
+ struct unwind_user_reginfo ra;
+ struct unwind_user_reginfo fp;
bool use_fp;
bool outermost;
};
diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index 38b3577f5253..45cd7380ac38 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c
@@ -307,8 +307,8 @@ static __always_inline int __find_fre(struct sframe_section *sec,
frame->cfa_off = fre->cfa_off;
frame->sp_off = SFRAME_SP_OFFSET;
- frame->ra_off = fre->ra_off;
- frame->fp_off = fre->fp_off;
+ sframe_init_reginfo(&frame->ra, fre->ra_off);
+ sframe_init_reginfo(&frame->fp, fre->fp_off);
frame->use_fp = SFRAME_FRE_CFA_BASE_REG_ID(fre->info) == SFRAME_BASE_REG_FP;
frame->outermost = fre->ra_undefined;
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index 58e1549cd9f4..122045cb411f 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -62,22 +62,45 @@ static int unwind_user_next_common(struct unwind_user_state *state,
return -EINVAL;
/* Get the Return Address (RA) */
- if (frame->ra_off) {
- if (get_user_word(&ra, cfa, frame->ra_off, state->ws))
- return -EINVAL;
- } else {
+ switch (frame->ra.loc) {
+ case UNWIND_USER_LOC_NONE:
if (!state->topmost || unwind_user_get_ra_reg(&ra))
return -EINVAL;
+ break;
+ case UNWIND_USER_LOC_STACK:
+ if (get_user_word(&ra, cfa, frame->ra.offset, state->ws))
+ return -EINVAL;
+ break;
+ case UNWIND_USER_LOC_REG:
+ if (!state->topmost || unwind_user_get_reg(&ra, frame->ra.regnum))
+ return -EINVAL;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return -EINVAL;
}
/* Get the Frame Pointer (FP) */
- if (frame->fp_off && get_user_word(&fp, cfa, frame->fp_off, state->ws))
+ switch (frame->fp.loc) {
+ case UNWIND_USER_LOC_NONE:
+ fp = state->fp;
+ break;
+ case UNWIND_USER_LOC_STACK:
+ if (get_user_word(&fp, cfa, frame->fp.offset, state->ws))
+ return -EINVAL;
+ break;
+ case UNWIND_USER_LOC_REG:
+ if (!state->topmost || unwind_user_get_reg(&fp, frame->fp.regnum))
+ return -EINVAL;
+ break;
+ default:
+ WARN_ON_ONCE(1);
return -EINVAL;
+ }
state->ip = ra;
state->sp = sp;
- if (frame->fp_off)
- state->fp = fp;
+ state->fp = fp;
state->topmost = false;
return 0;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 11/15] unwind_user/sframe: Enable archs with encoded SFrame CFA offsets
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
` (9 preceding siblings ...)
2025-12-05 17:14 ` [RFC PATCH v2 10/15] unwind_user: Enable archs that save RA/FP in other registers Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 12/15] s390/ptrace: Provide frame_pointer() Jens Remus
` (3 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
Enable architectures, such as s390, which store SFrame CFA offset values
encoded, to e.g. make (better) use of unsigned 8-bit SFrame offsets.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
Notes (jremus):
Changes in RFC v2:
- Rename generic_sframe_cfa_offset_decode() to
sframe_cfa_offset_decode(). (Josh)
include/asm-generic/unwind_user_sframe.h | 8 ++++++++
kernel/unwind/sframe.c | 1 +
2 files changed, 9 insertions(+)
diff --git a/include/asm-generic/unwind_user_sframe.h b/include/asm-generic/unwind_user_sframe.h
index 163961ca5252..80ae9bfaa88d 100644
--- a/include/asm-generic/unwind_user_sframe.h
+++ b/include/asm-generic/unwind_user_sframe.h
@@ -10,6 +10,14 @@
#define SFRAME_SP_OFFSET 0
#endif
+#ifndef sframe_cfa_offset_decode
+static inline s32 sframe_cfa_offset_decode(s32 offset)
+{
+ return offset;
+}
+#define sframe_cfa_offset_decode sframe_cfa_offset_decode
+#endif
+
#ifndef sframe_init_reginfo
static inline void
sframe_init_reginfo(struct unwind_user_reginfo *reginfo, s32 offset)
diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index 45cd7380ac38..92f770fc21f6 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c
@@ -226,6 +226,7 @@ static __always_inline int __read_fre(struct sframe_section *sec,
UNSAFE_GET_USER_INC(cfa_off, cur, offset_size, Efault);
offset_count--;
+ cfa_off = sframe_cfa_offset_decode(cfa_off);
ra_off = sec->ra_off;
if (!ra_off && offset_count) {
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 12/15] s390/ptrace: Provide frame_pointer()
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
` (10 preceding siblings ...)
2025-12-05 17:14 ` [RFC PATCH v2 11/15] unwind_user/sframe: Enable archs with encoded SFrame CFA offsets Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 13/15] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME Jens Remus
` (2 subsequent siblings)
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
On s390 64-bit the s390x ELF ABI [1] designates register 11 as the
"preferred" frame pointer (FP) register in user space.
While at it convert instruction_pointer() and user_stack_pointer()
from macros to inline functions, to align their definition with
x86 and arm64.
Use const qualifier on struct pt_regs pointers to prevent compiler
warnings:
arch/s390/kernel/stacktrace.c: In function ‘arch_stack_walk_user_common’:
arch/s390/kernel/stacktrace.c:114:34: warning: passing argument 1 of
‘instruction_pointer’ discards ‘const’ qualifier from pointer target
type [-Wdiscarded-qualifiers]
...
arch/s390/kernel/stacktrace.c:117:48: warning: passing argument 1 of
‘user_stack_pointer’ discards ‘const’ qualifier from pointer target
type [-Wdiscarded-qualifiers]
...
[1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
Notes (jremus):
Changes in RFC v2:
- Separate provide frame_pointer() into this new commit.
arch/s390/include/asm/ptrace.h | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index dfa770b15fad..455c119167fc 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -212,8 +212,6 @@ void update_cr_regs(struct task_struct *task);
#define arch_has_block_step() (1)
#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
-#define instruction_pointer(regs) ((regs)->psw.addr)
-#define user_stack_pointer(regs)((regs)->gprs[15])
#define profile_pc(regs) instruction_pointer(regs)
static inline long regs_return_value(struct pt_regs *regs)
@@ -235,6 +233,22 @@ static __always_inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
return regs->gprs[15];
}
+static __always_inline unsigned long instruction_pointer(const struct pt_regs *regs)
+{
+ return regs->psw.addr;
+}
+
+static __always_inline unsigned long frame_pointer(const struct pt_regs *regs)
+{
+ /* Return ABI-designated "preferred" frame-pointer register value. */
+ return regs->gprs[11];
+}
+
+static __always_inline unsigned long user_stack_pointer(const struct pt_regs *regs)
+{
+ return regs->gprs[15];
+}
+
static __always_inline unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset)
{
if (offset >= NUM_GPRS)
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 13/15] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
` (11 preceding siblings ...)
2025-12-05 17:14 ` [RFC PATCH v2 12/15] s390/ptrace: Provide frame_pointer() Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 14/15] unwind_user/backchain: Introduce back chain user space unwinding Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 15/15] s390/unwind_user/backchain: Enable HAVE_UNWIND_USER_BACKCHAIN Jens Remus
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
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.
Add s390-specific SFrame format definitions. Note that SFRAME_ABI_*
(and thus SFRAME_ABI_S390_ENDIAN_BIG) is currently unused.
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@linux.ibm.com>
---
Notes (jremus):
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 | 100 +++++++++++++++++++++
arch/s390/include/asm/unwind_user_sframe.h | 33 +++++++
kernel/unwind/sframe.c | 2 +-
kernel/unwind/sframe.h | 14 +++
5 files changed, 149 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 df22b10d9141..52d3f3b3e086 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -246,6 +246,7 @@ config S390
select HAVE_SETUP_PER_CPU_AREA
select HAVE_SOFTIRQ_ON_OWN_STACK
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..38dff49d5f86
--- /dev/null
+++ b/arch/s390/include/asm/unwind_user.h
@@ -0,0 +1,100 @@
+/* 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>
+
+#ifdef CONFIG_UNWIND_USER
+
+static inline int unwind_user_word_size(struct pt_regs *regs)
+{
+ return sizeof(long);
+}
+
+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 int __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:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static inline int arch_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];
+ return 0;
+ } else if (16 <= regnum && regnum <= 31) {
+ return __s390_get_dwarf_fpr(val, regnum);
+ }
+
+ 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..e3b80c48f326
--- /dev/null
+++ b/arch/s390/include/asm/unwind_user_sframe.h
@@ -0,0 +1,33 @@
+/* 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
+
+static inline s32 arch_sframe_cfa_offset_decode(s32 offset)
+{
+ return SFRAME_V2_S390X_CFA_OFFSET_DECODE(offset);
+}
+#define sframe_cfa_offset_decode arch_sframe_cfa_offset_decode
+
+static inline void
+arch_sframe_init_reginfo(struct unwind_user_reginfo *reginfo, s32 offset)
+{
+ if (SFRAME_V2_S390X_OFFSET_IS_REGNUM(offset)) {
+ reginfo->loc = UNWIND_USER_LOC_REG;
+ reginfo->regnum = SFRAME_V2_S390X_OFFSET_DECODE_REGNUM(offset);
+ } else if (offset) {
+ reginfo->loc = UNWIND_USER_LOC_STACK;
+ reginfo->offset = offset;
+ } else {
+ reginfo->loc = UNWIND_USER_LOC_NONE;
+ }
+}
+#define sframe_init_reginfo arch_sframe_init_reginfo
+
+#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 92f770fc21f6..bd446d55b552 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_start_addr;
diff --git a/kernel/unwind/sframe.h b/kernel/unwind/sframe.h
index 69ce0d5b9694..c09f25fbaa2f 100644
--- a/kernel/unwind/sframe.h
+++ b/kernel/unwind/sframe.h
@@ -18,6 +18,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) */
#define SFRAME_FDE_TYPE_PCINC 0
#define SFRAME_FDE_TYPE_PCMASK 1
@@ -69,4 +70,17 @@ struct sframe_fde {
#define SFRAME_FRE_OFFSET_SIZE(data) ((data >> 5) & 0x3)
#define SFRAME_FRE_MANGLED_RA_P(data) ((data >> 7) & 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_V2_S390X_CFA_OFFSET_DECODE(offset) \
+ (((offset) * SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR) \
+ - SFRAME_S390X_CFA_OFFSET_ADJUSTMENT)
+
+#define SFRAME_V2_S390X_OFFSET_IS_REGNUM(offset) ((offset) & 1)
+#define SFRAME_V2_S390X_OFFSET_DECODE_REGNUM(offset) ((offset) >> 1)
+
#endif /* _SFRAME_H */
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 14/15] unwind_user/backchain: Introduce back chain user space unwinding
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
` (12 preceding siblings ...)
2025-12-05 17:14 ` [RFC PATCH v2 13/15] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
2025-12-07 15:10 ` Josh Poimboeuf
2025-12-05 17:14 ` [RFC PATCH v2 15/15] s390/unwind_user/backchain: Enable HAVE_UNWIND_USER_BACKCHAIN Jens Remus
14 siblings, 1 reply; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
Add support for unwinding of user space using back chain to the
unwind user interface. Use it as secondary fallback for unwinding
using SFrame, if that fails and the primary fallback using frame
pointer is not available.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
Notes (jremus):
Changes in RFC v2:
- Adjusted to latest unwind user enhancements. Does hopefully no longer
appear grafted on.
arch/Kconfig | 6 ++++++
include/linux/unwind_user_backchain.h | 20 ++++++++++++++++++++
include/linux/unwind_user_types.h | 2 ++
kernel/unwind/user.c | 12 ++++++++++++
4 files changed, 40 insertions(+)
create mode 100644 include/linux/unwind_user_backchain.h
diff --git a/arch/Kconfig b/arch/Kconfig
index 7fa89d70b244..37fb78a5e876 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -488,6 +488,12 @@ config AS_SFRAME
config UNWIND_USER
bool
+config HAVE_UNWIND_USER_BACKCHAIN
+ bool
+ select UNWIND_USER
+ help
+ The arch supports unwinding of user space using back chain.
+
config HAVE_UNWIND_USER_FP
bool
select UNWIND_USER
diff --git a/include/linux/unwind_user_backchain.h b/include/linux/unwind_user_backchain.h
new file mode 100644
index 000000000000..e7a8e584b13f
--- /dev/null
+++ b/include/linux/unwind_user_backchain.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_UNWIND_USER_BACKCHAIN_H
+#define _LINUX_UNWIND_USER_BACKCHAIN_H
+
+struct unwind_user_state;
+
+#ifdef CONFIG_HAVE_UNWIND_USER_BACKCHAIN
+
+extern int arch_unwind_user_next_backchain(struct unwind_user_state *state);
+
+#else /* !CONFIG_HAVE_UNWIND_USER_BACKCHAIN */
+
+static inline int arch_unwind_user_next_backchain(struct unwind_user_state *state)
+{
+ return -EINVAL;
+}
+
+#endif /* !CONFIG_HAVE_UNWIND_USER_BACKCHAIN */
+
+#endif /* _LINUX_UNWIND_USER_BACKCHAIN_H */
diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_types.h
index 6efc12b6e831..b44502e90b7f 100644
--- a/include/linux/unwind_user_types.h
+++ b/include/linux/unwind_user_types.h
@@ -11,6 +11,7 @@
enum unwind_user_type_bits {
UNWIND_USER_TYPE_SFRAME_BIT = 0,
UNWIND_USER_TYPE_FP_BIT = 1,
+ UNWIND_USER_TYPE_BACKCHAIN_BIT = 2,
NR_UNWIND_USER_TYPE_BITS,
};
@@ -20,6 +21,7 @@ enum unwind_user_type {
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),
+ UNWIND_USER_TYPE_BACKCHAIN = BIT(UNWIND_USER_TYPE_BACKCHAIN_BIT),
};
struct unwind_stacktrace {
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index 122045cb411f..5b4649bc91ba 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -6,6 +6,7 @@
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <linux/unwind_user.h>
+#include <linux/unwind_user_backchain.h>
#include <linux/uaccess.h>
#include <linux/sframe.h>
@@ -105,6 +106,11 @@ static int unwind_user_next_common(struct unwind_user_state *state,
return 0;
}
+static int unwind_user_next_backchain(struct unwind_user_state *state)
+{
+ return arch_unwind_user_next_backchain(state);
+}
+
static int unwind_user_next_fp(struct unwind_user_state *state)
{
struct pt_regs *regs = task_pt_regs(current);
@@ -159,6 +165,10 @@ static int unwind_user_next(struct unwind_user_state *state)
if (!unwind_user_next_fp(state))
return 0;
continue;
+ case UNWIND_USER_TYPE_BACKCHAIN:
+ if (!unwind_user_next_backchain(state))
+ return 0;
+ continue; /* Try next method. */
default:
WARN_ONCE(1, "Undefined unwind bit %d", bit);
break;
@@ -187,6 +197,8 @@ static int unwind_user_start(struct unwind_user_state *state)
state->available_types |= UNWIND_USER_TYPE_SFRAME;
if (IS_ENABLED(CONFIG_HAVE_UNWIND_USER_FP))
state->available_types |= UNWIND_USER_TYPE_FP;
+ if (IS_ENABLED(CONFIG_HAVE_UNWIND_USER_BACKCHAIN))
+ state->available_types |= UNWIND_USER_TYPE_BACKCHAIN;
state->ip = instruction_pointer(regs);
state->sp = user_stack_pointer(regs);
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v2 15/15] s390/unwind_user/backchain: Enable HAVE_UNWIND_USER_BACKCHAIN
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
` (13 preceding siblings ...)
2025-12-05 17:14 ` [RFC PATCH v2 14/15] unwind_user/backchain: Introduce back chain user space unwinding Jens Remus
@ 2025-12-05 17:14 ` Jens Remus
14 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-05 17:14 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt
Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
Dylan Hatch
Enable unwinding of user space using back chain on s390. Based on
arch_stack_walk_user_common() in arch/s390/kernel/stacktrace.c.
Note that an invalid RA obtained from the stack frame pointed to by the
back chain is not a valid indication that the IP is still early in the
function prologue and a fallback to the RA and SP register r14 and r15
contents should be made.
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
Notes (jremus):
Changes in RFC v2:
- Adjusted to latest unwind user changes.
- Use struct stack_frame_user and struct stack_frame_vdso_wrapper from
asm/stacktrace.h.
- In topmost frame do not fallback to RA (and SP) register values if
RA is invalid. This is not a valid indication for early prologue.
- In topmost frame use RA and SP register values if they match those
saved in the frame. This indicates early prologue.
arch/s390/Kconfig | 1 +
arch/s390/kernel/Makefile | 2 +
arch/s390/kernel/unwind_user_backchain.c | 112 +++++++++++++++++++++++
3 files changed, 115 insertions(+)
create mode 100644 arch/s390/kernel/unwind_user_backchain.c
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 52d3f3b3e086..5aeb2abd390f 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -246,6 +246,7 @@ config S390
select HAVE_SETUP_PER_CPU_AREA
select HAVE_SOFTIRQ_ON_OWN_STACK
select HAVE_SYSCALL_TRACEPOINTS
+ select HAVE_UNWIND_USER_BACKCHAIN
select HAVE_UNWIND_USER_SFRAME
select HAVE_VIRT_CPU_ACCOUNTING
select HAVE_VIRT_CPU_ACCOUNTING_IDLE
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index eb06ff888314..eb662e95c5fd 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -83,6 +83,8 @@ obj-$(CONFIG_PERF_EVENTS) += perf_pai_crypto.o perf_pai_ext.o
obj-$(CONFIG_TRACEPOINTS) += trace.o
+obj-$(CONFIG_HAVE_UNWIND_USER_BACKCHAIN) += unwind_user_backchain.o
+
# vdso
obj-y += vdso64/
obj-$(CONFIG_COMPAT) += vdso32/
diff --git a/arch/s390/kernel/unwind_user_backchain.c b/arch/s390/kernel/unwind_user_backchain.c
new file mode 100644
index 000000000000..4e10ca43ea36
--- /dev/null
+++ b/arch/s390/kernel/unwind_user_backchain.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "backchain: " fmt
+
+#include <asm/asm-offsets.h>
+#include <asm/stacktrace.h>
+#include <linux/security.h>
+#include <linux/unwind_user.h>
+#include <linux/unwind_user_backchain.h>
+
+/**
+ * ip_invalid - Perform some basic checks whether an instruction pointer (IP)
+ * taken from an unreliable source is invalid
+ * @ip: The instruction pointer to be validated
+ *
+ * returns whether the instruction pointer is invalid
+ */
+static inline bool ip_invalid(unsigned long ip)
+{
+ /* Architecture requires IP to be 2-byte aligned. */
+ if (ip & 1)
+ return true;
+ if (ip < mmap_min_addr)
+ return true;
+ if (ip >= current->mm->context.asce_limit)
+ return true;
+ return false;
+}
+
+/**
+ * ip_within_vdso - Check whether an instruction pointer (IP) is within vDSO
+ * @ip: The instruction pointer
+ *
+ * returns whether the instruction pointer is within vDSO
+ */
+static inline bool ip_within_vdso(unsigned long ip)
+{
+ return in_range(ip, current->mm->context.vdso_base, vdso_text_size());
+}
+
+/**
+ * arch_unwind_user_next_backchain - Unwind one frame using s390 back chain
+ * @state: The unwind user state
+ *
+ * returns zero when successful, otherwise -EINVAL.
+ */
+int arch_unwind_user_next_backchain(struct unwind_user_state *state)
+{
+ struct stack_frame_user __user *sf;
+ unsigned long sp, ra;
+
+ sf = (void __user *)state->sp;
+
+ /*
+ * In topmost frame check whether IP in early prologue, RA and SP
+ * registers saved, and no new stack frame allocated.
+ */
+ if (state->topmost) {
+ unsigned long ra_reg;
+
+ if (__get_user(ra, (unsigned long __user *)&sf->gprs[8]))
+ return -EINVAL;
+ if (__get_user(sp, (unsigned long __user *)&sf->gprs[9]))
+ return -EINVAL;
+ if (unwind_user_get_ra_reg(&ra_reg))
+ return -EINVAL;
+ if (ra == ra_reg && sp == state->sp)
+ goto done;
+ }
+
+ if (__get_user(sp, (unsigned long __user *)&sf->back_chain))
+ return -EINVAL;
+ if (!sp && ip_within_vdso(state->ip)) {
+ /*
+ * Assume non-standard vDSO user wrapper stack frame.
+ * See vDSO user wrapper code for details.
+ */
+ struct stack_frame_vdso_wrapper *sf_vdso = (void __user *)sf;
+
+ if (__get_user(ra, (unsigned long __user *)&sf_vdso->return_address))
+ return -EINVAL;
+ sf = (void __user *)((unsigned long)sf + STACK_FRAME_VDSO_OVERHEAD);
+ if (__get_user(sp, (unsigned long __user *)&sf->back_chain))
+ return -EINVAL;
+ } else if (!sp) {
+ /* Assume outermost frame reached. */
+ state->done = true;
+ return 0;
+ } else {
+ /*
+ * Assume IP past prologue and new stack frame allocated.
+ * Follow back chain, which then equals the SP at entry.
+ * Skips caller if wrong in topmost frame.
+ */
+ sf = (void __user *)sp;
+ if (__get_user(ra, (unsigned long __user *)&sf->gprs[8]))
+ return -EINVAL;
+ /* Skip validation: ABI requires SP to be saved as well. */
+ }
+
+done:
+ /* Validate SP and RA (ABI requires SP to be 8-byte aligned). */
+ if (sp & 7 || ip_invalid(ra))
+ return -EINVAL;
+
+ state->ip = ra;
+ state->sp = sp;
+ state->fp = 0; /* Cannot unwind FP. */
+ state->topmost = false;
+
+ return 0;
+}
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [RFC PATCH v2 03/15] x86/unwind_user: Guard unwind_user_word_size() by UNWIND_USER
2025-12-05 17:14 ` [RFC PATCH v2 03/15] x86/unwind_user: Guard unwind_user_word_size() by UNWIND_USER Jens Remus
@ 2025-12-05 17:23 ` Linus Torvalds
0 siblings, 0 replies; 19+ messages in thread
From: Linus Torvalds @ 2025-12-05 17:23 UTC (permalink / raw)
To: Jens Remus
Cc: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
Jose E. Marchesi, Beau Belgrave, Andrew Morton, Florian Weimer,
Kees Cook, Carlos O'Donell, Sam James, Dylan Hatch
Random nit...
On Fri, 5 Dec 2025 at 09:15, Jens Remus <jremus@linux.ibm.com> wrote:
>
> +static inline int unwind_user_word_size(struct pt_regs *regs)
> +{
> + /* We can't unwind VM86 stacks */
> + if (regs->flags & X86_VM_MASK)
> + return 0;
> +#ifdef CONFIG_X86_64
> + if (!user_64bit_mode(regs))
> + return sizeof(int);
> +#endif
> + return sizeof(long);
> +}
I realize you just moved this around, but since I see it in the patch,
the #ifdef annoys me.
That user_64bit_mode() should work equally well on 32-bit, and this
can be written as
return user_64bit_mode(regs) ? 8 : 4;
which avoids the #ifdef, and makes a lot more sense ("sizeof(long)"
together with "user_64bit_mode()"? It's literally testing 32 vs 64
bitness, not "int vs long").
Linus
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC PATCH v2 14/15] unwind_user/backchain: Introduce back chain user space unwinding
2025-12-05 17:14 ` [RFC PATCH v2 14/15] unwind_user/backchain: Introduce back chain user space unwinding Jens Remus
@ 2025-12-07 15:10 ` Josh Poimboeuf
2025-12-08 15:38 ` Jens Remus
0 siblings, 1 reply; 19+ messages in thread
From: Josh Poimboeuf @ 2025-12-07 15:10 UTC (permalink / raw)
To: Jens Remus
Cc: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Masami Hiramatsu, Mathieu Desnoyers, Peter Zijlstra, Ingo Molnar,
Jiri Olsa, Arnaldo Carvalho de Melo, Namhyung Kim,
Thomas Gleixner, Andrii Nakryiko, Indu Bhagat, Jose E. Marchesi,
Beau Belgrave, Linus Torvalds, Andrew Morton, Florian Weimer,
Kees Cook, Carlos O'Donell, Sam James, Dylan Hatch
On Fri, Dec 05, 2025 at 06:14:45PM +0100, Jens Remus wrote:
> @@ -159,6 +165,10 @@ static int unwind_user_next(struct unwind_user_state *state)
> if (!unwind_user_next_fp(state))
> return 0;
> continue;
> + case UNWIND_USER_TYPE_BACKCHAIN:
> + if (!unwind_user_next_backchain(state))
> + return 0;
> + continue; /* Try next method. */
> default:
> WARN_ONCE(1, "Undefined unwind bit %d", bit);
> break;
> @@ -187,6 +197,8 @@ static int unwind_user_start(struct unwind_user_state *state)
> state->available_types |= UNWIND_USER_TYPE_SFRAME;
> if (IS_ENABLED(CONFIG_HAVE_UNWIND_USER_FP))
> state->available_types |= UNWIND_USER_TYPE_FP;
> + if (IS_ENABLED(CONFIG_HAVE_UNWIND_USER_BACKCHAIN))
> + state->available_types |= UNWIND_USER_TYPE_BACKCHAIN;
Any reason not to just use the existing CONFIG_HAVE_UNWIND_USER_FP hook
here rather than create the new BACKCHAIN one?
--
Josh
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC PATCH v2 14/15] unwind_user/backchain: Introduce back chain user space unwinding
2025-12-07 15:10 ` Josh Poimboeuf
@ 2025-12-08 15:38 ` Jens Remus
0 siblings, 0 replies; 19+ messages in thread
From: Jens Remus @ 2025-12-08 15:38 UTC (permalink / raw)
To: Josh Poimboeuf
Cc: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
Steven Rostedt, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
Masami Hiramatsu, Mathieu Desnoyers, Peter Zijlstra, Ingo Molnar,
Jiri Olsa, Arnaldo Carvalho de Melo, Namhyung Kim,
Thomas Gleixner, Andrii Nakryiko, Indu Bhagat, Jose E. Marchesi,
Beau Belgrave, Linus Torvalds, Andrew Morton, Florian Weimer,
Kees Cook, Carlos O'Donell, Sam James, Dylan Hatch
Hello Josh,
thank you for your feedback!
On 12/7/2025 4:10 PM, Josh Poimboeuf wrote:
> On Fri, Dec 05, 2025 at 06:14:45PM +0100, Jens Remus wrote:
>> @@ -159,6 +165,10 @@ static int unwind_user_next(struct unwind_user_state *state)
>> if (!unwind_user_next_fp(state))
>> return 0;
>> continue;
>> + case UNWIND_USER_TYPE_BACKCHAIN:
>> + if (!unwind_user_next_backchain(state))
>> + return 0;
>> + continue; /* Try next method. */
>> default:
>> WARN_ONCE(1, "Undefined unwind bit %d", bit);
>> break;
>> @@ -187,6 +197,8 @@ static int unwind_user_start(struct unwind_user_state *state)
>> state->available_types |= UNWIND_USER_TYPE_SFRAME;
>> if (IS_ENABLED(CONFIG_HAVE_UNWIND_USER_FP))
>> state->available_types |= UNWIND_USER_TYPE_FP;
>> + if (IS_ENABLED(CONFIG_HAVE_UNWIND_USER_BACKCHAIN))
>> + state->available_types |= UNWIND_USER_TYPE_BACKCHAIN;
>
> Any reason not to just use the existing CONFIG_HAVE_UNWIND_USER_FP hook
> here rather than create the new BACKCHAIN one?
At first I thought this would not be a good idea, as my unwind user
backchain implementation relies on being standalone without using
unwind_user_next_common(). Mainly because s390 back chain unwinding
does not have fixed CFA, FP, and RA offsets/locations. But then I gave
it a try and it does not look that bad actually.
I'll send a RFC v3 soon.
Regards,
Jens
--
Jens Remus
Linux on Z Development (D3303)
+49-7031-16-1128 Office
jremus@de.ibm.com
IBM
IBM Deutschland Research & Development GmbH; Vorsitzender des Aufsichtsrats: Wolfgang Wendt; Geschäftsführung: David Faller; Sitz der Gesellschaft: Böblingen; Registergericht: Amtsgericht Stuttgart, HRB 243294
IBM Data Privacy Statement: https://www.ibm.com/privacy/
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2025-12-08 15:38 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-05 17:14 [RFC PATCH v2 00/15] s390: SFrame user space unwinding Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 01/15] unwind_user: Enhance comments on get CFA, FP, and RA Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 02/15] unwind_user/fp: Use dummies instead of ifdef Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 03/15] x86/unwind_user: Guard unwind_user_word_size() by UNWIND_USER Jens Remus
2025-12-05 17:23 ` Linus Torvalds
2025-12-05 17:14 ` [RFC PATCH v2 04/15] s390: asm/dwarf.h should only be included in assembly files Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 05/15] s390/vdso: Avoid emitting DWARF CFI for non-vDSO Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 06/15] s390/vdso: Keep function symbols in vDSO Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 07/15] s390/vdso: Enable SFrame generation " Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 08/15] unwind_user: Enable archs that define CFA = SP_callsite + offset Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 09/15] unwind_user: Enable archs that pass RA in a register Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 10/15] unwind_user: Enable archs that save RA/FP in other registers Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 11/15] unwind_user/sframe: Enable archs with encoded SFrame CFA offsets Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 12/15] s390/ptrace: Provide frame_pointer() Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 13/15] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 14/15] unwind_user/backchain: Introduce back chain user space unwinding Jens Remus
2025-12-07 15:10 ` Josh Poimboeuf
2025-12-08 15:38 ` Jens Remus
2025-12-05 17:14 ` [RFC PATCH v2 15/15] s390/unwind_user/backchain: Enable HAVE_UNWIND_USER_BACKCHAIN Jens Remus
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).