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