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 | |
19 | using namespace llvm; |
20 | using namespace llvm::orc; |
21 | using namespace llvm::orc::shared; |
22 | |
23 | static orc::shared::CWrapperFunctionResult |
24 | llvm_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 | |
40 | static orc::shared::CWrapperFunctionResult |
41 | llvm_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 | |
53 | namespace 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" ; |
59 | static std::unique_ptr<UnwindInfoManager> Instance; |
60 | static int (*RemoveFindDynamicUnwindSections)(void *) = nullptr; |
61 | |
62 | UnwindInfoManager::~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 | |
73 | bool 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 | |
108 | void 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 | Error UnwindInfoManager::registerSections( |
116 | ArrayRef<orc::ExecutorAddrRange> CodeRanges, orc::ExecutorAddr DSOBase, |
117 | orc::ExecutorAddrRange DWARFEHFrame, orc::ExecutorAddrRange CompactUnwind) { |
118 | return Instance->registerSectionsImpl(CodeRanges, DSOBase, DWARFEHFrame, |
119 | CompactUnwind); |
120 | } |
121 | |
122 | Error UnwindInfoManager::deregisterSections( |
123 | ArrayRef<orc::ExecutorAddrRange> CodeRanges) { |
124 | return Instance->deregisterSectionsImpl(CodeRanges); |
125 | } |
126 | |
127 | int UnwindInfoManager::findSectionsImpl(uintptr_t Addr, UnwindSections *Info) { |
128 | std::lock_guard<std::mutex> Lock(M); |
129 | auto I = UWSecs.upper_bound(x: Addr); |
130 | if (I == UWSecs.begin()) |
131 | return 0; |
132 | --I; |
133 | *Info = I->second; |
134 | return 1; |
135 | } |
136 | |
137 | int UnwindInfoManager::findSections(uintptr_t Addr, UnwindSections *Info) { |
138 | return Instance->findSectionsImpl(Addr, Info); |
139 | } |
140 | |
141 | Error UnwindInfoManager::registerSectionsImpl( |
142 | ArrayRef<ExecutorAddrRange> CodeRanges, ExecutorAddr DSOBase, |
143 | ExecutorAddrRange DWARFEHFrame, ExecutorAddrRange CompactUnwind) { |
144 | std::lock_guard<std::mutex> Lock(M); |
145 | for (auto &R : CodeRanges) |
146 | UWSecs[R.Start.getValue()] = |
147 | UnwindSections{.dso_base: static_cast<uintptr_t>(DSOBase.getValue()), |
148 | .dwarf_section: static_cast<uintptr_t>(DWARFEHFrame.Start.getValue()), |
149 | .dwarf_section_length: static_cast<size_t>(DWARFEHFrame.size()), |
150 | .compact_unwind_section: static_cast<uintptr_t>(CompactUnwind.Start.getValue()), |
151 | .compact_unwind_section_length: static_cast<size_t>(CompactUnwind.size())}; |
152 | return Error::success(); |
153 | } |
154 | |
155 | Error UnwindInfoManager::deregisterSectionsImpl( |
156 | ArrayRef<ExecutorAddrRange> CodeRanges) { |
157 | std::lock_guard<std::mutex> Lock(M); |
158 | for (auto &R : CodeRanges) { |
159 | auto I = UWSecs.find(x: R.Start.getValue()); |
160 | if (I == UWSecs.end()) |
161 | return make_error<StringError>( |
162 | Args: "No unwind-info sections registered for range " + |
163 | formatv(Fmt: "{0:x} - {1:x}" , Vals: R.Start, Vals: R.End), |
164 | Args: inconvertibleErrorCode()); |
165 | UWSecs.erase(position: I); |
166 | } |
167 | return Error::success(); |
168 | } |
169 | |
170 | } // namespace llvm::orc |
171 | |