Skip to content

Replace libunwind with framehop based library#62395

Draft
gbaraldi wants to merge 2 commits into
masterfrom
gb/framehop-unwinder
Draft

Replace libunwind with framehop based library#62395
gbaraldi wants to merge 2 commits into
masterfrom
gb/framehop-unwinder

Conversation

@gbaraldi

Copy link
Copy Markdown
Member

Libunwind has been very unreliable. Specially on aarch64 platforms, being slow and dropping frames. https://github.com/mstange/framehop is a rust based unwinding library that seems better supported. I tasked the robots to build https://github.com/gbaraldi/framehopunwind. Which exposes a libunwind like C API for us to use. https://github.com/gbaraldi/framehopunwind
This is much faster and more reliable on aarch64 apple on my testing but it needs further checking

gbaraldi and others added 2 commits July 15, 2026 19:01
…P=1)

Adds an async-signal-safe, framehop-backed unwinder for the *backtrace*
path (stacktraces, exceptions, the profiler signal handler), replacing the
local-unwinding use of libunwind that can deadlock in signal handlers
(dl_iterate_phdr / malloc under the loader lock) and is ~3-4x slower.

The unwinder lives in an external crate (gbaraldi/framehopunwind), linked
into libjulia-internal (stackwalk.c) and libjulia-codegen (debuginfo.cpp
register_eh_frames), which share its single loaded instance. It is
installed from the prebuilt LibFramehopUnwind_jll v0.1.2 artifact by
default (bb-install; built in Yggdrasil from the pinned framehopunwind
commit), with a cargo source build behind
USE_BINARYBUILDER_FRAMEHOPUNWIND=0 (git-external, like mmtk_julia).

Opt-in via USE_FRAMEHOP=1; JL_USE_FRAMEHOP is derived for Linux/FreeBSD/macOS
on x86_64/aarch64. When off, the build is byte-for-byte unchanged. libunwind
stays linked (task.c context switching + proc-info lookup still use it). On
macOS bt_context_t is a mach thread state, so registers are extracted via
fh_context_from_thread_state, and the forceDwarf retry is compiled out.

Verified on Linux x86_64 (both the jll artifact and the source build):
Julia's backtrace, stacktraces, and Profile suites pass, backtraces/
exceptions/profiler match libunwind frame-for-frame, framehop is the live
unwinder (no libunwind stepping symbols imported), and backtrace capture
is ~3-4x faster.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Flip the default on so every CI pipeline builds and tests with the
framehop unwinder. Guarded to the supported set (Linux/FreeBSD/Darwin on
x86_64/aarch64, libunwind enabled, non-musl — LibFramehopUnwind_jll has no
musl artifact yet) so other pipelines build unchanged; an explicit
USE_FRAMEHOP=0 still overrides (use for sanitizer pipelines if the
uninstrumented unwinder library proves noisy under TSan/ASan).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant