Re: [RFC PATCH v2 00/24] unwind_user: Implement .eh_frame handling
From: Fangrui Song
Date: Mon Sep 07 2026 - 15:18:15 EST
On Fri, Aug 21, 2026 at 12:53 PM Jens Remus <jremus@xxxxxxxxxxxxx> wrote:
>
> This series adds support for parsing DWARF Call Frame Information (CFI)
> from the .eh_frame_hdr and .eh_frame sections of user space ELF files.
>
> The code is based on the deferred unwind user work originally done for
> SFrame by Josh, Steven, and myself:
>
> v4 : https://lore.kernel.org/all/cover.1737511963.git.jpoimboe@xxxxxxxxxx/
> v10: https://lore.kernel.org/all/20250827201548.448472904@xxxxxxxxxx/
> v16: https://lore.kernel.org/all/20260521142546.3908498-1-jremus@xxxxxxxxxxxxx/
>
> The goal is to make user space stack traces available in-kernel without
> requiring frame pointers and without copying large parts of the user
> stack for later processing.
>
> Today, reliable user stack traces from the kernel generally requires
> frame pointers. Otherwise, profilers such as perf have to copy large
> amounts of user space stack into the kernel ring buffer and process it
> later. Frame pointers are simple and robust, but enabling them for
> all executables and libraries has a performance cost.
>
> Another issue is that the frame layout can vary between compilers and
> architectures, and on architectures such as s390 there is no defined
> frame layout which allows reliable frame-pointer based stack tracing.
> The only way to perform user space profiling on there architectures is
> to copy the user space into the kernel buffer.
>
>
> The .eh_frame section is already emitted by most toolchains on most
> architectures unless explicitly disabled. It contains DWARF CFI
> describing how to recover the caller state at any point in a function.
> The .eh_frame_hdr section provides a binary search table for looking
> up the Frame Description Entry (FDE) for a given instruction pointer
> (IP).
>
> Because the .eh_frame_hdr and .eh_frame sections live in the ELF file,
> they need to be faulted in when used. This means that walking the user
> space stack requires being in a faultable context. As profilers like
> perf request a stack trace in interrupt or NMI context, the walking
> cannot be done when requested. This series reuses the deferred unwind
> user framework, that performed the actual user stack trace is later in
> a faultable context, before the task returns to user space.
>
> This series implements .eh_frame[_hdr] support for the deferred unwind
> user code and enables it for x86-64 and s390.
>
> It intentionally not implement a complete DWARF unwinder. It evaluates
> only the subset of DWARF CFI needed for stack tracing:
>
> - Call Frame Address (CFA): Using rule from DWARF CFI.
>
> - Stack pointer (SP): Using an implicit rule based on the CFA
> definition (SP = CFA for most architectures).
>
> - Frame pointer (FP): Using rule from DWARF CFI.
>
> - Return address (RA): Using rule from DWARF CFI.
>
> Unsupported CFI instructions, unsupported expressions, invalid data, or
> user memory faults stop the stack tracing safely and results in a partial
> stack trace.
>
>
> This series applies on top of v7.2 tag:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git v7.2
>
> The to be stack-traced user space executables and libraries need to
> contain .eh_frame_hdr and .eh_frame sections as well as a GNU_EH_FRAME
> PHDR.
>
> Namhyung Kim's related perf tools deferred callchain support can be used
> for testing, for example:
>
> perf record --call-graph fp,defer ...
> perf report
> perf script
>
>
> Why .eh_frame?
>
> This series is not meant to replace or undermine the SFrame work.
> SFrame remains the simpler and more purpose-built format for user stack
> tracing. The motivation for .eh_frame support is pragmatic: .eh_frame
> is already widely deployed today.
>
> - Availability and maturity: .eh_frame is already present in most ELF
> binaries for C++ exception handling. It has been used in production
> for decades for exception handling and debugger stack unwinding.
>
> - Toolchain support: .eh_frame is supported across all major compilers
> and architectures today, whereas .sframe adoption is still emerging.
>
> - Size: .sframe would be added in addition to existing .eh_frame[_hdr]
> rather than replacing it, increasing the ELF file size. [1]
>
>
> Addressing historical DWARF concerns:
>
> Using DWARF for kernel unwinding has a bad history. Previous attempts
> were complex, fragile, slow, and hard to maintain. Hand-written
> assembly and the complexity of the DWARF state machine were among the
> reasons the simpler ORC kernel unwind format was developed. [2,3,4]
>
> However, this implementation for user space stack tracing differs from
> those problematic kernel unwinding attempts:
>
> - It stack traces user space, not kernel.
>
> - It runs in a deferred, faultable context, not in NMI, interrupt, or
> oops context.
>
> - It may return partial stack traces. Bad CFI, unsupported operations,
> invalid user memory, or faults are allowed to terminate the unwind.
>
> - It implements only the CFI subset needed for stack tracing, not a
> general DWARF unwinder.
>
> - It does not include a general-purpose DWARF expression VM. Expression
> size is bounded. Only a small number of pattern-matched expressions
> is supported (e.g. DRAP and PLT expressions on x86). Unsupported
> expressions cause stack tracing to fail safely.
>
> - All user memory access uses [unsafe_]get_user() with proper bounds
> checking and fault handling.
>
> - Corruption detection with automatic section removal on invalid
> .eh_frame prevents further stack tracing attempts.
>
>
> Limitations and future work:
>
> - CIE version 1 support only and no DWARF64 support, as I have not run
> into either during my testing.
>
> - Signal frames are not handled yet. An architecture hook could support
> unwinding through FDEs whose CIE augmentation contains 'S' (signal
> frame), similar to Glibc's SFrame backtrace() support. See also my
> "[RFC PATCH v1 0/5] s390: Signal frame user space unwinding". [5]
>
> - x86-32, x86-x32, and 32-bit compat mode support not implemented yet.
>
> - CIE caching would be useful. Reading an FDE requires reading its
> referenced CIE first to obtain the FDE encoding. Most .eh_frame
> sections have only a very small number of CIEs, often one default
> CIE shared by most FDEs and possibly one signal frame CIE. Caching
> the last CIE per section, together with the initial CFA, FP, and RA
> rules, would avoid repeated CIE parsing and initial CFI instruction
> processing.
>
>
> [1]: https://lore.kernel.org/all/CAN30aBFVDxeoXApn_g_Hw0Ayhi4V=m7CcX8UDO6ZDTi6xA-3Pg@xxxxxxxxxxxxxx/
> [2]: https://lwn.net/Articles/727553/
> [3]: https://lkml.org/lkml/2012/2/10/356
> [4]: https://lkml.org/lkml/2017/5/20/165
> [5]: https://lore.kernel.org/all/20260127153331.2902504-1-jremus@xxxxxxxxxxxxx/
>
>
> Patches 1-6 add base functionality to unwind user to support .eh_frame-
> based (or .sframe-based) unwinding. Patches originate from my latest
> .sframe patch series.
>
> Patches 7-10 add the basic infrastructure for reading .eh_frame_hdr and
> .eh_frame sections and storing them in a per-mm maple tree.
>
> Patches 11-14 wire up the eh_frame infrastructure to the unwind user
> framework and add error handling and debugging support.
>
> Patch 15 duplicates registered .eh_frame_hdr section data on clone/fork.
>
> Patch 16 improves .eh_frame DWARF CFI instruction processing.
>
> Patch 17 enables architectures to implement selected DWARF expressions
> in CFI instructions.
>
> Patches 18-21 enable .eh_frame unwinding on x86-64 with minimal DWARF
> expression support for DRAP and PLT expressions.
>
> Patches 22-23 enable .eh_frame unwinding on s390.
>
> Patch 24 adds a prctl() interface for (un)registering .eh_frame_hdr
> sections for shared libraries. I will send a related test-patch for
> Glibc separately.
>
>
> Changes in RFC v2:
> - Addressed most of Sashikos AI review feedback.
> - Dropped patch that added support for linear .eh_frame search, as
> there is no good mean to limit it from reading outside of the
> .eh_frame section.
> - Tweaked limits based on limited testing (still fairly arbitrary;
> needs more thought):
> - Reduced state stack depth limit to 1.
> - Added FDE length limit of 32.768 bytes.
> - Added CFI instruction limit (CIE+FDE) of 16.384 instructions.
>
>
> Note that I will be away from keyboard for two weeks. I'll reply
> to your (and Sashiko AI's) feedback afterwards.
>
>
> Thanks and regards,
> Jens
Thanks for pivoting to .eh_frame unwinding. This work is highly appreciated.
The moment deferred unwinding is implemented, the kernel space
objection (https://lwn.net/Articles/728339/) no longer applies.
Every argument for ORC (and derived formats like SFrame) -- that it
must not crash during crash handling, that it is simple enough to be
bug-free, and that it is fast enough for lockdep -- was formulated
specifically to justify that kernel execution path.
On the userspace side, we are seeing major advances in compact unwinding:
* x86-64 (Alexis Engelke): Implemented a compact-unwind encoder in lld
that encodes 100% of Clang (main) -O3 and 99.9% of GCC 15 -O3
functions in an -fno-exceptions libLLVM.so. This reduces .eh_frame_hdr
+ .eh_frame size by 87% for Clang (1.80 descriptors per FDE) and 71%
for GCC (3.85 descriptors per FDE).
https://conf.gnu-tools-cauldron.org/prg26/talk/review/WV7MVNYXJA8XSMKRVBBV9GQJZZ3LW9KT
* AArch64 (Shoaib): Implemented a corresponding compact-unwind encoder
for AArch64, used in Android apps.
Crucially, neither of these approaches generates unwind information in
relocatable files.
Given the massive size reductions achieved by these compact unwind
descriptors, I suspect there won't be a use case or remaining need for
.sframe on either AArch64 or x86-64.