On Fri, Aug 21, 2026 at 12:53 PM Jens Remus <[email protected]> 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/[email protected]/
>   v10: https://lore.kernel.org/all/[email protected]/
>   v16: 
> https://lore.kernel.org/all/[email protected]/
>
> 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-...@mail.gmail.com/
> [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/[email protected]/
>
>
> 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.

Reply via email to