bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v3 00/17] s390: SFrame user space unwinding
@ 2025-12-08 17:15 Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 01/17] unwind_user: Enhance comments on get CFA, FP, and RA Jens Remus
                   ` (16 more replies)
  0 siblings, 17 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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 9-12),
including unwinding of user space using back chain (see patches 15-17).
The latter could be broken apart as a separate patch series.


Changes in RFC v3:
- Rebase on and include my unwind user cleanup series v4, which includes
  a simplification of unwind_user_word_size() on x86. (Linus)
- Implement unwinding of user space using s390 back chain using unwind
  user fp instead of introducing a new unwind user backchain. (Josh)

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-4 originate from my "[PATCH v4 0/3] unwind_user: Cleanups"
series and can be ignored here (please review in the respective series):
https://lore.kernel.org/all/20251208160352.1363040-1-jremus@linux.ibm.com/

Patch 5 aligns asm/dwarf.h to x86 asm/dwarf2.h.

Patch 6 replicates Josh's x86 patch "x86/asm: Avoid emitting DWARF
CFI for non-VDSO" for s390.

Patch 7 changes the build of the vDSO on s390 to keep the function
symbols for stack tracing purposes.

Patch 8 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 9-12 enable Josh's generic unwind user (sframe) frameworks to
support the following s390 particularities:

- Patch 9 adds support for architectures that define their CFA as SP at
  callsite + offset.

- Patch 10 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 11 adds support for architectures that save RA/FP in other
  registers instead of on the stack, e.g. in leaf functions.

- Patch 12 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 13 introduces frame_pointer() in ptrace on s390, which is a
prerequisite for enabling unwind user.

Patch 14 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.

Patches 15-16 enable unwind user (fp) to support the following s390
back chain particularities:

- Patch 15 introduces FP/RA location unknown, which enables s390
  back chain unwinding, which cannot unwind FP.

- Patch 16 enables sophisticated architecture-specific initialization
  of the FP frame, which enables s390 back chain unwinding to provide
  dynamic information.

Patch 17 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 (17):
  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
  x86/unwind_user: Simplify unwind_user_word_size()
  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: Introduce FP/RA location unknown
  unwind_user/fp: Use arch-specific helper to initialize FP frame
  s390/unwind_user/fp: Enable back chain unwinding of user space

 arch/Kconfig                               |   3 +
 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        | 183 +++++++++++++++++++++
 arch/s390/include/asm/unwind_user_sframe.h |  33 ++++
 arch/s390/kernel/vdso64/Makefile           |   9 +-
 arch/s390/kernel/vdso64/vdso64.lds.S       |   9 +
 arch/x86/include/asm/unwind_user.h         |  66 ++++++--
 include/asm-generic/Kbuild                 |   1 +
 include/asm-generic/unwind_user_sframe.h   |  35 ++++
 include/linux/unwind_user.h                |  30 +++-
 include/linux/unwind_user_types.h          |  20 ++-
 kernel/unwind/sframe.c                     |  13 +-
 kernel/unwind/sframe.h                     |  14 ++
 kernel/unwind/user.c                       |  83 ++++++----
 16 files changed, 493 insertions(+), 79 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 include/asm-generic/unwind_user_sframe.h

-- 
2.51.0


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 01/17] unwind_user: Enhance comments on get CFA, FP, and RA
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 02/17] unwind_user/fp: Use dummies instead of ifdef Jens Remus
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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] 24+ messages in thread

* [RFC PATCH v3 02/17] unwind_user/fp: Use dummies instead of ifdef
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 01/17] unwind_user: Enhance comments on get CFA, FP, and RA Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 03/17] x86/unwind_user: Guard unwind_user_word_size() by UNWIND_USER Jens Remus
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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>
---
 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] 24+ messages in thread

* [RFC PATCH v3 03/17] x86/unwind_user: Guard unwind_user_word_size() by UNWIND_USER
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 01/17] unwind_user: Enhance comments on get CFA, FP, and RA Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 02/17] unwind_user/fp: Use dummies instead of ifdef Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 04/17] x86/unwind_user: Simplify unwind_user_word_size() Jens Remus
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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>
---
 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] 24+ messages in thread

* [RFC PATCH v3 04/17] x86/unwind_user: Simplify unwind_user_word_size()
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (2 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 03/17] x86/unwind_user: Guard unwind_user_word_size() by UNWIND_USER Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 05/17] s390: asm/dwarf.h should only be included in assembly files Jens Remus
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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

Get rid of superfluous ifdef and return explicit word size depending on
32-bit or 64-bit mode.

Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
 arch/x86/include/asm/unwind_user.h | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h
index 4d699e4954ed..2dfb5ef11e36 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -12,11 +12,7 @@ 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);
+	return user_64bit_mode(regs) ? 8 : 4;
 }
 
 #endif /* CONFIG_UNWIND_USER */
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 05/17] s390: asm/dwarf.h should only be included in assembly files
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (3 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 04/17] x86/unwind_user: Simplify unwind_user_word_size() Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-10 15:16   ` Heiko Carstens
  2025-12-08 17:15 ` [RFC PATCH v3 06/17] s390/vdso: Avoid emitting DWARF CFI for non-vDSO Jens Remus
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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] 24+ messages in thread

* [RFC PATCH v3 06/17] s390/vdso: Avoid emitting DWARF CFI for non-vDSO
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (4 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 05/17] s390: asm/dwarf.h should only be included in assembly files Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 07/17] s390/vdso: Keep function symbols in vDSO Jens Remus
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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] 24+ messages in thread

* [RFC PATCH v3 07/17] s390/vdso: Keep function symbols in vDSO
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (5 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 06/17] s390/vdso: Avoid emitting DWARF CFI for non-vDSO Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 08/17] s390/vdso: Enable SFrame generation " Jens Remus
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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] 24+ messages in thread

* [RFC PATCH v3 08/17] s390/vdso: Enable SFrame generation in vDSO
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (6 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 07/17] s390/vdso: Keep function symbols in vDSO Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 09/17] unwind_user: Enable archs that define CFA = SP_callsite + offset Jens Remus
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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] 24+ messages in thread

* [RFC PATCH v3 09/17] unwind_user: Enable archs that define CFA = SP_callsite + offset
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (7 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 08/17] s390/vdso: Enable SFrame generation " Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 10/17] unwind_user: Enable archs that pass RA in a register Jens Remus
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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 2dfb5ef11e36..d70ffd7bbdb7 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -21,6 +21,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,				\
@@ -28,6 +29,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] 24+ messages in thread

* [RFC PATCH v3 10/17] unwind_user: Enable archs that pass RA in a register
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (8 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 09/17] unwind_user: Enable archs that define CFA = SP_callsite + offset Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 11/17] unwind_user: Enable archs that save RA/FP in other registers Jens Remus
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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] 24+ messages in thread

* [RFC PATCH v3 11/17] unwind_user: Enable archs that save RA/FP in other registers
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (9 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 10/17] unwind_user: Enable archs that pass RA in a register Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 12/17] unwind_user/sframe: Enable archs with encoded SFrame CFA offsets Jens Remus
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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 v3:
    - Rename UNWIND_USER_LOC_NONE to UNWIND_USER_LOC_RETAIN to better
      disambiguate from new UNWIND_USER_LOC_UNKNOWN to be introduced for
      for back chain unwinding on s390.
      Other naming options: IDENTITY, KEEP, PRESERVE, SAME, UNCHANGED.
    
    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 d70ffd7bbdb7..2480d86a405e 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -22,16 +22,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_RETAIN,\
+			},				\
 	.use_fp		= false,			\
 	.outermost	= false,
 
@@ -43,4 +54,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..fd71d6b1916b 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_RETAIN;
+	}
+}
+#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..4f78999a0750 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_RETAIN,
+	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..45f82ed28fcb 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_RETAIN:
 		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_RETAIN:
+		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] 24+ messages in thread

* [RFC PATCH v3 12/17] unwind_user/sframe: Enable archs with encoded SFrame CFA offsets
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (10 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 11/17] unwind_user: Enable archs that save RA/FP in other registers Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 13/17] s390/ptrace: Provide frame_pointer() Jens Remus
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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 fd71d6b1916b..ec68a77551f0 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] 24+ messages in thread

* [RFC PATCH v3 13/17] s390/ptrace: Provide frame_pointer()
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (11 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 12/17] unwind_user/sframe: Enable archs with encoded SFrame CFA offsets Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-10 15:19   ` Heiko Carstens
  2025-12-08 17:15 ` [RFC PATCH v3 14/17] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME Jens Remus
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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] 24+ messages in thread

* [RFC PATCH v3 14/17] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (12 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 13/17] s390/ptrace: Provide frame_pointer() Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-10 15:10   ` Heiko Carstens
  2025-12-08 17:15 ` [RFC PATCH v3 15/17] unwind_user: Introduce FP/RA location unknown Jens Remus
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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 v3:
    - Adjust to rename of UNWIND_USER_LOC_NONE to UNWIND_USER_LOC_RETAIN.
    - Adjust s390-specific unwind_user_word_size() to changes in the
      x86-specific (see patch 4).
    
    Changes in RFC v2:
    - Provide unwind_user_word_size() to satisfy new unwind user need.  Note
      that support for COMPAT has not been implemented as s390 support for
      COMPAT is expected to be removed with v6.19:
      https://lore.kernel.org/all/20251201102713.22472A5b-hca@linux.ibm.com/
    - Adjust to changes in preceding patches in this series that enable
      support in unwind user (sframe) for s390 particularities.
    
    Alternatively the s390-specific definitions could also be added to the
    s390-specific unwind user sframe header.  The current implementation
    follows Binutils approach to have all SFrame format definitions in one
    central header file.

 arch/s390/Kconfig                          |   1 +
 arch/s390/include/asm/unwind_user.h        | 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..3a95be1eb886
--- /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 8;
+}
+
+static inline int arch_unwind_user_get_ra_reg(unsigned long *val)
+{
+	struct pt_regs *regs = task_pt_regs(current);
+	*val = regs->gprs[14];
+	return 0;
+}
+#define unwind_user_get_ra_reg arch_unwind_user_get_ra_reg
+
+static inline 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..af650596cb5d
--- /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_RETAIN;
+	}
+}
+#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] 24+ messages in thread

* [RFC PATCH v3 15/17] unwind_user: Introduce FP/RA location unknown
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (13 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 14/17] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 16/17] unwind_user/fp: Use arch-specific helper to initialize FP frame Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 17/17] s390/unwind_user/fp: Enable back chain unwinding of user space Jens Remus
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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 an unwind user method to specify that the FP/RA location
is unknown.  For the frame pointer (FP) set the FP value to zero, so
that subsequent unwind next frame that rely on FP fail.  For the return
address (RA) treat as error.

This enables to implement support for unwinding of user space using back
chain on s390 with a subsequent commit, which can only unwind SP and RA,
but not FP.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---

Notes (jremus):
    Changes in RFC v3:
    - New patch.  Prerequirement to implement unwind user fp using back
      chain on s390.

 include/linux/unwind_user_types.h | 1 +
 kernel/unwind/user.c              | 4 ++++
 2 files changed, 5 insertions(+)

diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_types.h
index 4f78999a0750..f44035b98f7c 100644
--- a/include/linux/unwind_user_types.h
+++ b/include/linux/unwind_user_types.h
@@ -28,6 +28,7 @@ struct unwind_stacktrace {
 };
 
 enum unwind_user_loc {
+	UNWIND_USER_LOC_UNKNOWN,
 	UNWIND_USER_LOC_RETAIN,
 	UNWIND_USER_LOC_STACK,
 	UNWIND_USER_LOC_REG,
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index 45f82ed28fcb..7d06bdbc7f0d 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -93,6 +93,10 @@ static int unwind_user_next_common(struct unwind_user_state *state,
 		if (!state->topmost || unwind_user_get_reg(&fp, frame->fp.regnum))
 			return -EINVAL;
 		break;
+	case UNWIND_USER_LOC_UNKNOWN:
+		/* FP cannot be unwound. Not an error. Set to zero. */
+		fp = 0;
+		break;
 	default:
 		WARN_ON_ONCE(1);
 		return -EINVAL;
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 16/17] unwind_user/fp: Use arch-specific helper to initialize FP frame
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (14 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 15/17] unwind_user: Introduce FP/RA location unknown Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-08 17:15 ` [RFC PATCH v3 17/17] s390/unwind_user/fp: Enable back chain unwinding of user space Jens Remus
  16 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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 enables more sophisticated initialization of the FP frame, for
