* [PATCH v1 1/4] arm64/unwind_user/fp: Enable HAVE_UNWIND_USER_FP
2026-04-17 15:08 [PATCH v1 0/4] arm64: SFrame user space unwinding Jens Remus
@ 2026-04-17 15:08 ` Jens Remus
2026-04-17 15:08 ` [PATCH v1 2/4] arm64/uaccess: Add unsafe_copy_from_user() implementation Jens Remus
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: Jens Remus @ 2026-04-17 15:08 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Steven Rostedt, Josh Poimboeuf,
Indu Bhagat, Peter Zijlstra, Dylan Hatch, Weinan Liu
Cc: Jens Remus, linux-arm-kernel, linux-kernel, Heiko Carstens,
Ilya Leoshkevich
Add arm64 support for unwinding of user space using frame pointer (FP).
For this purpose enable the config option HAVE_UNWIND_USER_FP and
provide an arm64-specific ARCH_INIT_USER_FP_FRAME definition (specifying
the CFA offset from FP and the FP and RA offsets from CFA). Unlike x86,
as there is no mean to determine whether the user space IP in the
topmost frame is at function entry, rely on the common definition of
unwind_user_at_function_start(), which always returns false, and common
dummy definition of ARCH_INIT_USER_FP_ENTRY_FRAME.
For unwind user in general provide an arm64-specific implementation
of unwind_user_word_size().
Signed-off-by: Jens Remus <jremus@linux•ibm.com>
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/unwind_user.h | 42 ++++++++++++++++++++++++++++
2 files changed, 43 insertions(+)
create mode 100644 arch/arm64/include/asm/unwind_user.h
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 38dba5f7e4d2..994fd5162a1d 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -253,6 +253,7 @@ config ARM64
select HAVE_RUST if RUSTC_SUPPORTS_ARM64
select HAVE_STACKPROTECTOR
select HAVE_SYSCALL_TRACEPOINTS
+ select HAVE_UNWIND_USER_FP
select HAVE_KPROBES
select HAVE_KRETPROBES
select HAVE_GENERIC_VDSO
diff --git a/arch/arm64/include/asm/unwind_user.h b/arch/arm64/include/asm/unwind_user.h
new file mode 100644
index 000000000000..0641d4d97b0f
--- /dev/null
+++ b/arch/arm64/include/asm/unwind_user.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ARM64_UNWIND_USER_H
+#define _ASM_ARM64_UNWIND_USER_H
+
+#include <linux/sched/task_stack.h>
+#include <linux/types.h>
+
+#ifdef CONFIG_UNWIND_USER
+
+static inline int unwind_user_word_size(struct pt_regs *regs)
+{
+#ifdef COMPAT
+ if (compat_user_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 = { \
+ .rule = UNWIND_USER_CFA_RULE_FP_OFFSET, \
+ .offset = 2*(ws), \
+ }, \
+ .ra = { \
+ .rule = UNWIND_USER_RULE_CFA_OFFSET_DEREF, \
+ .offset = -1*(ws), \
+ }, \
+ .fp = { \
+ .rule = UNWIND_USER_RULE_CFA_OFFSET_DEREF, \
+ .offset = -2*(ws), \
+ }, \
+ .outermost = false,
+
+#endif /* CONFIG_HAVE_UNWIND_USER_FP */
+
+#include <asm-generic/unwind_user.h>
+
+#endif /* _ASM_ARM64_UNWIND_USER_H */
--
2.51.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v1 2/4] arm64/uaccess: Add unsafe_copy_from_user() implementation
2026-04-17 15:08 [PATCH v1 0/4] arm64: SFrame user space unwinding Jens Remus
2026-04-17 15:08 ` [PATCH v1 1/4] arm64/unwind_user/fp: Enable HAVE_UNWIND_USER_FP Jens Remus
@ 2026-04-17 15:08 ` Jens Remus
2026-04-17 15:08 ` [PATCH v1 3/4] arm64/vdso: Enable SFrame generation in vDSO Jens Remus
2026-04-17 15:08 ` [PATCH v1 4/4] arm64/unwind_user/sframe: Enable sframe unwinding on arm64 Jens Remus
3 siblings, 0 replies; 8+ messages in thread
From: Jens Remus @ 2026-04-17 15:08 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Steven Rostedt, Josh Poimboeuf,
Indu Bhagat, Peter Zijlstra, Dylan Hatch, Weinan Liu
Cc: Jens Remus, linux-arm-kernel, linux-kernel, Heiko Carstens,
Ilya Leoshkevich
This replicates Josh's x86 patch "x86/uaccess:
Add unsafe_copy_from_user() implementation" [1] for arm64.
Add an arm64 implementation of unsafe_copy_from_user() similar to the
existing unsafe_copy_to_user().
For this purpose rename the unsafe_copy_loop() helper to
unsafe_copy_to_user_loop() and introduce a unsafe_copy_from_user_loop()
helper.
While at it rename the unsafe_copy_to_user() local variables
__ucu_{dst|src|len} to __{dst|src|len} and change their pointer
type to void * to align to the x86 patch.
[1]: x86/uaccess: Add unsafe_copy_from_user() implementation,
https://lore.kernel.org/all/20251119132323.1281768-4-jremus@linux.ibm.com/
Signed-off-by: Jens Remus <jremus@linux•ibm.com>
---
arch/arm64/include/asm/uaccess.h | 39 ++++++++++++++++++++++++--------
1 file changed, 29 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 9810106a3f66..37d7d16b86a9 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -437,7 +437,7 @@ static inline void user_access_restore(unsigned long enabled) { }
* We want the unsafe accessors to always be inlined and use
* the error labels - thus the macro games.
*/
-#define unsafe_copy_loop(dst, src, len, type, label) \
+#define unsafe_copy_to_user_loop(dst, src, len, type, label) \
while (len >= sizeof(type)) { \
unsafe_put_user(*(type *)(src),(type __user *)(dst),label); \
dst += sizeof(type); \
@@ -445,15 +445,34 @@ static inline void user_access_restore(unsigned long enabled) { }
len -= sizeof(type); \
}
-#define unsafe_copy_to_user(_dst,_src,_len,label) \
-do { \
- char __user *__ucu_dst = (_dst); \
- const char *__ucu_src = (_src); \
- size_t __ucu_len = (_len); \
- unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u64, label); \
- unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u32, label); \
- unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u16, label); \
- unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u8, label); \
+#define unsafe_copy_to_user(_dst, _src, _len, label) \
+do { \
+ void __user *__dst = (_dst); \
+ const void *__src = (_src); \
+ size_t __len = (_len); \
+ unsafe_copy_to_user_loop(__dst, __src, __len, u64, label); \
+ unsafe_copy_to_user_loop(__dst, __src, __len, u32, label); \
+ unsafe_copy_to_user_loop(__dst, __src, __len, u16, label); \
+ unsafe_copy_to_user_loop(__dst, __src, __len, u8, label); \
+} while (0)
+
+#define unsafe_copy_from_user_loop(dst, src, len, type, label) \
+ while (len >= sizeof(type)) { \
+ unsafe_get_user(*(type *)(dst), (type __user *)(src), label); \
+ dst += sizeof(type); \
+ src += sizeof(type); \
+ len -= sizeof(type); \
+ }
+
+#define unsafe_copy_from_user(_dst, _src, _len, label) \
+do { \
+ void *__dst = (_dst); \
+ void __user *__src = (_src); \
+ size_t __len = (_len); \
+ unsafe_copy_from_user_loop(__dst, __src, __len, u64, label); \
+ unsafe_copy_from_user_loop(__dst, __src, __len, u32, label); \
+ unsafe_copy_from_user_loop(__dst, __src, __len, u16, label); \
+ unsafe_copy_from_user_loop(__dst, __src, __len, u8, label); \
} while (0)
#define INLINE_COPY_TO_USER
--
2.51.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v1 3/4] arm64/vdso: Enable SFrame generation in vDSO
2026-04-17 15:08 [PATCH v1 0/4] arm64: SFrame user space unwinding Jens Remus
2026-04-17 15:08 ` [PATCH v1 1/4] arm64/unwind_user/fp: Enable HAVE_UNWIND_USER_FP Jens Remus
2026-04-17 15:08 ` [PATCH v1 2/4] arm64/uaccess: Add unsafe_copy_from_user() implementation Jens Remus
@ 2026-04-17 15:08 ` Jens Remus
2026-05-22 1:31 ` Dylan Hatch
2026-04-17 15:08 ` [PATCH v1 4/4] arm64/unwind_user/sframe: Enable sframe unwinding on arm64 Jens Remus
3 siblings, 1 reply; 8+ messages in thread
From: Jens Remus @ 2026-04-17 15:08 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Steven Rostedt, Josh Poimboeuf,
Indu Bhagat, Peter Zijlstra, Dylan Hatch, Weinan Liu
Cc: Jens Remus, linux-arm-kernel, linux-kernel, Heiko Carstens,
Ilya Leoshkevich
This replicates Josh's x86 patch "x86/vdso: Enable sframe generation
in VDSO" [1] for arm64.
Enable .sframe generation in the vDSO library so kernel and user space
can unwind through it. Keep all function symbols in the vDSO .symtab
for stack trace purposes. This enables perf to lookup these function
symbols in addition to those already exported in vDSO .dynsym.
Starting with binutils 2.46 both GNU assembler and GNU linker
exclusively support generating and merging .sframe in SFrame V3 format.
For vDSO, only if supported by the assembler, generate .sframe, collect
it, mark it as KEEP, and generate a GNU_SFRAME program table entry.
Otherwise explicitly discard any .sframe.
[1]: x86/vdso: Enable sframe generation in VDSO,
https://lore.kernel.org/all/20260211141357.271402-7-jremus@linux.ibm.com/
Signed-off-by: Jens Remus <jremus@linux•ibm.com>
---
Notes (jremus):
@Dylan: Adding -Wa,--gsframe-3 to the VDSO CC_FLAGS_ADD_VDSO (and
AS_FLAGS_ADD_VDSO) may clash with your patch [1] that adds likewise
to the CC_FLAGS_REMOVE_VDSO. Any idea how to resolve?
[1]: [PATCH v3 2/8] arm64, unwind: build kernel with sframe V3 info,
https://lore.kernel.org/all/20260406185000.1378082-3-dylanbhatch@google.com/
arch/arm64/kernel/vdso/Makefile | 14 ++++++++++++--
arch/arm64/kernel/vdso/vdso.lds.S | 21 +++++++++++++++++++++
2 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
index 7dec05dd33b7..1f2f01673397 100644
--- a/arch/arm64/kernel/vdso/Makefile
+++ b/arch/arm64/kernel/vdso/Makefile
@@ -15,6 +15,10 @@ obj-vdso := vgettimeofday.o note.o sigreturn.o vgetrandom.o vgetrandom-chacha.o
targets := $(obj-vdso) vdso.so vdso.so.dbg
obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
+ifeq ($(CONFIG_AS_SFRAME3),y)
+ SFRAME_CFLAGS := -Wa,--gsframe-3
+endif
+
btildflags-$(CONFIG_ARM64_BTI_KERNEL) += -z force-bti
# -Bsymbolic has been added for consistency with arm, the compat vDSO and
@@ -41,7 +45,9 @@ CC_FLAGS_REMOVE_VDSO := $(CC_FLAGS_FTRACE) -Os $(CC_FLAGS_SCS) \
$(CC_FLAGS_LTO) $(CC_FLAGS_CFI) \
-Wmissing-prototypes -Wmissing-declarations
-CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
+CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables $(SFRAME_CFLAGS)
+
+AS_FLAGS_ADD_VDSO := $(SFRAME_CFLAGS)
CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_REMOVE_VDSO)
CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO)
@@ -49,6 +55,10 @@ CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO)
CFLAGS_vgettimeofday.o = $(CC_FLAGS_ADD_VDSO)
CFLAGS_vgetrandom.o = $(CC_FLAGS_ADD_VDSO)
+AFLAGS_sigreturn.o = $(AS_FLAGS_ADD_VDSO)
+
+AFLAGS_vgetrandom-chacha.o = $(AS_FLAGS_ADD_VDSO)
+
ifneq ($(c-gettimeofday-y),)
CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y)
endif
@@ -65,7 +75,7 @@ $(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE
$(call if_changed,vdsold_and_vdso_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)
diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S
index 52314be29191..527e107ca4b5 100644
--- a/arch/arm64/kernel/vdso/vdso.lds.S
+++ b/arch/arm64/kernel/vdso/vdso.lds.S
@@ -15,6 +15,8 @@
#include <asm-generic/vmlinux.lds.h>
#include <vdso/datapage.h>
+#define KEEP_SFRAME IS_ENABLED(CONFIG_AS_SFRAME)
+
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
@@ -68,6 +70,13 @@ SECTIONS
*(.igot .igot.plt)
} :text
+#if KEEP_SFRAME
+ .sframe : {
+ KEEP (*(.sframe))
+ *(.sframe.*)
+ } :text :sframe
+#endif
+
_end = .;
PROVIDE(end = .);
@@ -78,9 +87,18 @@ SECTIONS
*(.data .data.* .gnu.linkonce.d.* .sdata*)
*(.bss .sbss .dynbss .dynsbss)
*(.eh_frame .eh_frame_hdr)
+#if !KEEP_SFRAME
+ *(.sframe)
+ *(.sframe.*)
+#endif
}
}
+/*
+ * Very old versions of ld do not recognize this name token; use the constant.
+ */
+#define PT_GNU_SFRAME 0x6474e554
+
/*
* We must supply the ELF program headers explicitly to get just one
* PT_LOAD segment, and set the flags explicitly to make segments read-only.
@@ -90,6 +108,9 @@ PHDRS
text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
note PT_NOTE FLAGS(4); /* PF_R */
+#if KEEP_SFRAME
+ sframe PT_GNU_SFRAME FLAGS(4); /* PF_R */
+#endif
}
/*
--
2.51.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v1 3/4] arm64/vdso: Enable SFrame generation in vDSO
2026-04-17 15:08 ` [PATCH v1 3/4] arm64/vdso: Enable SFrame generation in vDSO Jens Remus
@ 2026-05-22 1:31 ` Dylan Hatch
2026-05-22 8:51 ` Jens Remus
0 siblings, 1 reply; 8+ messages in thread
From: Dylan Hatch @ 2026-05-22 1:31 UTC (permalink / raw)
To: Jens Remus
Cc: Catalin Marinas, Will Deacon, Steven Rostedt, Josh Poimboeuf,
Indu Bhagat, Peter Zijlstra, Weinan Liu, linux-arm-kernel,
linux-kernel, Heiko Carstens, Ilya Leoshkevich
Hi Jens,
Sorry for the slow reply on this.
On Fri, Apr 17, 2026 at 8:08 AM Jens Remus <jremus@linux•ibm.com> wrote:
>
> This replicates Josh's x86 patch "x86/vdso: Enable sframe generation
> in VDSO" [1] for arm64.
>
> Enable .sframe generation in the vDSO library so kernel and user space
> can unwind through it. Keep all function symbols in the vDSO .symtab
> for stack trace purposes. This enables perf to lookup these function
> symbols in addition to those already exported in vDSO .dynsym.
>
> Starting with binutils 2.46 both GNU assembler and GNU linker
> exclusively support generating and merging .sframe in SFrame V3 format.
> For vDSO, only if supported by the assembler, generate .sframe, collect
> it, mark it as KEEP, and generate a GNU_SFRAME program table entry.
> Otherwise explicitly discard any .sframe.
>
> [1]: x86/vdso: Enable sframe generation in VDSO,
> https://lore.kernel.org/all/20260211141357.271402-7-jremus@linux.ibm.com/
>
> Signed-off-by: Jens Remus <jremus@linux•ibm.com>
> ---
>
> Notes (jremus):
> @Dylan: Adding -Wa,--gsframe-3 to the VDSO CC_FLAGS_ADD_VDSO (and
> AS_FLAGS_ADD_VDSO) may clash with your patch [1] that adds likewise
> to the CC_FLAGS_REMOVE_VDSO. Any idea how to resolve?
>
> [1]: [PATCH v3 2/8] arm64, unwind: build kernel with sframe V3 info,
> https://lore.kernel.org/all/20260406185000.1378082-3-dylanbhatch@google.com/
In a kernel tree with both your patch and my [1] patch merged, I
believe we'd want to hold two invariants true:
1. If HAVE_UNWIND_KERNEL_SFRAME=n, we must not build the kernel with .sframe.
2. If AS_SFRAME3=y, we must build vDSO with .sframe.
Since HAVE_UNWIND_KERNEL_SFRAME=y implies AS_SFRAME3=y, I wonder if we
should be able to drop CC_FLAGS_SFRAME from CC_FLAGS_REMOVE_VDSO and
move some definitions:
diff --git a/Makefile b/Makefile
index 227fda16deb1..ef059bccb8c1 100644
--- a/Makefile
+++ b/Makefile
@@ -1147,12 +1147,15 @@ endif
# Ensure compilers do not transform certain loops into calls to wcslen()
KBUILD_CFLAGS += -fno-builtin-wcslen
+ifeq ($(CONFIG_AS_SFRAME3),y)
+CC_FLAGS_SFRAME := -Wa,--gsframe-3
+export CC_FLAGS_SFRAME
+endif
+
# build with sframe table
ifdef CONFIG_HAVE_UNWIND_KERNEL_SFRAME
-CC_FLAGS_SFRAME := -Wa,--gsframe-3
KBUILD_CFLAGS += $(CC_FLAGS_SFRAME)
KBUILD_AFLAGS += $(CC_FLAGS_SFRAME)
-export CC_FLAGS_SFRAME
endif
# change __FILE__ to the relative path to the source directory
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
index e90427a8d0f6..f03cac27857c 100644
--- a/arch/arm64/kernel/vdso/Makefile
+++ b/arch/arm64/kernel/vdso/Makefile
@@ -15,10 +15,6 @@ obj-vdso := vgettimeofday.o note.o sigreturn.o
vgetrandom.o vgetrandom-chacha.o
targets := $(obj-vdso) vdso.so vdso.so.dbg
obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
-ifeq ($(CONFIG_AS_SFRAME3),y)
- SFRAME_CFLAGS := -Wa,--gsframe-3
-endif
-
btildflags-$(CONFIG_ARM64_BTI_KERNEL) += -z force-bti
# -Bsymbolic has been added for consistency with arm, the compat vDSO and
@@ -42,12 +38,12 @@ ccflags-y += -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
CC_FLAGS_REMOVE_VDSO := $(CC_FLAGS_FTRACE) -Os $(CC_FLAGS_SCS) \
$(RANDSTRUCT_CFLAGS) $(KSTACK_ERASE_CFLAGS) \
$(GCC_PLUGINS_CFLAGS) \
- $(CC_FLAGS_LTO) $(CC_FLAGS_CFI) $(CC_FLAGS_SFRAME) \
+ $(CC_FLAGS_LTO) $(CC_FLAGS_CFI) \
-Wmissing-prototypes -Wmissing-declarations
-CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
$(SFRAME_CFLAGS)
+CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
$(CC_FLAGS_SFRAME)
-AS_FLAGS_ADD_VDSO := $(SFRAME_CFLAGS)
+AS_FLAGS_ADD_VDSO := $(CC_FLAGS_SFRAME)
CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_REMOVE_VDSO)
CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO)
If done this way I think we will add the -Wa,--gsframe-3 twice when
HAVE_UNWIND_KERNEL_SFRAME=y, but maybe that's not a problem? This
could probably be folded into either this patch or mine [1], depending
which is applied first. I'm happy to rebase my unwind-for-kernel
patches onto this series, or we can do the other way around if that
works better.
What do you think?
Thanks,
Dylan
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v1 3/4] arm64/vdso: Enable SFrame generation in vDSO
2026-05-22 1:31 ` Dylan Hatch
@ 2026-05-22 8:51 ` Jens Remus
2026-05-22 18:24 ` Dylan Hatch
0 siblings, 1 reply; 8+ messages in thread
From: Jens Remus @ 2026-05-22 8:51 UTC (permalink / raw)
To: Dylan Hatch
Cc: Catalin Marinas, Will Deacon, Steven Rostedt, Josh Poimboeuf,
Indu Bhagat, Peter Zijlstra, Weinan Liu, linux-arm-kernel,
linux-kernel, Heiko Carstens, Ilya Leoshkevich
Hello Dylan,
thank you for the feedback!
On 5/22/2026 3:31 AM, Dylan Hatch wrote:
> On Fri, Apr 17, 2026 at 8:08 AM Jens Remus <jremus@linux•ibm.com> wrote:
>>
>> This replicates Josh's x86 patch "x86/vdso: Enable sframe generation
>> in VDSO" [1] for arm64.
>>
>> Enable .sframe generation in the vDSO library so kernel and user space
>> can unwind through it. Keep all function symbols in the vDSO .symtab
>> for stack trace purposes. This enables perf to lookup these function
>> symbols in addition to those already exported in vDSO .dynsym.
>>
>> Starting with binutils 2.46 both GNU assembler and GNU linker
>> exclusively support generating and merging .sframe in SFrame V3 format.
>> For vDSO, only if supported by the assembler, generate .sframe, collect
>> it, mark it as KEEP, and generate a GNU_SFRAME program table entry.
>> Otherwise explicitly discard any .sframe.
>>
>> [1]: x86/vdso: Enable sframe generation in VDSO,
>> https://lore.kernel.org/all/20260211141357.271402-7-jremus@linux.ibm.com/
>>
>> Signed-off-by: Jens Remus <jremus@linux•ibm.com>
>> ---
>>
>> Notes (jremus):
>> @Dylan: Adding -Wa,--gsframe-3 to the VDSO CC_FLAGS_ADD_VDSO (and
>> AS_FLAGS_ADD_VDSO) may clash with your patch [1] that adds likewise
>> to the CC_FLAGS_REMOVE_VDSO. Any idea how to resolve?
>>
>> [1]: [PATCH v3 2/8] arm64, unwind: build kernel with sframe V3 info,
>> https://lore.kernel.org/all/20260406185000.1378082-3-dylanbhatch@google.com/
>
> In a kernel tree with both your patch and my [1] patch merged, I
> believe we'd want to hold two invariants true:
>
> 1. If HAVE_UNWIND_KERNEL_SFRAME=n, we must not build the kernel with .sframe.
> 2. If AS_SFRAME3=y, we must build vDSO with .sframe.
>
> Since HAVE_UNWIND_KERNEL_SFRAME=y implies AS_SFRAME3=y, I wonder if we
> should be able to drop CC_FLAGS_SFRAME from CC_FLAGS_REMOVE_VDSO and
> move some definitions:
>
> diff --git a/Makefile b/Makefile
> index 227fda16deb1..ef059bccb8c1 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1147,12 +1147,15 @@ endif
> # Ensure compilers do not transform certain loops into calls to wcslen()
> KBUILD_CFLAGS += -fno-builtin-wcslen
>
> +ifeq ($(CONFIG_AS_SFRAME3),y)
> +CC_FLAGS_SFRAME := -Wa,--gsframe-3
> +export CC_FLAGS_SFRAME
> +endif
> +
> # build with sframe table
> ifdef CONFIG_HAVE_UNWIND_KERNEL_SFRAME
> -CC_FLAGS_SFRAME := -Wa,--gsframe-3
> KBUILD_CFLAGS += $(CC_FLAGS_SFRAME)
> KBUILD_AFLAGS += $(CC_FLAGS_SFRAME)
> -export CC_FLAGS_SFRAME
> endif
>
> # change __FILE__ to the relative path to the source directory
> diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
> index e90427a8d0f6..f03cac27857c 100644
> --- a/arch/arm64/kernel/vdso/Makefile
> +++ b/arch/arm64/kernel/vdso/Makefile
> @@ -15,10 +15,6 @@ obj-vdso := vgettimeofday.o note.o sigreturn.o
> vgetrandom.o vgetrandom-chacha.o
> targets := $(obj-vdso) vdso.so vdso.so.dbg
> obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
>
> -ifeq ($(CONFIG_AS_SFRAME3),y)
> - SFRAME_CFLAGS := -Wa,--gsframe-3
> -endif
> -
> btildflags-$(CONFIG_ARM64_BTI_KERNEL) += -z force-bti
>
> # -Bsymbolic has been added for consistency with arm, the compat vDSO and
> @@ -42,12 +38,12 @@ ccflags-y += -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
> CC_FLAGS_REMOVE_VDSO := $(CC_FLAGS_FTRACE) -Os $(CC_FLAGS_SCS) \
> $(RANDSTRUCT_CFLAGS) $(KSTACK_ERASE_CFLAGS) \
> $(GCC_PLUGINS_CFLAGS) \
> - $(CC_FLAGS_LTO) $(CC_FLAGS_CFI) $(CC_FLAGS_SFRAME) \
> + $(CC_FLAGS_LTO) $(CC_FLAGS_CFI) \
> -Wmissing-prototypes -Wmissing-declarations
>
> -CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
> $(SFRAME_CFLAGS)
> +CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
> $(CC_FLAGS_SFRAME)
>
> -AS_FLAGS_ADD_VDSO := $(SFRAME_CFLAGS)
> +AS_FLAGS_ADD_VDSO := $(CC_FLAGS_SFRAME)
>
> CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_REMOVE_VDSO)
> CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO)
>
>
> If done this way I think we will add the -Wa,--gsframe-3 twice when
> HAVE_UNWIND_KERNEL_SFRAME=y, but maybe that's not a problem? This
> could probably be folded into either this patch or mine [1], depending
> which is applied first. I'm happy to rebase my unwind-for-kernel
> patches onto this series, or we can do the other way around if that
> works better.
>
> What do you think?
I like that approach. Go ahead.
Regards,
Jens
--
Jens Remus
Linux on Z Development (D3303)
jremus@de•ibm.com / jremus@linux•ibm.com
IBM Deutschland Research & Development GmbH; Vorsitzender des Aufsichtsrats: Wolfgang Wendt; Geschäftsführung: David Faller; Sitz der Gesellschaft: Ehningen; Registergericht: Amtsgericht Stuttgart, HRB 243294
IBM Data Privacy Statement: https://www.ibm.com/privacy/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v1 3/4] arm64/vdso: Enable SFrame generation in vDSO
2026-05-22 8:51 ` Jens Remus
@ 2026-05-22 18:24 ` Dylan Hatch
0 siblings, 0 replies; 8+ messages in thread
From: Dylan Hatch @ 2026-05-22 18:24 UTC (permalink / raw)
To: Jens Remus
Cc: Catalin Marinas, Will Deacon, Steven Rostedt, Josh Poimboeuf,
Indu Bhagat, Peter Zijlstra, Weinan Liu, linux-arm-kernel,
linux-kernel, Heiko Carstens, Ilya Leoshkevich
On Fri, May 22, 2026 at 1:51 AM Jens Remus <jremus@linux•ibm.com> wrote:
>
> Hello Dylan,
>
> thank you for the feedback!
>
> On 5/22/2026 3:31 AM, Dylan Hatch wrote:
> > On Fri, Apr 17, 2026 at 8:08 AM Jens Remus <jremus@linux•ibm.com> wrote:
> >>
> >> This replicates Josh's x86 patch "x86/vdso: Enable sframe generation
> >> in VDSO" [1] for arm64.
> >>
> >> Enable .sframe generation in the vDSO library so kernel and user space
> >> can unwind through it. Keep all function symbols in the vDSO .symtab
> >> for stack trace purposes. This enables perf to lookup these function
> >> symbols in addition to those already exported in vDSO .dynsym.
> >>
> >> Starting with binutils 2.46 both GNU assembler and GNU linker
> >> exclusively support generating and merging .sframe in SFrame V3 format.
> >> For vDSO, only if supported by the assembler, generate .sframe, collect
> >> it, mark it as KEEP, and generate a GNU_SFRAME program table entry.
> >> Otherwise explicitly discard any .sframe.
> >>
> >> [1]: x86/vdso: Enable sframe generation in VDSO,
> >> https://lore.kernel.org/all/20260211141357.271402-7-jremus@linux.ibm.com/
> >>
> >> Signed-off-by: Jens Remus <jremus@linux•ibm.com>
> >> ---
> >>
> >> Notes (jremus):
> >> @Dylan: Adding -Wa,--gsframe-3 to the VDSO CC_FLAGS_ADD_VDSO (and
> >> AS_FLAGS_ADD_VDSO) may clash with your patch [1] that adds likewise
> >> to the CC_FLAGS_REMOVE_VDSO. Any idea how to resolve?
> >>
> >> [1]: [PATCH v3 2/8] arm64, unwind: build kernel with sframe V3 info,
> >> https://lore.kernel.org/all/20260406185000.1378082-3-dylanbhatch@google.com/
> >
> > In a kernel tree with both your patch and my [1] patch merged, I
> > believe we'd want to hold two invariants true:
> >
> > 1. If HAVE_UNWIND_KERNEL_SFRAME=n, we must not build the kernel with .sframe.
> > 2. If AS_SFRAME3=y, we must build vDSO with .sframe.
> >
> > Since HAVE_UNWIND_KERNEL_SFRAME=y implies AS_SFRAME3=y, I wonder if we
> > should be able to drop CC_FLAGS_SFRAME from CC_FLAGS_REMOVE_VDSO and
> > move some definitions:
> >
> > diff --git a/Makefile b/Makefile
> > index 227fda16deb1..ef059bccb8c1 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -1147,12 +1147,15 @@ endif
> > # Ensure compilers do not transform certain loops into calls to wcslen()
> > KBUILD_CFLAGS += -fno-builtin-wcslen
> >
> > +ifeq ($(CONFIG_AS_SFRAME3),y)
> > +CC_FLAGS_SFRAME := -Wa,--gsframe-3
> > +export CC_FLAGS_SFRAME
> > +endif
> > +
> > # build with sframe table
> > ifdef CONFIG_HAVE_UNWIND_KERNEL_SFRAME
> > -CC_FLAGS_SFRAME := -Wa,--gsframe-3
> > KBUILD_CFLAGS += $(CC_FLAGS_SFRAME)
> > KBUILD_AFLAGS += $(CC_FLAGS_SFRAME)
> > -export CC_FLAGS_SFRAME
> > endif
> >
> > # change __FILE__ to the relative path to the source directory
> > diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
> > index e90427a8d0f6..f03cac27857c 100644
> > --- a/arch/arm64/kernel/vdso/Makefile
> > +++ b/arch/arm64/kernel/vdso/Makefile
> > @@ -15,10 +15,6 @@ obj-vdso := vgettimeofday.o note.o sigreturn.o
> > vgetrandom.o vgetrandom-chacha.o
> > targets := $(obj-vdso) vdso.so vdso.so.dbg
> > obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
> >
> > -ifeq ($(CONFIG_AS_SFRAME3),y)
> > - SFRAME_CFLAGS := -Wa,--gsframe-3
> > -endif
> > -
> > btildflags-$(CONFIG_ARM64_BTI_KERNEL) += -z force-bti
> >
> > # -Bsymbolic has been added for consistency with arm, the compat vDSO and
> > @@ -42,12 +38,12 @@ ccflags-y += -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
> > CC_FLAGS_REMOVE_VDSO := $(CC_FLAGS_FTRACE) -Os $(CC_FLAGS_SCS) \
> > $(RANDSTRUCT_CFLAGS) $(KSTACK_ERASE_CFLAGS) \
> > $(GCC_PLUGINS_CFLAGS) \
> > - $(CC_FLAGS_LTO) $(CC_FLAGS_CFI) $(CC_FLAGS_SFRAME) \
> > + $(CC_FLAGS_LTO) $(CC_FLAGS_CFI) \
> > -Wmissing-prototypes -Wmissing-declarations
> >
> > -CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
> > $(SFRAME_CFLAGS)
> > +CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
> > $(CC_FLAGS_SFRAME)
> >
> > -AS_FLAGS_ADD_VDSO := $(SFRAME_CFLAGS)
> > +AS_FLAGS_ADD_VDSO := $(CC_FLAGS_SFRAME)
> >
> > CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_REMOVE_VDSO)
> > CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO)
> >
> >
> > If done this way I think we will add the -Wa,--gsframe-3 twice when
> > HAVE_UNWIND_KERNEL_SFRAME=y, but maybe that's not a problem? This
> > could probably be folded into either this patch or mine [1], depending
> > which is applied first. I'm happy to rebase my unwind-for-kernel
> > patches onto this series, or we can do the other way around if that
> > works better.
> >
> > What do you think?
>
> I like that approach. Go ahead.
Do you have an updated version you can send? I noticed some of these
patches don't apply cleanly on Steven's current sframe branch. If you
can't get to it before you leave then no worries, have a good vacation
:)
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v1 4/4] arm64/unwind_user/sframe: Enable sframe unwinding on arm64
2026-04-17 15:08 [PATCH v1 0/4] arm64: SFrame user space unwinding Jens Remus
` (2 preceding siblings ...)
2026-04-17 15:08 ` [PATCH v1 3/4] arm64/vdso: Enable SFrame generation in vDSO Jens Remus
@ 2026-04-17 15:08 ` Jens Remus
3 siblings, 0 replies; 8+ messages in thread
From: Jens Remus @ 2026-04-17 15:08 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Steven Rostedt, Josh Poimboeuf,
Indu Bhagat, Peter Zijlstra, Dylan Hatch, Weinan Liu
Cc: Jens Remus, linux-arm-kernel, linux-kernel, Heiko Carstens,
Ilya Leoshkevich
Add arm64 support for unwinding of user space using SFrame.
This leverages the unwind user (sframe) support for s390 which
enables architectures that pass the return address in a register,
may not necessarily save the return address on the stack (for
instance in leaf functions), and have SP at call site equal
SP at entry.
For this purpose provide arm64-specific unwind_user_get_ra_reg() and
unwind_user_get_reg() implementations, which return the value of the
link register (LR) or an arbitrary register in the topmost user space
frame. Define the arm64 SP and FP DWARF register numbers.
Signed-off-by: Jens Remus <jremus@linux•ibm.com>
---
Notes (jremus):
Note: An arm64 implementation of unwind_user_get_reg() is strictly
only needed, if SFrame V3 flexible FDE would get generated for aarch64,
which is currently not the case in GNU Binutils 2.46.
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/unwind_user.h | 23 +++++++++++++++++++++
arch/arm64/include/asm/unwind_user_sframe.h | 8 +++++++
3 files changed, 32 insertions(+)
create mode 100644 arch/arm64/include/asm/unwind_user_sframe.h
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 994fd5162a1d..641a3a5fe5c9 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -254,6 +254,7 @@ config ARM64
select HAVE_STACKPROTECTOR
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_UNWIND_USER_FP
+ select HAVE_UNWIND_USER_SFRAME
select HAVE_KPROBES
select HAVE_KRETPROBES
select HAVE_GENERIC_VDSO
diff --git a/arch/arm64/include/asm/unwind_user.h b/arch/arm64/include/asm/unwind_user.h
index 0641d4d97b0f..3c7fd8c4ba5b 100644
--- a/arch/arm64/include/asm/unwind_user.h
+++ b/arch/arm64/include/asm/unwind_user.h
@@ -4,6 +4,7 @@
#include <linux/sched/task_stack.h>
#include <linux/types.h>
+#include <asm/insn.h>
#ifdef CONFIG_UNWIND_USER
@@ -16,6 +17,28 @@ static inline int unwind_user_word_size(struct pt_regs *regs)
return sizeof(long);
}
+static inline int unwind_user_get_ra_reg(unsigned long *val)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ *val = regs->regs[AARCH64_INSN_REG_LR];
+ return 0;
+}
+#define unwind_user_get_ra_reg unwind_user_get_ra_reg
+
+static inline int unwind_user_get_reg(unsigned long *val, unsigned int regnum)
+{
+ const struct pt_regs *regs = task_pt_regs(current);
+
+ if (regnum <= 30)
+ /* DWARF register numbers 0..15 */
+ *val = regs->regs[regnum];
+ else
+ return -EINVAL;
+
+ return 0;
+}
+#define unwind_user_get_reg unwind_user_get_reg
+
#endif /* CONFIG_UNWIND_USER */
#ifdef CONFIG_HAVE_UNWIND_USER_FP
diff --git a/arch/arm64/include/asm/unwind_user_sframe.h b/arch/arm64/include/asm/unwind_user_sframe.h
new file mode 100644
index 000000000000..65c0a6b6c835
--- /dev/null
+++ b/arch/arm64/include/asm/unwind_user_sframe.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ARM64_UNWIND_USER_SFRAME_H
+#define _ASM_ARM64_UNWIND_USER_SFRAME_H
+
+#define SFRAME_REG_SP 31
+#define SFRAME_REG_FP 29
+
+#endif /* _ASM_ARM64_UNWIND_USER_SFRAME_H */
--
2.51.0
^ permalink raw reply related [flat|nested] 8+ messages in thread