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/ExecutionEngine/JITSymbol.h"
131d0676b5SLang Hames #include "llvm/Support/BinaryStreamReader.h"
141d0676b5SLang Hames #include "llvm/Support/Compiler.h"
151d0676b5SLang Hames #include "llvm/Support/Debug.h"
161d0676b5SLang Hames #include "llvm/Support/DynamicLibrary.h"
171d0676b5SLang Hames #include "llvm/Support/raw_ostream.h"
181d0676b5SLang Hames 
191d0676b5SLang Hames #include "llvm/Support/FormatVariadic.h"
201d0676b5SLang Hames 
211d0676b5SLang Hames #define DEBUG_TYPE "orc"
221d0676b5SLang Hames 
231d0676b5SLang Hames using namespace llvm;
241d0676b5SLang Hames using namespace llvm::orc;
254eb9fe2eSLang Hames using namespace llvm::orc::shared;
261d0676b5SLang Hames 
271d0676b5SLang Hames namespace llvm {
281d0676b5SLang Hames namespace orc {
291d0676b5SLang Hames 
301d0676b5SLang Hames #if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) &&          \
311d0676b5SLang Hames     !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
321d0676b5SLang Hames 
331d0676b5SLang Hames extern "C" void __register_frame(const void *);
341d0676b5SLang Hames extern "C" void __deregister_frame(const void *);
351d0676b5SLang Hames 
registerFrameWrapper(const void * P)361d0676b5SLang Hames Error registerFrameWrapper(const void *P) {
371d0676b5SLang Hames   __register_frame(P);
381d0676b5SLang Hames   return Error::success();
391d0676b5SLang Hames }
401d0676b5SLang Hames 
deregisterFrameWrapper(const void * P)411d0676b5SLang Hames Error deregisterFrameWrapper(const void *P) {
421d0676b5SLang Hames   __deregister_frame(P);
431d0676b5SLang Hames   return Error::success();
441d0676b5SLang Hames }
451d0676b5SLang Hames 
461d0676b5SLang Hames #else
471d0676b5SLang Hames 
481d0676b5SLang Hames // The building compiler does not have __(de)register_frame but
491d0676b5SLang Hames // it may be found at runtime in a dynamically-loaded library.
501d0676b5SLang Hames // For example, this happens when building LLVM with Visual C++
511d0676b5SLang Hames // but using the MingW runtime.
521d0676b5SLang Hames static Error registerFrameWrapper(const void *P) {
531d0676b5SLang Hames   static void((*RegisterFrame)(const void *)) = 0;
541d0676b5SLang Hames 
551d0676b5SLang Hames   if (!RegisterFrame)
561d0676b5SLang Hames     *(void **)&RegisterFrame =
571d0676b5SLang Hames         llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
581d0676b5SLang Hames 
591d0676b5SLang Hames   if (RegisterFrame) {
601d0676b5SLang Hames     RegisterFrame(P);
611d0676b5SLang Hames     return Error::success();
621d0676b5SLang Hames   }
631d0676b5SLang Hames 
641d0676b5SLang Hames   return make_error<StringError>("could not register eh-frame: "
651d0676b5SLang Hames                                  "__register_frame function not found",
661d0676b5SLang Hames                                  inconvertibleErrorCode());
671d0676b5SLang Hames }
681d0676b5SLang Hames 
691d0676b5SLang Hames static Error deregisterFrameWrapper(const void *P) {
701d0676b5SLang Hames   static void((*DeregisterFrame)(const void *)) = 0;
711d0676b5SLang Hames 
721d0676b5SLang Hames   if (!DeregisterFrame)
731d0676b5SLang Hames     *(void **)&DeregisterFrame =
741d0676b5SLang Hames         llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
751d0676b5SLang Hames             "__deregister_frame");
761d0676b5SLang Hames 
771d0676b5SLang Hames   if (DeregisterFrame) {
781d0676b5SLang Hames     DeregisterFrame(P);
791d0676b5SLang Hames     return Error::success();
801d0676b5SLang Hames   }
811d0676b5SLang Hames 
821d0676b5SLang Hames   return make_error<StringError>("could not deregister eh-frame: "
831d0676b5SLang Hames                                  "__deregister_frame function not found",
841d0676b5SLang Hames                                  inconvertibleErrorCode());
851d0676b5SLang Hames }
861d0676b5SLang Hames #endif
871d0676b5SLang Hames 
88d898693fSAzharuddin Mohammed #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
891d0676b5SLang Hames 
901d0676b5SLang Hames template <typename HandleFDEFn>
walkLibunwindEHFrameSection(const char * const SectionStart,size_t SectionSize,HandleFDEFn HandleFDE)9195733438SHarald van Dijk Error walkLibunwindEHFrameSection(const char *const SectionStart,
921d0676b5SLang Hames                                   size_t SectionSize, HandleFDEFn HandleFDE) {
931d0676b5SLang Hames   const char *CurCFIRecord = SectionStart;
941d0676b5SLang Hames   const char *End = SectionStart + SectionSize;
951d0676b5SLang Hames   uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
961d0676b5SLang Hames 
971d0676b5SLang Hames   while (CurCFIRecord != End && Size != 0) {
981d0676b5SLang Hames     const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
991d0676b5SLang Hames     if (Size == 0xffffffff)
1001d0676b5SLang Hames       Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
1011d0676b5SLang Hames     else
1021d0676b5SLang Hames       Size += 4;
1031d0676b5SLang Hames     uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
1041d0676b5SLang Hames 
1051d0676b5SLang Hames     LLVM_DEBUG({
1061d0676b5SLang Hames       dbgs() << "Registering eh-frame section:\n";
1071d0676b5SLang Hames       dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
1081d0676b5SLang Hames              << (void *)CurCFIRecord << ": [";
1091d0676b5SLang Hames       for (unsigned I = 0; I < Size; ++I)
1101d0676b5SLang Hames         dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
1111d0676b5SLang Hames       dbgs() << " ]\n";
1121d0676b5SLang Hames     });
1131d0676b5SLang Hames 
1141d0676b5SLang Hames     if (Offset != 0)
1151d0676b5SLang Hames       if (auto Err = HandleFDE(CurCFIRecord))
1161d0676b5SLang Hames         return Err;
1171d0676b5SLang Hames 
1181d0676b5SLang Hames     CurCFIRecord += Size;
1191d0676b5SLang Hames 
1201d0676b5SLang Hames     Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
1211d0676b5SLang Hames   }
1221d0676b5SLang Hames 
1231d0676b5SLang Hames   return Error::success();
1241d0676b5SLang Hames }
1251d0676b5SLang Hames 
126d898693fSAzharuddin Mohammed #endif // HAVE_UNW_ADD_DYNAMIC_FDE || __APPLE__
1271d0676b5SLang Hames 
registerEHFrameSection(const void * EHFrameSectionAddr,size_t EHFrameSectionSize)1281d0676b5SLang Hames Error registerEHFrameSection(const void *EHFrameSectionAddr,
1291d0676b5SLang Hames                              size_t EHFrameSectionSize) {
13095733438SHarald van Dijk   /* libgcc and libunwind __register_frame behave differently. We use the
13195733438SHarald van Dijk    * presence of __unw_add_dynamic_fde to detect libunwind. */
132d898693fSAzharuddin Mohammed #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
13395733438SHarald van Dijk   // With libunwind, __register_frame has to be called for each FDE entry.
13495733438SHarald van Dijk   return walkLibunwindEHFrameSection(
13595733438SHarald van Dijk       static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
13695733438SHarald van Dijk       registerFrameWrapper);
1371d0676b5SLang Hames #else
13895733438SHarald van Dijk   // With libgcc, __register_frame takes a single argument:
1391d0676b5SLang Hames   // a pointer to the start of the .eh_frame section.
1401d0676b5SLang Hames 
1411d0676b5SLang Hames   // How can it find the end? Because crtendS.o is linked
1421d0676b5SLang Hames   // in and it has an .eh_frame section with four zero chars.
1431d0676b5SLang Hames   return registerFrameWrapper(EHFrameSectionAddr);
1441d0676b5SLang Hames #endif
1451d0676b5SLang Hames }
1461d0676b5SLang Hames 
deregisterEHFrameSection(const void * EHFrameSectionAddr,size_t EHFrameSectionSize)1471d0676b5SLang Hames Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
1481d0676b5SLang Hames                                size_t EHFrameSectionSize) {
149d898693fSAzharuddin Mohammed #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
15095733438SHarald van Dijk   return walkLibunwindEHFrameSection(
15195733438SHarald van Dijk       static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
15295733438SHarald van Dijk       deregisterFrameWrapper);
1531d0676b5SLang Hames #else
1541d0676b5SLang Hames   return deregisterFrameWrapper(EHFrameSectionAddr);
1551d0676b5SLang Hames #endif
1561d0676b5SLang Hames }
1571d0676b5SLang Hames 
1581d0676b5SLang Hames } // end namespace orc
1591d0676b5SLang Hames } // end namespace llvm
1601d0676b5SLang Hames 
registerEHFrameWrapper(ExecutorAddrRange EHFrame)161*089acf25SLang Hames static Error registerEHFrameWrapper(ExecutorAddrRange EHFrame) {
162*089acf25SLang Hames   return llvm::orc::registerEHFrameSection(EHFrame.Start.toPtr<const void *>(),
163*089acf25SLang Hames                                            EHFrame.size());
1646498b0e9SLang Hames }
1656498b0e9SLang Hames 
deregisterEHFrameWrapper(ExecutorAddrRange EHFrame)166*089acf25SLang Hames static Error deregisterEHFrameWrapper(ExecutorAddrRange EHFrame) {
167*089acf25SLang Hames   return llvm::orc::deregisterEHFrameSection(
168*089acf25SLang Hames       EHFrame.Start.toPtr<const void *>(), EHFrame.size());
1694eb9fe2eSLang Hames }
1704eb9fe2eSLang Hames 
171213666f8SLang Hames extern "C" orc::shared::CWrapperFunctionResult
llvm_orc_registerEHFrameSectionWrapper(const char * Data,uint64_t Size)1724eb9fe2eSLang Hames llvm_orc_registerEHFrameSectionWrapper(const char *Data, uint64_t Size) {
173*089acf25SLang Hames   return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
1744eb9fe2eSLang Hames              Data, Size, registerEHFrameWrapper)
1751d0676b5SLang Hames       .release();
1761d0676b5SLang Hames }
1771d0676b5SLang Hames 
178213666f8SLang Hames extern "C" orc::shared::CWrapperFunctionResult
llvm_orc_deregisterEHFrameSectionWrapper(const char * Data,uint64_t Size)1794eb9fe2eSLang Hames llvm_orc_deregisterEHFrameSectionWrapper(const char *Data, uint64_t Size) {
180*089acf25SLang Hames   return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
1814eb9fe2eSLang Hames              Data, Size, deregisterEHFrameWrapper)
1821d0676b5SLang Hames       .release();
1831d0676b5SLang Hames }
184