instance to implement support for unwinding of user space using back
chain on s390 with a subsequent commit.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---

Notes (jremus):
    Changes in RFC v3:
    - New patch.  Prerequirement to implement unwind user fp using back
      chain on s390.

 arch/x86/include/asm/unwind_user.h | 20 +++++++++++++++++---
 include/linux/unwind_user.h        | 20 +++++++-------------
 kernel/unwind/user.c               | 16 ++++------------
 3 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h
index 2480d86a405e..ca581edecb9d 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -46,11 +46,25 @@ static inline int unwind_user_word_size(struct pt_regs *regs)
 	.use_fp		= false,			\
 	.outermost	= false,
 
-static inline bool unwind_user_at_function_start(struct pt_regs *regs)
+static inline int unwind_user_fp_get_frame(struct unwind_user_state *state,
+					   struct unwind_user_frame *frame)
 {
-	return is_uprobe_at_func_entry(regs);
+	struct pt_regs *regs = task_pt_regs(current);
+
+	if (state->topmost && is_uprobe_at_func_entry(regs)) {
+		const struct unwind_user_frame fp_entry_frame = {
+			ARCH_INIT_USER_FP_ENTRY_FRAME(state->ws)
+		};
+		*frame = fp_entry_frame;
+	} else {
+		const struct unwind_user_frame fp_frame = {
+			ARCH_INIT_USER_FP_FRAME(state->ws)
+		};
+		*frame = fp_frame;
+	}
+	return 0;
 }
