blob: e331bad84200864e250fd3a018dd7fd6d805efe7 [file] [log] [blame]
//===--------- RegisterEHFrames.cpp - Register EH frame 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/RegisterEHFrames.h"
#include "llvm/Config/config.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/FormatVariadic.h"
#define DEBUG_TYPE "orc"
using namespace llvm;
using namespace llvm::orc;
using namespace llvm::orc::shared;
namespace llvm {
namespace orc {
#if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) && \
!defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
extern "C" void __register_frame(const void *);
extern "C" void __deregister_frame(const void *);
Error registerFrameWrapper(const void *P) {
__register_frame(P);
return Error::success();
}
Error deregisterFrameWrapper(const void *P) {
__deregister_frame(P);
return Error::success();
}
#else
// The building compiler does not have __(de)register_frame but
// it may be found at runtime in a dynamically-loaded library.
// For example, this happens when building LLVM with Visual C++
// but using the MingW runtime.
static Error registerFrameWrapper(const void *P) {
static void((*RegisterFrame)(const void *)) = 0;
if (!RegisterFrame)
*(void **)&RegisterFrame =
llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
if (RegisterFrame) {
RegisterFrame(P);
return Error::success();
}
return make_error<StringError>("could not register eh-frame: "
"__register_frame function not found",
inconvertibleErrorCode());
}
static Error deregisterFrameWrapper(const void *P) {
static void((*DeregisterFrame)(const void *)) = 0;
if (!DeregisterFrame)
*(void **)&DeregisterFrame =
llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
"__deregister_frame");
if (DeregisterFrame) {
DeregisterFrame(P);
return Error::success();
}
return make_error<StringError>("could not deregister eh-frame: "
"__deregister_frame function not found",
inconvertibleErrorCode());
}
#endif
#if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
template <typename HandleFDEFn>
Error walkLibunwindEHFrameSection(const char *const SectionStart,
size_t SectionSize, HandleFDEFn HandleFDE) {
const char *CurCFIRecord = SectionStart;
const char *End = SectionStart + SectionSize;
uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
while (CurCFIRecord != End && Size != 0) {
const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
if (Size == 0xffffffff)
Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
else
Size += 4;
uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
LLVM_DEBUG({
dbgs() << "Registering eh-frame section:\n";
dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
<< (void *)CurCFIRecord << ": [";
for (unsigned I = 0; I < Size; ++I)
dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
dbgs() << " ]\n";
});
if (Offset != 0)
if (auto Err = HandleFDE(CurCFIRecord))
return Err;
CurCFIRecord += Size;
Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
}
return Error::success();
}
#endif // HAVE_UNW_ADD_DYNAMIC_FDE || __APPLE__
Error registerEHFrameSection(const void *EHFrameSectionAddr,
size_t EHFrameSectionSize) {
/* libgcc and libunwind __register_frame behave differently. We use the
* presence of __unw_add_dynamic_fde to detect libunwind. */
#if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
// With libunwind, __register_frame has to be called for each FDE entry.
return walkLibunwindEHFrameSection(
static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
registerFrameWrapper);
#else
// With libgcc, __register_frame takes a single argument:
// a pointer to the start of the .eh_frame section.
// How can it find the end? Because crtendS.o is linked
// in and it has an .eh_frame section with four zero chars.
return registerFrameWrapper(EHFrameSectionAddr);
#endif
}
Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
size_t EHFrameSectionSize) {
#if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
return walkLibunwindEHFrameSection(
static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
deregisterFrameWrapper);
#else
return deregisterFrameWrapper(EHFrameSectionAddr);
#endif
}
} // end namespace orc
} // end namespace llvm
extern "C" llvm::orc::shared::CWrapperFunctionResult
llvm_orc_registerEHFrameSectionCustomDirectWrapper(
const char *EHFrameSectionAddr, uint64_t Size) {
if (auto Err = registerEHFrameSection(EHFrameSectionAddr, Size))
return WrapperFunctionResult::createOutOfBandError(toString(std::move(Err)))
.release();
return llvm::orc::shared::CWrapperFunctionResult();
}
extern "C" llvm::orc::shared::CWrapperFunctionResult
llvm_orc_deregisterEHFrameSectionCustomDirectWrapper(
const char *EHFrameSectionAddr, uint64_t Size) {
if (auto Err = deregisterEHFrameSection(EHFrameSectionAddr, Size))
return WrapperFunctionResult::createOutOfBandError(toString(std::move(Err)))
.release();
return llvm::orc::shared::CWrapperFunctionResult();
}
static Error registerEHFrameWrapper(ExecutorAddr Addr, uint64_t Size) {
return llvm::orc::registerEHFrameSection(Addr.toPtr<const void *>(), Size);
}
static Error deregisterEHFrameWrapper(ExecutorAddr Addr, uint64_t Size) {
return llvm::orc::deregisterEHFrameSection(Addr.toPtr<const void *>(), Size);
}
extern "C" orc::shared::CWrapperFunctionResult
llvm_orc_registerEHFrameSectionWrapper(const char *Data, uint64_t Size) {
return WrapperFunction<SPSError(SPSExecutorAddr, uint64_t)>::handle(
Data, Size, registerEHFrameWrapper)
.release();
}
extern "C" orc::shared::CWrapperFunctionResult
llvm_orc_deregisterEHFrameSectionWrapper(const char *Data, uint64_t Size) {
return WrapperFunction<SPSError(SPSExecutorAddr, uint64_t)>::handle(
Data, Size, deregisterEHFrameWrapper)
.release();
}