1 //===--------- RegisterEHFrames.cpp - Register EH frame sections ----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
10 
11 #include "llvm/Config/config.h"
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::shared;
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 #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
89 
90 template <typename HandleFDEFn>
91 Error walkLibunwindEHFrameSection(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 // HAVE_UNW_ADD_DYNAMIC_FDE || __APPLE__
127 
128 Error registerEHFrameSection(const void *EHFrameSectionAddr,
129                              size_t EHFrameSectionSize) {
130   /* libgcc and libunwind __register_frame behave differently. We use the
131    * presence of __unw_add_dynamic_fde to detect libunwind. */
132 #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
133   // With libunwind, __register_frame has to be called for each FDE entry.
134   return walkLibunwindEHFrameSection(
135       static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
136       registerFrameWrapper);
137 #else
138   // With libgcc, __register_frame takes a single argument:
139   // a pointer to the start of the .eh_frame section.
140 
141   // How can it find the end? Because crtendS.o is linked
142   // in and it has an .eh_frame section with four zero chars.
143   return registerFrameWrapper(EHFrameSectionAddr);
144 #endif
145 }
146 
147 Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
148                                size_t EHFrameSectionSize) {
149 #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
150   return walkLibunwindEHFrameSection(
151       static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
152       deregisterFrameWrapper);
153 #else
154   return deregisterFrameWrapper(EHFrameSectionAddr);
155 #endif
156 }
157 
158 } // end namespace orc
159 } // end namespace llvm
160 
161 static Error registerEHFrameWrapper(ExecutorAddrRange EHFrame) {
162   return llvm::orc::registerEHFrameSection(EHFrame.Start.toPtr<const void *>(),
163                                            EHFrame.size());
164 }
165 
166 static Error deregisterEHFrameWrapper(ExecutorAddrRange EHFrame) {
167   return llvm::orc::deregisterEHFrameSection(
168       EHFrame.Start.toPtr<const void *>(), EHFrame.size());
169 }
170 
171 extern "C" orc::shared::CWrapperFunctionResult
172 llvm_orc_registerEHFrameSectionWrapper(const char *Data, uint64_t Size) {
173   return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
174              Data, Size, registerEHFrameWrapper)
175       .release();
176 }
177 
178 extern "C" orc::shared::CWrapperFunctionResult
179 llvm_orc_deregisterEHFrameSectionWrapper(const char *Data, uint64_t Size) {
180   return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
181              Data, Size, deregisterEHFrameWrapper)
182       .release();
183 }
184