1 //===--------- RegisterEHFrames.cpp - Register EH frame sections ----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
11 
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::tpctypes;
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 #ifdef __APPLE__
89 
90 template <typename HandleFDEFn>
91 Error walkAppleEHFrameSection(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 // __APPLE__
127 
128 Error registerEHFrameSection(const void *EHFrameSectionAddr,
129                              size_t EHFrameSectionSize) {
130 #ifdef __APPLE__
131   // On Darwin __register_frame has to be called for each FDE entry.
132   return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
133                                  EHFrameSectionSize, registerFrameWrapper);
134 #else
135   // On Linux __register_frame takes a single argument:
136   // a pointer to the start of the .eh_frame section.
137 
138   // How can it find the end? Because crtendS.o is linked
139   // in and it has an .eh_frame section with four zero chars.
140   return registerFrameWrapper(EHFrameSectionAddr);
141 #endif
142 }
143 
144 Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
145                                size_t EHFrameSectionSize) {
146 #ifdef __APPLE__
147   return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
148                                  EHFrameSectionSize, deregisterFrameWrapper);
149 #else
150   return deregisterFrameWrapper(EHFrameSectionAddr);
151 #endif
152 }
153 
154 } // end namespace orc
155 } // end namespace llvm
156 
157 extern "C" CWrapperFunctionResult
158 llvm_orc_registerEHFrameSectionWrapper(uint8_t *Data, uint64_t Size) {
159   if (Size != sizeof(uint64_t) + sizeof(uint64_t))
160     return WrapperFunctionResult::from(
161                "Invalid arguments to llvm_orc_registerEHFrameSectionWrapper")
162         .release();
163 
164   uint64_t EHFrameSectionAddr;
165   uint64_t EHFrameSectionSize;
166 
167   {
168     BinaryStreamReader ArgReader(ArrayRef<uint8_t>(Data, Size),
169                                  support::endianness::big);
170     cantFail(ArgReader.readInteger(EHFrameSectionAddr));
171     cantFail(ArgReader.readInteger(EHFrameSectionSize));
172   }
173 
174   if (auto Err = registerEHFrameSection(
175           jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
176           EHFrameSectionSize)) {
177     auto ErrMsg = toString(std::move(Err));
178     return WrapperFunctionResult::from(ErrMsg).release();
179   }
180   return WrapperFunctionResult().release();
181 }
182 
183 extern "C" CWrapperFunctionResult
184 llvm_orc_deregisterEHFrameSectionWrapper(uint8_t *Data, uint64_t Size) {
185   if (Size != sizeof(uint64_t) + sizeof(uint64_t))
186     return WrapperFunctionResult::from(
187                "Invalid arguments to llvm_orc_registerEHFrameSectionWrapper")
188         .release();
189 
190   uint64_t EHFrameSectionAddr;
191   uint64_t EHFrameSectionSize;
192 
193   {
194     BinaryStreamReader ArgReader(ArrayRef<uint8_t>(Data, Size),
195                                  support::endianness::big);
196     cantFail(ArgReader.readInteger(EHFrameSectionAddr));
197     cantFail(ArgReader.readInteger(EHFrameSectionSize));
198   }
199 
200   if (auto Err = deregisterEHFrameSection(
201           jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
202           EHFrameSectionSize)) {
203     auto ErrMsg = toString(std::move(Err));
204     return WrapperFunctionResult::from(ErrMsg).release();
205   }
206   return WrapperFunctionResult().release();
207 }
208