-#define unwind_user_at_function_start unwind_user_at_function_start
+#define unwind_user_fp_get_frame unwind_user_fp_get_frame
 
 #endif /* CONFIG_HAVE_UNWIND_USER_FP */
 
diff --git a/include/linux/unwind_user.h b/include/linux/unwind_user.h
index 61fd5c05d0f0..4adab1a612a6 100644
--- a/include/linux/unwind_user.h
+++ b/include/linux/unwind_user.h
@@ -7,21 +7,15 @@
 
 #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)
+static inline int unwind_user_fp_get_frame(struct unwind_user_state *state,
+					   struct unwind_user_frame *frame)
 {
-	return false;
+	WARN_ON_ONCE(1);
+	return -EINVAL;
 }
-#define unwind_user_at_function_start unwind_user_at_function_start
-#endif
+#define unwind_user_fp_get_frame unwind_user_fp_get_frame
+
+#endif /* CONFIG_HAVE_UNWIND_USER_FP */
 
 #ifndef unwind_user_get_ra_reg
 static inline int unwind_user_get_ra_reg(unsigned long *val)
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index 7d06bdbc7f0d..6877242ceae3 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -111,19 +111,11 @@ static int unwind_user_next_common(struct unwind_user_state *state,
 
 static int unwind_user_next_fp(struct unwind_user_state *state)
 {
-	struct pt_regs *regs = task_pt_regs(current);
-
-	if (state->topmost && unwind_user_at_function_start(regs)) {
-		const struct unwind_user_frame fp_entry_frame = {
-			ARCH_INIT_USER_FP_ENTRY_FRAME(state->ws)
-		};
-		return unwind_user_next_common(state, &fp_entry_frame);
-	}
+	struct unwind_user_frame frame;
 
-	const struct unwind_user_frame fp_frame = {
-		ARCH_INIT_USER_FP_FRAME(state->ws)
-	};
-	return unwind_user_next_common(state, &fp_frame);
+	if (unwind_user_fp_get_frame(state, &frame))
+		return -ENOENT;
+	return unwind_user_next_common(state, &frame);
 }
 
 static int unwind_user_next_sframe(struct unwind_user_state *state)
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 17/17] s390/unwind_user/fp: Enable back chain unwinding of user space
  2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
                   ` (15 preceding siblings ...)
  2025-12-08 17:15 ` [RFC PATCH v3 16/17] unwind_user/fp: Use arch-specific helper to initialize FP frame Jens Remus
