| 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 | |