[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