@ 2025-12-08 17:15 ` Jens Remus
  2025-12-12  9:21   ` Jens Remus
  16 siblings, 1 reply; 24+ messages in thread
From: Jens Remus @ 2025-12-08 17:15 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

Unwinding of user space using frame pointer (FP) is virtually impossible
on s390 for the following reasons:  The s390 64-bit (s390x) ELF ABI [1]
does only designate a "preferred" FP register and does not mandate fixed
FP and return address (RA) stack save slots.  Therefore neither the FP
register nor the FP/RA stack save slot offsets from CFA are known.
Compilers, such as GCC and Clang, do not necessarily setup a FP register
early in the function prologue, even not with compiler option
-fno-omit-frame-pointer.  Therefore the CFA offset from FP register is
not known.

This could be resolved by having compiler option -no-omit-frame-pointer
enforce all of the following:  Use the preferred FP register 11 as frame
pointer, use fixed FP/RA stack slot offsets from CFA (e.g. -72 for FP
and -48 for RA), and setup the FP register immediately after saving the
call saved registers.

Fortunately s390 provides an alternative to frame pointer:  back chain,
which can be enabled using s390-specific compiler option -mbackchain.
The back chain is very similar to a frame pointer on the stack.

Leverage the unwind user fp infrastructure to enable unwinding of user
space using back chain.  Enable HAVE_UNWIND_USER_FP and provide a s390-
specific implementation of unwind_user_fp_get_frame(), which uses the
back chain.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---

