1e8d8bef9SDimitry Andric //===--------- RegisterEHFrames.cpp - Register EH frame sections ----------===// 2e8d8bef9SDimitry Andric // 3*349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric 9e8d8bef9SDimitry Andric #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" 10e8d8bef9SDimitry Andric 11e8d8bef9SDimitry Andric #include "llvm/Config/config.h" 12e8d8bef9SDimitry Andric #include "llvm/ExecutionEngine/JITSymbol.h" 13e8d8bef9SDimitry Andric #include "llvm/Support/BinaryStreamReader.h" 14e8d8bef9SDimitry Andric #include "llvm/Support/Compiler.h" 15e8d8bef9SDimitry Andric #include "llvm/Support/Debug.h" 16e8d8bef9SDimitry Andric #include "llvm/Support/DynamicLibrary.h" 17e8d8bef9SDimitry Andric #include "llvm/Support/raw_ostream.h" 18e8d8bef9SDimitry Andric 19e8d8bef9SDimitry Andric #include "llvm/Support/FormatVariadic.h" 20e8d8bef9SDimitry Andric 21e8d8bef9SDimitry Andric #define DEBUG_TYPE "orc" 22e8d8bef9SDimitry Andric 23e8d8bef9SDimitry Andric using namespace llvm; 24e8d8bef9SDimitry Andric using namespace llvm::orc; 25fe6060f1SDimitry Andric using namespace llvm::orc::shared; 26e8d8bef9SDimitry Andric 27e8d8bef9SDimitry Andric namespace llvm { 28e8d8bef9SDimitry Andric namespace orc { 29e8d8bef9SDimitry Andric 30e8d8bef9SDimitry Andric #if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) && \ 31e8d8bef9SDimitry Andric !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) 32e8d8bef9SDimitry Andric 33e8d8bef9SDimitry Andric extern "C" void __register_frame(const void *); 34e8d8bef9SDimitry Andric extern "C" void __deregister_frame(const void *); 35e8d8bef9SDimitry Andric 36e8d8bef9SDimitry Andric Error registerFrameWrapper(const void *P) { 37e8d8bef9SDimitry Andric __register_frame(P); 38e8d8bef9SDimitry Andric return Error::success(); 39e8d8bef9SDimitry Andric } 40e8d8bef9SDimitry Andric 41e8d8bef9SDimitry Andric Error deregisterFrameWrapper(const void *P) { 42e8d8bef9SDimitry Andric __deregister_frame(P); 43e8d8bef9SDimitry Andric return Error::success(); 44e8d8bef9SDimitry Andric } 45e8d8bef9SDimitry Andric 46e8d8bef9SDimitry Andric #else 47e8d8bef9SDimitry Andric 48e8d8bef9SDimitry Andric // The building compiler does not have __(de)register_frame but 49e8d8bef9SDimitry Andric // it may be found at runtime in a dynamically-loaded library. 50e8d8bef9SDimitry Andric // For example, this happens when building LLVM with Visual C++ 51e8d8bef9SDimitry Andric // but using the MingW runtime. 52e8d8bef9SDimitry Andric static Error registerFrameWrapper(const void *P) { 53e8d8bef9SDimitry Andric static void((*RegisterFrame)(const void *)) = 0; 54e8d8bef9SDimitry Andric 55e8d8bef9SDimitry Andric if (!RegisterFrame) 56e8d8bef9SDimitry Andric *(void **)&RegisterFrame = 57e8d8bef9SDimitry Andric llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame"); 58e8d8bef9SDimitry Andric 59e8d8bef9SDimitry Andric if (RegisterFrame) { 60e8d8bef9SDimitry Andric RegisterFrame(P); 61e8d8bef9SDimitry Andric return Error::success(); 62e8d8bef9SDimitry Andric } 63e8d8bef9SDimitry Andric 64e8d8bef9SDimitry Andric return make_error<StringError>("could not register eh-frame: " 65e8d8bef9SDimitry Andric "__register_frame function not found", 66e8d8bef9SDimitry Andric inconvertibleErrorCode()); 67e8d8bef9SDimitry Andric } 68e8d8bef9SDimitry Andric 69e8d8bef9SDimitry Andric static Error deregisterFrameWrapper(const void *P) { 70e8d8bef9SDimitry Andric static void((*DeregisterFrame)(const void *)) = 0; 71e8d8bef9SDimitry Andric 72e8d8bef9SDimitry Andric if (!DeregisterFrame) 73e8d8bef9SDimitry Andric *(void **)&DeregisterFrame = 74e8d8bef9SDimitry Andric llvm::sys::DynamicLibrary::SearchForAddressOfSymbol( 75e8d8bef9SDimitry Andric "__deregister_frame"); 76e8d8bef9SDimitry Andric 77e8d8bef9SDimitry Andric if (DeregisterFrame) { 78e8d8bef9SDimitry Andric DeregisterFrame(P); 79e8d8bef9SDimitry Andric return Error::success(); 80e8d8bef9SDimitry Andric } 81e8d8bef9SDimitry Andric 82e8d8bef9SDimitry Andric return make_error<StringError>("could not deregister eh-frame: " 83e8d8bef9SDimitry Andric "__deregister_frame function not found", 84e8d8bef9SDimitry Andric inconvertibleErrorCode()); 85e8d8bef9SDimitry Andric } 86e8d8bef9SDimitry Andric #endif 87e8d8bef9SDimitry Andric 88*349cc55cSDimitry Andric #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__) 89e8d8bef9SDimitry Andric 90e8d8bef9SDimitry Andric template <typename HandleFDEFn> 91*349cc55cSDimitry Andric Error walkLibunwindEHFrameSection(const char *const SectionStart, 92e8d8bef9SDimitry Andric size_t SectionSize, HandleFDEFn HandleFDE) { 93e8d8bef9SDimitry Andric const char *CurCFIRecord = SectionStart; 94e8d8bef9SDimitry Andric const char *End = SectionStart + SectionSize; 95e8d8bef9SDimitry Andric uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord); 96e8d8bef9SDimitry Andric 97e8d8bef9SDimitry Andric while (CurCFIRecord != End && Size != 0) { 98e8d8bef9SDimitry Andric const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4); 99e8d8bef9SDimitry Andric if (Size == 0xffffffff) 100e8d8bef9SDimitry Andric Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12; 101e8d8bef9SDimitry Andric else 102e8d8bef9SDimitry Andric Size += 4; 103e8d8bef9SDimitry Andric uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField); 104e8d8bef9SDimitry Andric 105e8d8bef9SDimitry Andric LLVM_DEBUG({ 106e8d8bef9SDimitry Andric dbgs() << "Registering eh-frame section:\n"; 107e8d8bef9SDimitry Andric dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @" 108e8d8bef9SDimitry Andric << (void *)CurCFIRecord << ": ["; 109e8d8bef9SDimitry Andric for (unsigned I = 0; I < Size; ++I) 110e8d8bef9SDimitry Andric dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I)); 111e8d8bef9SDimitry Andric dbgs() << " ]\n"; 112e8d8bef9SDimitry Andric }); 113e8d8bef9SDimitry Andric 114e8d8bef9SDimitry Andric if (Offset != 0) 115e8d8bef9SDimitry Andric if (auto Err = HandleFDE(CurCFIRecord)) 116e8d8bef9SDimitry Andric return Err; 117e8d8bef9SDimitry Andric 118e8d8bef9SDimitry Andric CurCFIRecord += Size; 119e8d8bef9SDimitry Andric 120e8d8bef9SDimitry Andric Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord); 121e8d8bef9SDimitry Andric } 122e8d8bef9SDimitry Andric 123e8d8bef9SDimitry Andric return Error::success(); 124e8d8bef9SDimitry Andric } 125e8d8bef9SDimitry Andric 126*349cc55cSDimitry Andric #endif // HAVE_UNW_ADD_DYNAMIC_FDE || __APPLE__ 127e8d8bef9SDimitry Andric 128e8d8bef9SDimitry Andric Error registerEHFrameSection(const void *EHFrameSectionAddr, 129e8d8bef9SDimitry Andric size_t EHFrameSectionSize) { 130*349cc55cSDimitry Andric /* libgcc and libunwind __register_frame behave differently. We use the 131*349cc55cSDimitry Andric * presence of __unw_add_dynamic_fde to detect libunwind. */ 132*349cc55cSDimitry Andric #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__) 133*349cc55cSDimitry Andric // With libunwind, __register_frame has to be called for each FDE entry. 134*349cc55cSDimitry Andric return walkLibunwindEHFrameSection( 135*349cc55cSDimitry Andric static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize, 136*349cc55cSDimitry Andric registerFrameWrapper); 137e8d8bef9SDimitry Andric #else 138*349cc55cSDimitry Andric // With libgcc, __register_frame takes a single argument: 139e8d8bef9SDimitry Andric // a pointer to the start of the .eh_frame section. 140e8d8bef9SDimitry Andric 141e8d8bef9SDimitry Andric // How can it find the end? Because crtendS.o is linked 142e8d8bef9SDimitry Andric // in and it has an .eh_frame section with four zero chars. 143e8d8bef9SDimitry Andric return registerFrameWrapper(EHFrameSectionAddr); 144e8d8bef9SDimitry Andric #endif 145e8d8bef9SDimitry Andric } 146e8d8bef9SDimitry Andric 147e8d8bef9SDimitry Andric Error deregisterEHFrameSection(const void *EHFrameSectionAddr, 148e8d8bef9SDimitry Andric size_t EHFrameSectionSize) { 149*349cc55cSDimitry Andric #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__) 150*349cc55cSDimitry Andric return walkLibunwindEHFrameSection( 151*349cc55cSDimitry Andric static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize, 152*349cc55cSDimitry Andric deregisterFrameWrapper); 153e8d8bef9SDimitry Andric #else 154e8d8bef9SDimitry Andric return deregisterFrameWrapper(EHFrameSectionAddr); 155e8d8bef9SDimitry Andric #endif 156e8d8bef9SDimitry Andric } 157e8d8bef9SDimitry Andric 158e8d8bef9SDimitry Andric } // end namespace orc 159e8d8bef9SDimitry Andric } // end namespace llvm 160e8d8bef9SDimitry Andric 161*349cc55cSDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult 162*349cc55cSDimitry Andric llvm_orc_registerEHFrameSectionCustomDirectWrapper( 163*349cc55cSDimitry Andric const char *EHFrameSectionAddr, uint64_t Size) { 164*349cc55cSDimitry Andric if (auto Err = registerEHFrameSection(EHFrameSectionAddr, Size)) 165*349cc55cSDimitry Andric return WrapperFunctionResult::createOutOfBandError(toString(std::move(Err))) 166*349cc55cSDimitry Andric .release(); 167*349cc55cSDimitry Andric return llvm::orc::shared::CWrapperFunctionResult(); 168fe6060f1SDimitry Andric } 169fe6060f1SDimitry Andric 170*349cc55cSDimitry Andric extern "C" llvm::orc::shared::CWrapperFunctionResult 171*349cc55cSDimitry Andric llvm_orc_deregisterEHFrameSectionCustomDirectWrapper( 172*349cc55cSDimitry Andric const char *EHFrameSectionAddr, uint64_t Size) { 173*349cc55cSDimitry Andric if (auto Err = deregisterEHFrameSection(EHFrameSectionAddr, Size)) 174*349cc55cSDimitry Andric return WrapperFunctionResult::createOutOfBandError(toString(std::move(Err))) 175*349cc55cSDimitry Andric .release(); 176*349cc55cSDimitry Andric return llvm::orc::shared::CWrapperFunctionResult(); 177fe6060f1SDimitry Andric } 178fe6060f1SDimitry Andric 179*349cc55cSDimitry Andric static Error registerEHFrameWrapper(ExecutorAddr Addr, uint64_t Size) { 180*349cc55cSDimitry Andric return llvm::orc::registerEHFrameSection(Addr.toPtr<const void *>(), Size); 181*349cc55cSDimitry Andric } 182*349cc55cSDimitry Andric 183*349cc55cSDimitry Andric static Error deregisterEHFrameWrapper(ExecutorAddr Addr, uint64_t Size) { 184*349cc55cSDimitry Andric return llvm::orc::deregisterEHFrameSection(Addr.toPtr<const void *>(), Size); 185*349cc55cSDimitry Andric } 186*349cc55cSDimitry Andric 187*349cc55cSDimitry Andric extern "C" orc::shared::CWrapperFunctionResult 188fe6060f1SDimitry Andric llvm_orc_registerEHFrameSectionWrapper(const char *Data, uint64_t Size) { 189*349cc55cSDimitry Andric return WrapperFunction<SPSError(SPSExecutorAddr, uint64_t)>::handle( 190fe6060f1SDimitry Andric Data, Size, registerEHFrameWrapper) 191e8d8bef9SDimitry Andric .release(); 192e8d8bef9SDimitry Andric } 193e8d8bef9SDimitry Andric 194*349cc55cSDimitry Andric extern "C" orc::shared::CWrapperFunctionResult 195fe6060f1SDimitry Andric llvm_orc_deregisterEHFrameSectionWrapper(const char *Data, uint64_t Size) { 196*349cc55cSDimitry Andric return WrapperFunction<SPSError(SPSExecutorAddr, uint64_t)>::handle( 197fe6060f1SDimitry Andric Data, Size, deregisterEHFrameWrapper) 198e8d8bef9SDimitry Andric .release(); 199e8d8bef9SDimitry Andric } 200