11d0676b5SLang Hames //===--------- RegisterEHFrames.cpp - Register EH frame sections ----------===// 21d0676b5SLang Hames // 3c874dd53SChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4c874dd53SChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information. 5c874dd53SChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 61d0676b5SLang Hames // 71d0676b5SLang Hames //===----------------------------------------------------------------------===// 81d0676b5SLang Hames 91d0676b5SLang Hames #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" 101d0676b5SLang Hames 1122e44358SLang Hames #include "llvm/Config/config.h" 121d0676b5SLang Hames #include "llvm/Support/Compiler.h" 131d0676b5SLang Hames #include "llvm/Support/DynamicLibrary.h" 141d0676b5SLang Hames #include "llvm/Support/raw_ostream.h" 151d0676b5SLang Hames 161d0676b5SLang Hames #define DEBUG_TYPE "orc" 171d0676b5SLang Hames 181d0676b5SLang Hames using namespace llvm; 191d0676b5SLang Hames using namespace llvm::orc; 204eb9fe2eSLang Hames using namespace llvm::orc::shared; 211d0676b5SLang Hames 221d0676b5SLang Hames namespace llvm { 231d0676b5SLang Hames namespace orc { 241d0676b5SLang Hames 251d0676b5SLang Hames #if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) && \ 261d0676b5SLang Hames !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) 271d0676b5SLang Hames 281d0676b5SLang Hames extern "C" void __register_frame(const void *); 291d0676b5SLang Hames extern "C" void __deregister_frame(const void *); 301d0676b5SLang Hames 311d0676b5SLang Hames Error registerFrameWrapper(const void *P) { 321d0676b5SLang Hames __register_frame(P); 331d0676b5SLang Hames return Error::success(); 341d0676b5SLang Hames } 351d0676b5SLang Hames 361d0676b5SLang Hames Error deregisterFrameWrapper(const void *P) { 371d0676b5SLang Hames __deregister_frame(P); 381d0676b5SLang Hames return Error::success(); 391d0676b5SLang Hames } 401d0676b5SLang Hames 411d0676b5SLang Hames #else 421d0676b5SLang Hames 431d0676b5SLang Hames // The building compiler does not have __(de)register_frame but 441d0676b5SLang Hames // it may be found at runtime in a dynamically-loaded library. 451d0676b5SLang Hames // For example, this happens when building LLVM with Visual C++ 461d0676b5SLang Hames // but using the MingW runtime. 471d0676b5SLang Hames static Error registerFrameWrapper(const void *P) { 481d0676b5SLang Hames static void((*RegisterFrame)(const void *)) = 0; 491d0676b5SLang Hames 501d0676b5SLang Hames if (!RegisterFrame) 511d0676b5SLang Hames *(void **)&RegisterFrame = 521d0676b5SLang Hames llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame"); 531d0676b5SLang Hames 541d0676b5SLang Hames if (RegisterFrame) { 551d0676b5SLang Hames RegisterFrame(P); 561d0676b5SLang Hames return Error::success(); 571d0676b5SLang Hames } 581d0676b5SLang Hames 591d0676b5SLang Hames return make_error<StringError>("could not register eh-frame: " 601d0676b5SLang Hames "__register_frame function not found", 611d0676b5SLang Hames inconvertibleErrorCode()); 621d0676b5SLang Hames } 631d0676b5SLang Hames 641d0676b5SLang Hames static Error deregisterFrameWrapper(const void *P) { 651d0676b5SLang Hames static void((*DeregisterFrame)(const void *)) = 0; 661d0676b5SLang Hames 671d0676b5SLang Hames if (!DeregisterFrame) 681d0676b5SLang Hames *(void **)&DeregisterFrame = 691d0676b5SLang Hames llvm::sys::DynamicLibrary::SearchForAddressOfSymbol( 701d0676b5SLang Hames "__deregister_frame"); 711d0676b5SLang Hames 721d0676b5SLang Hames if (DeregisterFrame) { 731d0676b5SLang Hames DeregisterFrame(P); 741d0676b5SLang Hames return Error::success(); 751d0676b5SLang Hames } 761d0676b5SLang Hames 771d0676b5SLang Hames return make_error<StringError>("could not deregister eh-frame: " 781d0676b5SLang Hames "__deregister_frame function not found", 791d0676b5SLang Hames inconvertibleErrorCode()); 801d0676b5SLang Hames } 811d0676b5SLang Hames #endif 821d0676b5SLang Hames 83d898693fSAzharuddin Mohammed #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__) 841d0676b5SLang Hames 851d0676b5SLang Hames template <typename HandleFDEFn> 8695733438SHarald van Dijk Error walkLibunwindEHFrameSection(const char *const SectionStart, 871d0676b5SLang Hames size_t SectionSize, HandleFDEFn HandleFDE) { 881d0676b5SLang Hames const char *CurCFIRecord = SectionStart; 891d0676b5SLang Hames const char *End = SectionStart + SectionSize; 901d0676b5SLang Hames uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord); 911d0676b5SLang Hames 921d0676b5SLang Hames while (CurCFIRecord != End && Size != 0) { 931d0676b5SLang Hames const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4); 941d0676b5SLang Hames if (Size == 0xffffffff) 951d0676b5SLang Hames Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12; 961d0676b5SLang Hames else 971d0676b5SLang Hames Size += 4; 981d0676b5SLang Hames uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField); 991d0676b5SLang Hames 1001d0676b5SLang Hames LLVM_DEBUG({ 1011d0676b5SLang Hames dbgs() << "Registering eh-frame section:\n"; 1021d0676b5SLang Hames dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @" 1031d0676b5SLang Hames << (void *)CurCFIRecord << ": ["; 1041d0676b5SLang Hames for (unsigned I = 0; I < Size; ++I) 1051d0676b5SLang Hames dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I)); 1061d0676b5SLang Hames dbgs() << " ]\n"; 1071d0676b5SLang Hames }); 1081d0676b5SLang Hames 1091d0676b5SLang Hames if (Offset != 0) 1101d0676b5SLang Hames if (auto Err = HandleFDE(CurCFIRecord)) 1111d0676b5SLang Hames return Err; 1121d0676b5SLang Hames 1131d0676b5SLang Hames CurCFIRecord += Size; 1141d0676b5SLang Hames 1151d0676b5SLang Hames Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord); 1161d0676b5SLang Hames } 1171d0676b5SLang Hames 1181d0676b5SLang Hames return Error::success(); 1191d0676b5SLang Hames } 1201d0676b5SLang Hames 121d898693fSAzharuddin Mohammed #endif // HAVE_UNW_ADD_DYNAMIC_FDE || __APPLE__ 1221d0676b5SLang Hames 1231d0676b5SLang Hames Error registerEHFrameSection(const void *EHFrameSectionAddr, 1241d0676b5SLang Hames size_t EHFrameSectionSize) { 12595733438SHarald van Dijk /* libgcc and libunwind __register_frame behave differently. We use the 12695733438SHarald van Dijk * presence of __unw_add_dynamic_fde to detect libunwind. */ 127d898693fSAzharuddin Mohammed #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__) 12895733438SHarald van Dijk // With libunwind, __register_frame has to be called for each FDE entry. 12995733438SHarald van Dijk return walkLibunwindEHFrameSection( 13095733438SHarald van Dijk static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize, 13195733438SHarald van Dijk registerFrameWrapper); 1321d0676b5SLang Hames #else 13395733438SHarald van Dijk // With libgcc, __register_frame takes a single argument: 1341d0676b5SLang Hames // a pointer to the start of the .eh_frame section. 1351d0676b5SLang Hames 1361d0676b5SLang Hames // How can it find the end? Because crtendS.o is linked 1371d0676b5SLang Hames // in and it has an .eh_frame section with four zero chars. 1381d0676b5SLang Hames return registerFrameWrapper(EHFrameSectionAddr); 1391d0676b5SLang Hames #endif 1401d0676b5SLang Hames } 1411d0676b5SLang Hames 1421d0676b5SLang Hames Error deregisterEHFrameSection(const void *EHFrameSectionAddr, 1431d0676b5SLang Hames size_t EHFrameSectionSize) { 144d898693fSAzharuddin Mohammed #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__) 14595733438SHarald van Dijk return walkLibunwindEHFrameSection( 14695733438SHarald van Dijk static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize, 14795733438SHarald van Dijk deregisterFrameWrapper); 1481d0676b5SLang Hames #else 1491d0676b5SLang Hames return deregisterFrameWrapper(EHFrameSectionAddr); 1501d0676b5SLang Hames #endif 1511d0676b5SLang Hames } 1521d0676b5SLang Hames 1531d0676b5SLang Hames } // end namespace orc 1541d0676b5SLang Hames } // end namespace llvm 1551d0676b5SLang Hames 156*089acf25SLang Hames static Error registerEHFrameWrapper(ExecutorAddrRange EHFrame) { 157*089acf25SLang Hames return llvm::orc::registerEHFrameSection(EHFrame.Start.toPtr<const void *>(), 158*089acf25SLang Hames EHFrame.size()); 1596498b0e9SLang Hames } 1606498b0e9SLang Hames 161*089acf25SLang Hames static Error deregisterEHFrameWrapper(ExecutorAddrRange EHFrame) { 162*089acf25SLang Hames return llvm::orc::deregisterEHFrameSection( 163*089acf25SLang Hames EHFrame.Start.toPtr<const void *>(), EHFrame.size()); 1644eb9fe2eSLang Hames } 1654eb9fe2eSLang Hames 166213666f8SLang Hames extern "C" orc::shared::CWrapperFunctionResult 1674eb9fe2eSLang Hames llvm_orc_registerEHFrameSectionWrapper(const char *Data, uint64_t Size) { 168*089acf25SLang Hames return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle( 1694eb9fe2eSLang Hames Data, Size, registerEHFrameWrapper) 1701d0676b5SLang Hames .release(); 1711d0676b5SLang Hames } 1721d0676b5SLang Hames 173213666f8SLang Hames extern "C" orc::shared::CWrapperFunctionResult 1744eb9fe2eSLang Hames llvm_orc_deregisterEHFrameSectionWrapper(const char *Data, uint64_t Size) { 175*089acf25SLang Hames return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle( 1764eb9fe2eSLang Hames Data, Size, deregisterEHFrameWrapper) 1771d0676b5SLang Hames .release(); 1781d0676b5SLang Hames } 179