Notes (jremus):
    Changes in RFC v3:
    - New patch.  Implement unwind user fp using back chain on s390. Reuses
      logic from RFC v2 patch "unwind_user/backchain: Introduce back chain
      user space unwinding". (Josh)

 arch/s390/Kconfig                   |  1 +
 arch/s390/include/asm/unwind_user.h | 83 +++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+)

diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 52d3f3b3e086..eb6a0fe895bc 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_FP
 	select HAVE_UNWIND_USER_SFRAME
 	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
index 3a95be1eb886..99cbb83dd248 100644
--- a/arch/s390/include/asm/unwind_user.h
+++ b/arch/s390/include/asm/unwind_user.h
@@ -3,8 +3,12 @@
 #define _ASM_S390_UNWIND_USER_H
 
 #include <linux/sched/task_stack.h>
+#include <linux/security.h>
 #include <linux/types.h>
+#include <asm/asm-offsets.h>
 #include <asm/fpu-insn.h>
+#include <asm/stacktrace.h>
+#include <linux/unwind_user_types.h>
 
 #ifdef CONFIG_UNWIND_USER
 
@@ -95,6 +99,85 @@ static inline int arch_unwind_user_get_reg(unsigned long *val, int regnum)
 
 #endif /* CONFIG_UNWIND_USER */
 
