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(P: 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(P: 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(EHFrameSectionAddr: EHFrame.Start.toPtr<const void *>(), |
163 | EHFrameSectionSize: EHFrame.size()); |
164 | } |
165 | |
166 | static Error deregisterEHFrameWrapper(ExecutorAddrRange EHFrame) { |
167 | return llvm::orc::deregisterEHFrameSection( |
168 | EHFrameSectionAddr: EHFrame.Start.toPtr<const void *>(), EHFrameSectionSize: 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 | ArgData: Data, ArgSize: Size, Handler&: 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 | ArgData: Data, ArgSize: Size, Handler&: deregisterEHFrameWrapper) |
182 | .release(); |
183 | } |
184 | |