1//===------- UnwindInfoManager.cpp - Register unwind info sections --------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.h"
10#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
11#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
12
13#ifdef __APPLE__
14#include <dlfcn.h>
15#endif // __APPLE__
16
17#define DEBUG_TYPE "orc"
18
19using namespace llvm;
20using namespace llvm::orc;
21using namespace llvm::orc::shared;
22
23static orc::shared::CWrapperFunctionBuffer
24llvm_orc_rt_alt_UnwindInfoManager_register(const char *ArgData,
25 size_t ArgSize) {
26 using SPSSig = SPSError(SPSSequence<SPSExecutorAddrRange>, SPSExecutorAddr,
27 SPSExecutorAddrRange, SPSExecutorAddrRange);
28
29 return WrapperFunction<SPSSig>::handle(
30 ArgData, ArgSize,
31 Handler: [](std::vector<ExecutorAddrRange> CodeRanges, ExecutorAddr DSOBase,
32 ExecutorAddrRange DWARFRange,
33 ExecutorAddrRange CompactUnwindRange) {
34 return UnwindInfoManager::registerSections(
35 CodeRanges, DSOBase, DWARFEHFrame: DWARFRange, CompactUnwind: CompactUnwindRange);
36 })
37 .release();
38}
39
40static orc::shared::CWrapperFunctionBuffer
41llvm_orc_rt_alt_UnwindInfoManager_deregister(const char *ArgData,
42 size_t ArgSize) {
43 using SPSSig = SPSError(SPSSequence<SPSExecutorAddrRange>);
44
45 return WrapperFunction<SPSSig>::handle(
46 ArgData, ArgSize,
47 Handler: [](std::vector<ExecutorAddrRange> CodeRanges) {
48 return UnwindInfoManager::deregisterSections(CodeRanges);
49 })
50 .release();
51}
52
53namespace llvm::orc {
54
55[[maybe_unused]] static const char *AddFnName =
56 "__unw_add_find_dynamic_unwind_sections";
57[[maybe_unused]] static const char *RemoveFnName =
58 "__unw_remove_find_dynamic_unwind_sections";
59static std::unique_ptr<UnwindInfoManager> Instance;
60static int (*RemoveFindDynamicUnwindSections)(void *) = nullptr;
61
62UnwindInfoManager::~UnwindInfoManager() {
63 if (int Err = RemoveFindDynamicUnwindSections((void *)&findSections)) {
64 (void)Err; // Silence unused variable warning in release builds.
65 LLVM_DEBUG({
66 dbgs() << "Failed call to " << RemoveFnName << ": error = " << Err
67 << "\n";
68 });
69 (void)Err;
70 }
71}
72
73bool UnwindInfoManager::TryEnable() {
74#ifdef __APPLE__
75 static std::mutex M;
76 std::lock_guard<std::mutex> Lock(M);
77
78 if (Instance)
79 return true;
80
81 auto AddFn = (int (*)(void *))dlsym(RTLD_DEFAULT, AddFnName);
82 if (!AddFn)
83 return false;
84
85 auto RemoveFn = (int (*)(void *))dlsym(RTLD_DEFAULT, RemoveFnName);
86 if (!RemoveFn)
87 return false;
88
89 Instance.reset(new UnwindInfoManager());
90
91 if (auto Err = AddFn((void *)&findSections)) {
92 (void)Err; // Silence unused variable warning in release builds.
93 LLVM_DEBUG({
94 dbgs() << "Failed call to " << AddFnName << ": error = " << Err << "\n";
95 });
96 Instance = nullptr;
97 return false;
98 }
99
100 RemoveFindDynamicUnwindSections = RemoveFn;
101 return true;
102
103#else
104 return false;
105#endif // __APPLE__
106}
107
108void UnwindInfoManager::addBootstrapSymbols(StringMap<ExecutorAddr> &M) {
109 M[rt_alt::UnwindInfoManagerRegisterActionName] =
110 ExecutorAddr::fromPtr(Ptr: llvm_orc_rt_alt_UnwindInfoManager_register);
111 M[rt_alt::UnwindInfoManagerDeregisterActionName] =
112 ExecutorAddr::fromPtr(Ptr: llvm_orc_rt_alt_UnwindInfoManager_deregister);
113
114 {
115 // Also provide symbols defined by StandaloneMachOUnwindInfoRegistrar
116 // in the new ORC runtime.
117 const auto &SNs = rt::orc_rt_MachOUnwindInfoRegistrarSPSSymbols;
118 M[SNs.RegisterSectionsName] =
119 ExecutorAddr::fromPtr(Ptr: llvm_orc_rt_alt_UnwindInfoManager_register);
120 M[SNs.DeregisterSectionsName] =
121 ExecutorAddr::fromPtr(Ptr: llvm_orc_rt_alt_UnwindInfoManager_deregister);
122 }
123}
124
125Error UnwindInfoManager::registerSections(
126 ArrayRef<orc::ExecutorAddrRange> CodeRanges, orc::ExecutorAddr DSOBase,
127 orc::ExecutorAddrRange DWARFEHFrame, orc::ExecutorAddrRange CompactUnwind) {
128 return Instance->registerSectionsImpl(CodeRanges, DSOBase, DWARFEHFrame,
129 CompactUnwind);
130}
131
132Error UnwindInfoManager::deregisterSections(
133 ArrayRef<orc::ExecutorAddrRange> CodeRanges) {
134 return Instance->deregisterSectionsImpl(CodeRanges);
135}
136
137int UnwindInfoManager::findSectionsImpl(uintptr_t Addr, UnwindSections *Info) {
138 std::lock_guard<std::mutex> Lock(M);
139 auto I = UWSecs.upper_bound(x: Addr);
140 if (I == UWSecs.begin())
141 return 0;
142 --I;
143 *Info = I->second;
144 return 1;
145}
146
147int UnwindInfoManager::findSections(uintptr_t Addr, UnwindSections *Info) {
148 return Instance->findSectionsImpl(Addr, Info);
149}
150
151Error UnwindInfoManager::registerSectionsImpl(
152 ArrayRef<ExecutorAddrRange> CodeRanges, ExecutorAddr DSOBase,
153 ExecutorAddrRange DWARFEHFrame, ExecutorAddrRange CompactUnwind) {
154 std::lock_guard<std::mutex> Lock(M);
155 for (auto &R : CodeRanges)
156 UWSecs[R.Start.getValue()] =
157 UnwindSections{.dso_base: static_cast<uintptr_t>(DSOBase.getValue()),
158 .dwarf_section: static_cast<uintptr_t>(DWARFEHFrame.Start.getValue()),
159 .dwarf_section_length: static_cast<size_t>(DWARFEHFrame.size()),
160 .compact_unwind_section: static_cast<uintptr_t>(CompactUnwind.Start.getValue()),
161 .compact_unwind_section_length: static_cast<size_t>(CompactUnwind.size())};
162 return Error::success();
163}
164
165Error UnwindInfoManager::deregisterSectionsImpl(
166 ArrayRef<ExecutorAddrRange> CodeRanges) {
167 std::lock_guard<std::mutex> Lock(M);
168 for (auto &R : CodeRanges) {
169 auto I = UWSecs.find(x: R.Start.getValue());
170 if (I == UWSecs.end())
171 return make_error<StringError>(
172 Args: "No unwind-info sections registered for range " +
173 formatv(Fmt: "{0:x} - {1:x}", Vals: R.Start, Vals: R.End),
174 Args: inconvertibleErrorCode());
175 UWSecs.erase(position: I);
176 }
177 return Error::success();
178}
179
180} // namespace llvm::orc
181