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