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.
