//===--------- RegisterEHFrames.cpp - Register EH frame sections ----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #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::tpctypes; 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("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("could not deregister eh-frame: " "__deregister_frame function not found", inconvertibleErrorCode()); } #endif #ifdef __APPLE__ template Error walkAppleEHFrameSection(const char *const SectionStart, size_t SectionSize, HandleFDEFn HandleFDE) { const char *CurCFIRecord = SectionStart; const char *End = SectionStart + SectionSize; uint64_t Size = *reinterpret_cast(CurCFIRecord); while (CurCFIRecord != End && Size != 0) { const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4); if (Size == 0xffffffff) Size = *reinterpret_cast(CurCFIRecord + 4) + 12; else Size += 4; uint32_t Offset = *reinterpret_cast(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(CurCFIRecord); } return Error::success(); } #endif // __APPLE__ Error registerEHFrameSection(const void *EHFrameSectionAddr, size_t EHFrameSectionSize) { #ifdef __APPLE__ // On Darwin __register_frame has to be called for each FDE entry. return walkAppleEHFrameSection(static_cast(EHFrameSectionAddr), EHFrameSectionSize, registerFrameWrapper); #else // On Linux __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) { #ifdef __APPLE__ return walkAppleEHFrameSection(static_cast(EHFrameSectionAddr), EHFrameSectionSize, deregisterFrameWrapper); #else return deregisterFrameWrapper(EHFrameSectionAddr); #endif } } // end namespace orc } // end namespace llvm extern "C" CWrapperFunctionResult llvm_orc_registerEHFrameSectionWrapper(uint8_t *Data, uint64_t Size) { if (Size != sizeof(uint64_t) + sizeof(uint64_t)) return WrapperFunctionResult::from( "Invalid arguments to llvm_orc_registerEHFrameSectionWrapper") .release(); uint64_t EHFrameSectionAddr; uint64_t EHFrameSectionSize; { BinaryStreamReader ArgReader(ArrayRef(Data, Size), support::endianness::big); cantFail(ArgReader.readInteger(EHFrameSectionAddr)); cantFail(ArgReader.readInteger(EHFrameSectionSize)); } if (auto Err = registerEHFrameSection( jitTargetAddressToPointer(EHFrameSectionAddr), EHFrameSectionSize)) { auto ErrMsg = toString(std::move(Err)); return WrapperFunctionResult::from(ErrMsg).release(); } return WrapperFunctionResult().release(); } extern "C" CWrapperFunctionResult llvm_orc_deregisterEHFrameSectionWrapper(uint8_t *Data, uint64_t Size) { if (Size != sizeof(uint64_t) + sizeof(uint64_t)) return WrapperFunctionResult::from( "Invalid arguments to llvm_orc_registerEHFrameSectionWrapper") .release(); uint64_t EHFrameSectionAddr; uint64_t EHFrameSectionSize; { BinaryStreamReader ArgReader(ArrayRef(Data, Size), support::endianness::big); cantFail(ArgReader.readInteger(EHFrameSectionAddr)); cantFail(ArgReader.readInteger(EHFrameSectionSize)); } if (auto Err = deregisterEHFrameSection( jitTargetAddressToPointer(EHFrameSectionAddr), EHFrameSectionSize)) { auto ErrMsg = toString(std::move(Err)); return WrapperFunctionResult::from(ErrMsg).release(); } return WrapperFunctionResult().release(); }