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