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