+#ifdef CONFIG_HAVE_UNWIND_USER_FP
+
+static inline bool ip_within_vdso(unsigned long ip)
+{
+	return in_range(ip, current->mm->context.vdso_base, vdso_text_size());
+}
+
+static inline int unwind_user_fp_get_frame(struct unwind_user_state *state,
+					   struct unwind_user_frame *frame)
+{
+	struct stack_frame_user __user *sf;
+	unsigned long __user *ra_addr;
+	unsigned long sp;
+
+	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, ra_reg;
+
+		ra_addr = (unsigned long __user *)&sf->gprs[8];
+		if (__get_user(ra, ra_addr))
+			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;
+
+		ra_addr = (unsigned long __user *)&sf_vdso->return_address;
+		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. unwind_user_next_common()
+		 * disregards all other fields in outermost frame.
+		 */
+		frame->outermost = false;
+		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;
+		ra_addr = (unsigned long __user *)&sf->gprs[8];
+	}
+
+done:
+	frame->cfa_off = sp - state->sp + 160;
+	frame->sp_off = -160;
+	frame->fp.loc = UNWIND_USER_LOC_UNKNOWN;	/* Cannot unwind FP. */
+	frame->use_fp = false;
+	frame->ra.loc = UNWIND_USER_LOC_STACK;
+	frame->ra.offset = (unsigned long)ra_addr - (state->sp + frame->cfa_off);
+	frame->outermost = false;
+
+	return 0;
+}
+#define unwind_user_fp_get_frame unwind_user_fp_get_frame
+
+#endif /* CONFIG_HAVE_UNWIND_USER_FP */
+
 #include <asm-generic/unwind_user.h>
 
 #endif /* _ASM_S390_UNWIND_USER_H */
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH v3 14/17] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME
  2025-12-08 17:15 ` [RFC PATCH v3 14/17] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME Jens Remus
@ 2025-12-10 15:10   ` Heiko Carstens
  2025-12-12  8:13     ` Jens Remus
  0 siblings, 1 reply; 24+ messages in thread
From: Heiko Carstens @ 2025-12-10 15:10 UTC (permalink / raw)
  To: Jens Remus
  Cc: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
	Steven Rostedt, 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

Hi Jens,

On Mon, Dec 08, 2025 at 06:15:56PM +0100, Jens Remus wrote:
> +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;

IIRC, I mentioned this already last time. But it is not correct to access user
space floating point register contents like this. Due to in-kernel fpu/vector
register usage the user space register contents may have been saved away to
the per-thread vxrs save area, and registers may have been used for in-kernel
usage instead.
Read: the above code could access lazy register contents of in-kernel usage.

Change the above to something like:

	struct fpu *fpu = &current->thread.ufpu;

	save_user_fpu_regs();
	switch (regnum) {
	case 16: return fpu->vxrs[0].high;
	case 17: return fpu->vxrs[2].high;
	case 18: return fpu->vxrs[4].high;
	case 19: return fpu->vxrs[6].high;
	case 20: return fpu->vxrs[1].high;
	...

save_user_fpu_regs() will write all user space fpu/vector register contents to
the per-thread save area (if not already saved), and then it is possible to
read contents from there.

I'll see if I can provide something better for this use case, since this code
needs to access only the first 16 registers; so no need to write contents of
all registers to the save area.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH v3 05/17] s390: asm/dwarf.h should only be included in assembly files
  2025-12-08 17:15 ` [RFC PATCH v3 05/17] s390: asm/dwarf.h should only be included in assembly files Jens Remus
@ 2025-12-10 15:16   ` Heiko Carstens
  2025-12-11  9:43     ` Jens Remus
  0 siblings, 1 reply; 24+ messages in thread
From: Heiko Carstens @ 2025-12-10 15:16 UTC (permalink / raw)
  To: Jens Remus
  Cc: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
	Steven Rostedt, 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 Mon, Dec 08, 2025 at 06:15:47PM +0100, Jens Remus wrote:
> 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(-)

Is there a reason why this and the next two patches couldn't go upstream
already now? It looks like they improve things in any case.
No dependency to the sframe work.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH v3 13/17] s390/ptrace: Provide frame_pointer()
  2025-12-08 17:15 ` [RFC PATCH v3 13/17] s390/ptrace: Provide frame_pointer() Jens Remus
@ 2025-12-10 15:19   ` Heiko Carstens
  0 siblings, 0 replies; 24+ messages in thread
