[llvm] [orc-rt] Add DWARFEHFrameRegistrar for .eh_frame registration. (PR #226093)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 24 02:57:21 PDT 2026
https://github.com/lhames created https://github.com/llvm/llvm-project/pull/226093
Adds sys::posix::DWARFEHFrameRegistrar, which registers JIT'd .eh_frame sections, and expose it to controllers via the
orc_rt_ci_aa_sps_DWARFEHFrameRegistrar_registerSection and orc_rt_ci_aa_sps_DWARFEHFrameRegistrar_deregisterSection allocation actions.
The interface is added to the controller interface on Linux only; on Darwin, StandaloneMachOUnwindInfoRegistrar is preferred.
>From b0a66b0d28109ba9fb6e7e87f0cf7a2b480f8592 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Thu, 24 Sep 2026 12:33:47 +1000
Subject: [PATCH] [orc-rt] Add DWARFEHFrameRegistrar for .eh_frame
registration.
Adds sys::posix::DWARFEHFrameRegistrar, which registers JIT'd .eh_frame
sections, and expose it to controllers via the
orc_rt_ci_aa_sps_DWARFEHFrameRegistrar_registerSection and
orc_rt_ci_aa_sps_DWARFEHFrameRegistrar_deregisterSection allocation
actions.
The interface is added to the controller interface on Linux only; on
Darwin, StandaloneMachOUnwindInfoRegistrar is preferred.
---
orc-rt/include/CMakeLists.txt | 7 +
.../bedrock/sys/posix/DWARFEHFrameRegistrar.h | 39 ++++++
.../bedrock/sps/DWARFEHFrameRegistrarSPSCI.h | 31 +++++
orc-rt/lib/bedrock/CMakeLists.txt | 2 +
orc-rt/lib/bedrock/sps/AllSPSCI.cpp | 5 +
.../sys/posix/DWARFEHFrameRegistrar.cpp | 128 ++++++++++++++++++
.../posix/sps/DWARFEHFrameRegistrarSPSCI.cpp | 38 ++++++
7 files changed, 250 insertions(+)
create mode 100644 orc-rt/include/orc-rt-internal/bedrock/sys/posix/DWARFEHFrameRegistrar.h
create mode 100644 orc-rt/include/orc-rt/bedrock/sps/DWARFEHFrameRegistrarSPSCI.h
create mode 100644 orc-rt/lib/bedrock/sys/posix/DWARFEHFrameRegistrar.cpp
create mode 100644 orc-rt/lib/bedrock/sys/posix/sps/DWARFEHFrameRegistrarSPSCI.cpp
diff --git a/orc-rt/include/CMakeLists.txt b/orc-rt/include/CMakeLists.txt
index e03b17c931c9e..72069456c5e3b 100644
--- a/orc-rt/include/CMakeLists.txt
+++ b/orc-rt/include/CMakeLists.txt
@@ -59,6 +59,13 @@ set(ORC_RT_HEADERS
orc-rt/support/sps/SimplePackedSerialization.h
)
+# Headers for POSIX-only interfaces, installed only where they're implemented.
+if (APPLE OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ list(APPEND ORC_RT_HEADERS
+ orc-rt/bedrock/sps/DWARFEHFrameRegistrarSPSCI.h
+ )
+endif()
+
# Headers for Darwin-only interfaces, installed only where they're implemented.
if (APPLE)
list(APPEND ORC_RT_HEADERS
diff --git a/orc-rt/include/orc-rt-internal/bedrock/sys/posix/DWARFEHFrameRegistrar.h b/orc-rt/include/orc-rt-internal/bedrock/sys/posix/DWARFEHFrameRegistrar.h
new file mode 100644
index 0000000000000..a6026b264b31d
--- /dev/null
+++ b/orc-rt/include/orc-rt-internal/bedrock/sys/posix/DWARFEHFrameRegistrar.h
@@ -0,0 +1,39 @@
+//===- DWARFEHFrameRegistrar.h - DWARF EH frame registration ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// DWARF EH frame registration with the process's unwinder.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_INTERNAL_BEDROCK_SYS_POSIX_DWARFEHFRAMEREGISTRAR_H
+#define ORC_RT_INTERNAL_BEDROCK_SYS_POSIX_DWARFEHFRAMEREGISTRAR_H
+
+#include "orc-rt/support/Error.h"
+#include "orc-rt/support/span.h"
+
+namespace orc_rt::sys::posix {
+
+/// Registers and deregisters JIT'd .eh_frame sections with the process's
+/// unwinder (libgcc or libunwind), so that exceptions can be thrown through
+/// JIT'd code.
+class DWARFEHFrameRegistrar {
+public:
+ /// Register the .eh_frame section in EHFrame. Returns an error if the
+ /// section is malformed, in which case nothing is registered.
+ ///
+ /// The section must remain mapped and unmodified until it is deregistered.
+ static Error registerSection(span<const char> EHFrame) noexcept;
+
+ /// Deregister an .eh_frame section previously registered with
+ /// registerSection.
+ static Error deregisterSection(span<const char> EHFrame) noexcept;
+};
+
+} // namespace orc_rt::sys::posix
+
+#endif // ORC_RT_INTERNAL_BEDROCK_SYS_POSIX_DWARFEHFRAMEREGISTRAR_H
diff --git a/orc-rt/include/orc-rt/bedrock/sps/DWARFEHFrameRegistrarSPSCI.h b/orc-rt/include/orc-rt/bedrock/sps/DWARFEHFrameRegistrarSPSCI.h
new file mode 100644
index 0000000000000..27ca942b633a9
--- /dev/null
+++ b/orc-rt/include/orc-rt/bedrock/sps/DWARFEHFrameRegistrarSPSCI.h
@@ -0,0 +1,31 @@
+//===------------- DWARFEHFrameRegistrarSPSCI.h -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// SPS Controller Interface registration for DWARFEHFrameRegistrar.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_BEDROCK_SPS_DWARFEHFRAMEREGISTRARSPSCI_H
+#define ORC_RT_BEDROCK_SPS_DWARFEHFRAMEREGISTRARSPSCI_H
+
+#include "orc-rt/bedrock/SimpleSymbolTable.h"
+#include "orc-rt/support/sps/SPSAllocAction.h"
+
+ORC_RT_SPS_ALLOC_ACTION_DECL(
+ orc_rt_ci_aa_sps_DWARFEHFrameRegistrar_registerSection)
+ORC_RT_SPS_ALLOC_ACTION_DECL(
+ orc_rt_ci_aa_sps_DWARFEHFrameRegistrar_deregisterSection)
+
+namespace orc_rt::sps_ci {
+
+/// Add the DWARFEHFrameRegistrar SPS interface to the controller interface.
+Error addDWARFEHFrameRegistrar(SimpleSymbolTable &ST);
+
+} // namespace orc_rt::sps_ci
+
+#endif // ORC_RT_BEDROCK_SPS_DWARFEHFRAMEREGISTRARSPSCI_H
diff --git a/orc-rt/lib/bedrock/CMakeLists.txt b/orc-rt/lib/bedrock/CMakeLists.txt
index 20c1c49e98694..207900d0fa468 100644
--- a/orc-rt/lib/bedrock/CMakeLists.txt
+++ b/orc-rt/lib/bedrock/CMakeLists.txt
@@ -38,11 +38,13 @@ set(ORC_RT_BEDROCK_SOURCES
# copy of them.
set(ORC_RT_BEDROCK_POSIX_SOURCES
+ sys/posix/DWARFEHFrameRegistrar.cpp
sys/posix/DynamicLibrary.cpp
sys/posix/Memory.cpp
sys/posix/PageSize.cpp
sys/posix/SocketConnector.cpp
sys/posix/SocketHandle.cpp
+ sys/posix/sps/DWARFEHFrameRegistrarSPSCI.cpp
sys/posix/sps/SimpleRemoteCAOverSocket.cpp
)
diff --git a/orc-rt/lib/bedrock/sps/AllSPSCI.cpp b/orc-rt/lib/bedrock/sps/AllSPSCI.cpp
index 5dc1fb32f5391..9a9b43ad62e87 100644
--- a/orc-rt/lib/bedrock/sps/AllSPSCI.cpp
+++ b/orc-rt/lib/bedrock/sps/AllSPSCI.cpp
@@ -12,6 +12,7 @@
#include "orc-rt/bedrock/sps/AllSPSCI.h"
#include "orc-rt/bedrock/sps/CallSPSCI.h"
+#include "orc-rt/bedrock/sps/DWARFEHFrameRegistrarSPSCI.h"
#include "orc-rt/bedrock/sps/GDBJITRegistrarSPSCI.h"
#include "orc-rt/bedrock/sps/MemoryAccessSPSCI.h"
#include "orc-rt/bedrock/sps/NativeDylibManagerSPSCI.h"
@@ -29,7 +30,11 @@ Error addAll(SimpleSymbolTable &ST) {
addNativeDylibManager,
addSimpleNativeMemoryMap,
#if defined(__APPLE__)
+ // DWARFEHFrameRegistrar is also built on Darwin, but
+ // StandaloneMachOUnwindInfoRegistrar is preferred there.
addStandaloneMachOUnwindInfoRegistrar,
+#elif defined(__linux__)
+ addDWARFEHFrameRegistrar,
#endif
};
diff --git a/orc-rt/lib/bedrock/sys/posix/DWARFEHFrameRegistrar.cpp b/orc-rt/lib/bedrock/sys/posix/DWARFEHFrameRegistrar.cpp
new file mode 100644
index 0000000000000..efa91106429f6
--- /dev/null
+++ b/orc-rt/lib/bedrock/sys/posix/DWARFEHFrameRegistrar.cpp
@@ -0,0 +1,128 @@
+//===- DWARFEHFrameRegistrar.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// DWARF eh-frame registration support.
+//
+// This requires an Itanium-style unwinder providing __register_frame, not
+// POSIX as such: it lives in sys/posix/ because that's the set of supported
+// targets that have one.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt-internal/bedrock/sys/posix/DWARFEHFrameRegistrar.h"
+#include "orc-rt-internal/support/Endian.h"
+#include "orc-rt/support/Compiler.h"
+
+#include <cstdint>
+
+// libgcc: takes the start of a zero-terminated .eh_frame section.
+extern "C" void __register_frame(const void *EHFrame) ORC_RT_WEAK_IMPORT;
+extern "C" void __deregister_frame(const void *EHFrame) ORC_RT_WEAK_IMPORT;
+
+// libunwind: takes a single FDE. (libunwind's __register_frame takes an FDE
+// too, and forwards to these.)
+extern "C" void __unw_add_dynamic_fde(uintptr_t FDE) ORC_RT_WEAK_IMPORT;
+extern "C" void __unw_remove_dynamic_fde(uintptr_t FDE) ORC_RT_WEAK_IMPORT;
+
+using namespace orc_rt;
+
+namespace {
+
+// The unwinder is chosen when the client links, not when orc-rt is built, so
+// detect it at runtime. We use libunwind's own FDE API rather than calling
+// __register_frame per FDE: if both unwinders are loaded, __register_frame may
+// bind to libgcc's, which would misread an FDE as a section.
+bool haveLibunwind() noexcept {
+ return __unw_add_dynamic_fde && __unw_remove_dynamic_fde;
+}
+
+/// Call HandleFDE on the start of each FDE in EHFrame, stopping at a
+/// zero-length terminator record if there is one. Returns an error if any
+/// record overruns EHFrame, or if RequireTerminator is set and there's no
+/// terminator.
+template <typename HandleFDEFn>
+Error walkEHFrameSection(span<const char> EHFrame, bool RequireTerminator,
+ HandleFDEFn &&HandleFDE) noexcept {
+ const char *P = EHFrame.data();
+ const char *End = P + EHFrame.size();
+
+ auto MakeMalformedError = [&](const char *Problem) {
+ return make_error<StringError>(
+ std::string("Malformed .eh_frame section: ") + Problem);
+ };
+
+ while (P != End) {
+ if (End - P < 4)
+ return MakeMalformedError("truncated record length");
+ uint64_t Length = endian_read<uint32_t>(P, endian::native);
+ if (Length == 0)
+ return Error::success(); // Terminator.
+
+ size_t LengthFieldSize = 4;
+ if (Length == 0xffffffff) {
+ if (End - P < 12)
+ return MakeMalformedError("truncated extended record length");
+ Length = endian_read<uint64_t>(P + 4, endian::native);
+ LengthFieldSize = 12;
+ }
+
+ // Every record starts with a 4-byte CIE id (for CIEs) or CIE pointer (for
+ // FDEs).
+ size_t Remaining = End - P - LengthFieldSize;
+ if (Length < 4 || Length > Remaining)
+ return MakeMalformedError("record overruns section");
+
+ if (endian_read<uint32_t>(P + LengthFieldSize, endian::native) != 0)
+ HandleFDE(P);
+
+ P += LengthFieldSize + Length;
+ }
+
+ if (RequireTerminator)
+ return MakeMalformedError("missing terminator");
+ return Error::success();
+}
+
+} // namespace
+
+namespace orc_rt::sys::posix {
+
+Error DWARFEHFrameRegistrar::registerSection(
+ span<const char> EHFrame) noexcept {
+ if (haveLibunwind()) {
+ // Validate before registering anything, so that a malformed section isn't
+ // left partially registered.
+ if (auto Err = walkEHFrameSection(EHFrame, false, [](const char *) {}))
+ return Err;
+ return walkEHFrameSection(EHFrame, false, [](const char *FDE) {
+ __unw_add_dynamic_fde(reinterpret_cast<uintptr_t>(FDE));
+ });
+ }
+
+ if (ORC_RT_UNLIKELY(!__register_frame))
+ return make_error<StringError>("__register_frame not found");
+
+ __register_frame(EHFrame.data());
+ return Error::success();
+}
+
+Error DWARFEHFrameRegistrar::deregisterSection(
+ span<const char> EHFrame) noexcept {
+ if (haveLibunwind())
+ return walkEHFrameSection(EHFrame, false, [](const char *FDE) {
+ __unw_remove_dynamic_fde(reinterpret_cast<uintptr_t>(FDE));
+ });
+
+ if (ORC_RT_UNLIKELY(!__deregister_frame))
+ return make_error<StringError>("__deregister_frame not found");
+
+ __deregister_frame(EHFrame.data());
+ return Error::success();
+}
+
+} // namespace orc_rt::sys::posix
diff --git a/orc-rt/lib/bedrock/sys/posix/sps/DWARFEHFrameRegistrarSPSCI.cpp b/orc-rt/lib/bedrock/sys/posix/sps/DWARFEHFrameRegistrarSPSCI.cpp
new file mode 100644
index 0000000000000..63a0be2202830
--- /dev/null
+++ b/orc-rt/lib/bedrock/sys/posix/sps/DWARFEHFrameRegistrarSPSCI.cpp
@@ -0,0 +1,38 @@
+//===- DWARFEHFrameRegistrarSPSCI.cpp -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// SPS Controller Interface implementation for DWARFEHFrameRegistrar.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt/bedrock/sps/DWARFEHFrameRegistrarSPSCI.h"
+#include "orc-rt-internal/bedrock/sys/posix/DWARFEHFrameRegistrar.h"
+
+namespace orc_rt::sps_ci {
+
+ORC_RT_SPS_ALLOC_ACTION_IMPL(
+ orc_rt_ci_aa_sps_DWARFEHFrameRegistrar_registerSection,
+ (SPSExecutorAddrRange), &sys::posix::DWARFEHFrameRegistrar::registerSection)
+
+ORC_RT_SPS_ALLOC_ACTION_IMPL(
+ orc_rt_ci_aa_sps_DWARFEHFrameRegistrar_deregisterSection,
+ (SPSExecutorAddrRange),
+ &sys::posix::DWARFEHFrameRegistrar::deregisterSection)
+
+static std::pair<SymbolNameSpec, const void *>
+ orc_rt_ci_DWARFEHFrameRegistrar_sps_interface[] = {
+ ORC_RT_SYMTAB_C_PAIR(
+ orc_rt_ci_aa_sps_DWARFEHFrameRegistrar_registerSection),
+ ORC_RT_SYMTAB_C_PAIR(
+ orc_rt_ci_aa_sps_DWARFEHFrameRegistrar_deregisterSection)};
+
+Error addDWARFEHFrameRegistrar(SimpleSymbolTable &ST) {
+ return ST.addUnique(orc_rt_ci_DWARFEHFrameRegistrar_sps_interface);
+}
+
+} // namespace orc_rt::sps_ci
More information about the llvm-commits
mailing list