171 lines
5.6 KiB
C++

//===------- 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/OrcRTBridge.h"
#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.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::CWrapperFunctionResult
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::CWrapperFunctionResult
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) {
M[rt_alt::UnwindInfoManagerRegisterActionName] =
ExecutorAddr::fromPtr(llvm_orc_rt_alt_UnwindInfoManager_register);
M[rt_alt::UnwindInfoManagerDeregisterActionName] =
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