From: Heiko Carstens @ 2025-12-10 15:19 UTC (permalink / raw)
  To: Jens Remus
  Cc: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
	Steven Rostedt, 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 Mon, Dec 08, 2025 at 06:15:55PM +0100, Jens Remus wrote:
> 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)

"while at it", and then you don't convert user_mode() to a function? :)

Please provide a stand-alone patch for the "while at it" stuff, so it
can go independently.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH v3 05/17] s390: asm/dwarf.h should only be included in assembly files
  2025-12-10 15:16   ` Heiko Carstens
@ 2025-12-11  9:43     ` Jens Remus
  0 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-11  9:43 UTC (permalink / raw)
  To: Heiko Carstens
  Cc: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
	Steven Rostedt, 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 12/10/2025 4:16 PM, Heiko Carstens wrote:
> On Mon, Dec 08, 2025 at 06:15:47PM +0100, Jens Remus wrote:
>> Align to x86 and add a compile-time check that asm/dwarf.h is only
>> included in pure assembly files.

> Is there a reason why this and the next two patches couldn't go upstream
> already now? It looks like they improve things in any case.
> No dependency to the sframe work.

They probably could go upstream now.  At least this one.  For the two
other patches the question is whether we want to wait for whether the
respective x86 changes go upstream, as their descriptions claim to align
to x86.

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] 24+ messages in thread

* Re: [RFC PATCH v3 14/17] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME
  2025-12-10 15:10   ` Heiko Carstens
@ 2025-12-12  8:13     ` Jens Remus
  0 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-12  8:13 UTC (permalink / raw)
  To: Heiko Carstens
  Cc: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
	Steven Rostedt, 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

Hello Heiko,

thank you for the feedback!

On 12/10/2025 4:10 PM, Heiko Carstens wrote:
> On Mon, Dec 08, 2025 at 06:15:56PM +0100, Jens Remus wrote:
>> +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;
> 
> IIRC, I mentioned this already last time. But it is not correct to access user
> space floating point register contents like this. Due to in-kernel fpu/vector
> register usage the user space register contents may have been saved away to
> the per-thread vxrs save area, and registers may have been used for in-kernel
> usage instead.
> Read: the above code could access lazy register contents of in-kernel usage.
> 
> Change the above to something like:
> 
> 	struct fpu *fpu = &current->thread.ufpu;
> 
> 	save_user_fpu_regs();
> 	switch (regnum) {
> 	case 16: return fpu->vxrs[0].high;
> 	case 17: return fpu->vxrs[2].high;
> 	case 18: return fpu->vxrs[4].high;
> 	case 19: return fpu->vxrs[6].high;
> 	case 20: return fpu->vxrs[1].high;
> 	...
> 
> save_user_fpu_regs() will write all user space fpu/vector register contents to
> the per-thread save area (if not already saved), and then it is possible to
> read contents from there.

Thanks!  I have changed the code accordingly.  Works fine.

> I'll see if I can provide something better for this use case, since this code
> needs to access only the first 16 registers; so no need to write contents of
> all registers to the save area.

Ok.

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] 24+ messages in thread

* Re: [RFC PATCH v3 17/17] s390/unwind_user/fp: Enable back chain unwinding of user space
  2025-12-08 17:15 ` [RFC PATCH v3 17/17] s390/unwind_user/fp: Enable back chain unwinding of user space Jens Remus
@ 2025-12-12  9:21   ` Jens Remus
  0 siblings, 0 replies; 24+ messages in thread
From: Jens Remus @ 2025-12-12  9:21 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
	Steven Rostedt
  Cc: 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 12/8/2025 6:15 PM, Jens Remus wrote:

...

> Leverage the unwind user fp infrastructure to enable unwinding of user
> space using back chain.  Enable HAVE_UNWIND_USER_FP and provide a s390-
> specific implementation of unwind_user_fp_get_frame(), which uses the
> back chain.

> diff --git a/arch/s390/include/asm/unwind_user.h b/arch/s390/include/asm/unwind_user.h

> +static inline int unwind_user_fp_get_frame(struct unwind_user_state *state,
> +					   struct unwind_user_frame *frame)
> +{
> +	struct stack_frame_user __user *sf;
> +	unsigned long __user *ra_addr;
> +	unsigned long sp;
> +
> +	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, ra_reg;
> +
> +		ra_addr = (unsigned long __user *)&sf->gprs[8];
> +		if (__get_user(ra, ra_addr))
> +			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;
> +	}

I realized that this additional heuristic is flawed:

The topmost function may be past prologue, have allocated a new stack
frame, and called a function.  The callee may have saved its RA and SP
registers in the current stack frame, so that after the return from
function call, the heuristic would erroneously assume that the topmost
function is in early prologue and use the callee's RA and SP.

Instead of erroneously skipping the caller it might erroneously insert
a callee as caller.  I'll remove it again in the next version.

> +
> +	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;
> +
> +		ra_addr = (unsigned long __user *)&sf_vdso->return_address;
> +		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. unwind_user_next_common()
> +		 * disregards all other fields in outermost frame.
> +		 */
> +		frame->outermost = false;

		frame->outermost = 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;
> +		ra_addr = (unsigned long __user *)&sf->gprs[8];
> +	}
> +
> +done:
> +	frame->cfa_off = sp - state->sp + 160;
> +	frame->sp_off = -160;
> +	frame->fp.loc = UNWIND_USER_LOC_UNKNOWN;	/* Cannot unwind FP. */
> +	frame->use_fp = false;
> +	frame->ra.loc = UNWIND_USER_LOC_STACK;
> +	frame->ra.offset = (unsigned long)ra_addr - (state->sp + frame->cfa_off);
> +	frame->outermost = false;
> +
> +	return 0;
> +}
> +#define unwind_user_fp_get_frame unwind_user_fp_get_frame
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] 24+ messages in thread

end of thread, other threads:[~2025-12-12  9:22 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-08 17:15 [RFC PATCH v3 00/17] s390: SFrame user space unwinding Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 01/17] unwind_user: Enhance comments on get CFA, FP, and RA Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 02/17] unwind_user/fp: Use dummies instead of ifdef Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 03/17] x86/unwind_user: Guard unwind_user_word_size() by UNWIND_USER Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 04/17] x86/unwind_user: Simplify unwind_user_word_size() Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 05/17] s390: asm/dwarf.h should only be included in assembly files Jens Remus
2025-12-10 15:16   ` Heiko Carstens
2025-12-11  9:43     ` Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 06/17] s390/vdso: Avoid emitting DWARF CFI for non-vDSO Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 07/17] s390/vdso: Keep function symbols in vDSO Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 08/17] s390/vdso: Enable SFrame generation " Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 09/17] unwind_user: Enable archs that define CFA = SP_callsite + offset Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 10/17] unwind_user: Enable archs that pass RA in a register Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 11/17] unwind_user: Enable archs that save RA/FP in other registers Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 12/17] unwind_user/sframe: Enable archs with encoded SFrame CFA offsets Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 13/17] s390/ptrace: Provide frame_pointer() Jens Remus
2025-12-10 15:19   ` Heiko Carstens
2025-12-08 17:15 ` [RFC PATCH v3 14/17] s390/unwind_user/sframe: Enable HAVE_UNWIND_USER_SFRAME Jens Remus
2025-12-10 15:10   ` Heiko Carstens
2025-12-12  8:13     ` Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 15/17] unwind_user: Introduce FP/RA location unknown Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 16/17] unwind_user/fp: Use arch-specific helper to initialize FP frame Jens Remus
2025-12-08 17:15 ` [RFC PATCH v3 17/17] s390/unwind_user/fp: Enable back chain unwinding of user space Jens Remus
2025-12-12  9:21   ` 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).