| //===------- UnwindInfoManager.cpp - Register unwind info sections --------===// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.h" | |
| #include "llvm/ExecutionEngine/Orc/Shared/Mangler.h" | |
| #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" | |
| #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" | |
| #include "llvm/TargetParser/Host.h" | |
| #include "llvm/TargetParser/Triple.h" | |
| #ifdef __APPLE__ | |
| #include <dlfcn.h> | |
| #endif // __APPLE__ | |
| #define DEBUG_TYPE "orc" | |
| using namespace llvm; | |
| using namespace llvm::orc; | |
| using namespace llvm::orc::shared; | |
| static orc::shared::CWrapperFunctionBuffer | |
| llvm_orc_rt_alt_UnwindInfoManager_register(const char *ArgData, | |
| size_t ArgSize) { | |
| using SPSSig = SPSError(SPSSequence<SPSExecutorAddrRange>, SPSExecutorAddr, | |
| SPSExecutorAddrRange, SPSExecutorAddrRange); | |
| return WrapperFunction<SPSSig>::handle( | |
| ArgData, ArgSize, | |
| [](std::vector<ExecutorAddrRange> CodeRanges, ExecutorAddr DSOBase, | |
| ExecutorAddrRange DWARFRange, | |
| ExecutorAddrRange CompactUnwindRange) { | |
| return UnwindInfoManager::registerSections( | |
| CodeRanges, DSOBase, DWARFRange, CompactUnwindRange); | |
| }) | |
| .release(); | |
| } | |
| static orc::shared::CWrapperFunctionBuffer | |
| llvm_orc_rt_alt_UnwindInfoManager_deregister(const char *ArgData, | |
| size_t ArgSize) { | |
| using SPSSig = SPSError(SPSSequence<SPSExecutorAddrRange>); | |
| return WrapperFunction<SPSSig>::handle( | |
| ArgData, ArgSize, | |
| [](std::vector<ExecutorAddrRange> CodeRanges) { | |
| return UnwindInfoManager::deregisterSections(CodeRanges); | |
| }) | |
| .release(); | |
| } | |
| namespace llvm::orc { | |
| [[maybe_unused]] static const char *AddFnName = | |
| "__unw_add_find_dynamic_unwind_sections"; | |
| [[maybe_unused]] static const char *RemoveFnName = | |
| "__unw_remove_find_dynamic_unwind_sections"; | |
| static std::unique_ptr<UnwindInfoManager> Instance; | |
| static int (*RemoveFindDynamicUnwindSections)(void *) = nullptr; | |
| UnwindInfoManager::~UnwindInfoManager() { | |
| if (int Err = RemoveFindDynamicUnwindSections((void *)&findSections)) { | |
| (void)Err; // Silence unused variable warning in release builds. | |
| LLVM_DEBUG({ | |
| dbgs() << "Failed call to " << RemoveFnName << ": error = " << Err | |
| << "\n"; | |
| }); | |
| (void)Err; | |
| } | |
| } | |
| bool UnwindInfoManager::TryEnable() { | |
| #ifdef __APPLE__ | |
| static std::mutex M; | |
| std::lock_guard<std::mutex> Lock(M); | |
| if (Instance) | |
| return true; | |
| auto AddFn = (int (*)(void *))dlsym(RTLD_DEFAULT, AddFnName); | |
| if (!AddFn) | |
| return false; | |
| auto RemoveFn = (int (*)(void *))dlsym(RTLD_DEFAULT, RemoveFnName); | |
| if (!RemoveFn) | |
| return false; | |
| Instance.reset(new UnwindInfoManager()); | |
| if (auto Err = AddFn((void *)&findSections)) { | |
| (void)Err; // Silence unused variable warning in release builds. | |
| LLVM_DEBUG({ | |
| dbgs() << "Failed call to " << AddFnName << ": error = " << Err << "\n"; | |
| }); | |
| Instance = nullptr; | |
| return false; | |
| } | |
| RemoveFindDynamicUnwindSections = RemoveFn; | |
| return true; | |
| #else | |
| return false; | |
| #endif // __APPLE__ | |
| } | |
| void UnwindInfoManager::addBootstrapSymbols(StringMap<ExecutorAddr> &M) { | |
| Mangler Mangle{Triple(sys::getProcessTriple())}; | |
| // Provide the symbols for the StandaloneMachOUnwindInfoRegistrar SPS | |
| // interface in the ORC runtime. | |
| const auto &SNs = rt::orc_rt_MachOUnwindInfoRegistrarSPSSymbols; | |
| M[Mangle.mangledCopy(SNs.RegisterSectionsName)] = | |
| ExecutorAddr::fromPtr(llvm_orc_rt_alt_UnwindInfoManager_register); | |
| M[Mangle.mangledCopy(SNs.DeregisterSectionsName)] = | |
| ExecutorAddr::fromPtr(llvm_orc_rt_alt_UnwindInfoManager_deregister); | |
| } | |
| Error UnwindInfoManager::registerSections( | |
| ArrayRef<orc::ExecutorAddrRange> CodeRanges, orc::ExecutorAddr DSOBase, | |
| orc::ExecutorAddrRange DWARFEHFrame, orc::ExecutorAddrRange CompactUnwind) { | |
| return Instance->registerSectionsImpl(CodeRanges, DSOBase, DWARFEHFrame, | |
| CompactUnwind); | |
| } | |
| Error UnwindInfoManager::deregisterSections( | |
| ArrayRef<orc::ExecutorAddrRange> CodeRanges) { | |
| return Instance->deregisterSectionsImpl(CodeRanges); | |
| } | |
| int UnwindInfoManager::findSectionsImpl(uintptr_t Addr, UnwindSections *Info) { | |
| std::lock_guard<std::mutex> Lock(M); | |
| auto I = UWSecs.upper_bound(Addr); | |
| if (I == UWSecs.begin()) | |
| return 0; | |
| --I; | |
| *Info = I->second; | |
| return 1; | |
| } | |
| int UnwindInfoManager::findSections(uintptr_t Addr, UnwindSections *Info) { | |
| return Instance->findSectionsImpl(Addr, Info); | |
| } | |
| Error UnwindInfoManager::registerSectionsImpl( | |
| ArrayRef<ExecutorAddrRange> CodeRanges, ExecutorAddr DSOBase, | |
| ExecutorAddrRange DWARFEHFrame, ExecutorAddrRange CompactUnwind) { | |
| std::lock_guard<std::mutex> Lock(M); | |
| for (auto &R : CodeRanges) | |
| UWSecs[R.Start.getValue()] = | |
| UnwindSections{static_cast<uintptr_t>(DSOBase.getValue()), | |
| static_cast<uintptr_t>(DWARFEHFrame.Start.getValue()), | |
| static_cast<size_t>(DWARFEHFrame.size()), | |
| static_cast<uintptr_t>(CompactUnwind.Start.getValue()), | |
| static_cast<size_t>(CompactUnwind.size())}; | |
| return Error::success(); | |
| } | |
| Error UnwindInfoManager::deregisterSectionsImpl( | |
| ArrayRef<ExecutorAddrRange> CodeRanges) { | |
| std::lock_guard<std::mutex> Lock(M); | |
| for (auto &R : CodeRanges) { | |
| auto I = UWSecs.find(R.Start.getValue()); | |
| if (I == UWSecs.end()) | |
| return make_error<StringError>( | |
| "No unwind-info sections registered for range " + | |
| formatv("{0:x} - {1:x}", R.Start, R.End), | |
| inconvertibleErrorCode()); | |
| UWSecs.erase(I); | |
| } | |
| return Error::success(); | |
| } | |
| } // namespace llvm::orc |