xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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/Support/Compiler.h"
13 #include "llvm/Support/DynamicLibrary.h"
14 #include "llvm/Support/raw_ostream.h"
15 
16 #define DEBUG_TYPE "orc"
17 
18 using namespace llvm;
19 using namespace llvm::orc;
20 using namespace llvm::orc::shared;
21 
22 namespace llvm {
23 namespace orc {
24 
25 #if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) &&          \
26     !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
27 
28 extern "C" void __register_frame(const void *);
29 extern "C" void __deregister_frame(const void *);
30 
31 Error registerFrameWrapper(const void *P) {
32   __register_frame(P);
33   return Error::success();
34 }
35 
36 Error deregisterFrameWrapper(const void *P) {
37   __deregister_frame(P);
38   return Error::success();
39 }
40 
41 #else
42 
43 // The building compiler does not have __(de)register_frame but
44 // it may be found at runtime in a dynamically-loaded library.
45 // For example, this happens when building LLVM with Visual C++
46 // but using the MingW runtime.
47 static Error registerFrameWrapper(const void *P) {
48   static void((*RegisterFrame)(const void *)) = 0;
49 
50   if (!RegisterFrame)
51     *(void **)&RegisterFrame =
52         llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
53 
54   if (RegisterFrame) {
55     RegisterFrame(P);
56     return Error::success();
57   }
58 
59   return make_error<StringError>("could not register eh-frame: "
60                                  "__register_frame function not found",
61                                  inconvertibleErrorCode());
62 }
63 
64 static Error deregisterFrameWrapper(const void *P) {
65   static void((*DeregisterFrame)(const void *)) = 0;
66 
67   if (!DeregisterFrame)
68     *(void **)&DeregisterFrame =
69         llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
70             "__deregister_frame");
71 
72   if (DeregisterFrame) {
73     DeregisterFrame(P);
74     return Error::success();
75   }
76 
77   return make_error<StringError>("could not deregister eh-frame: "
78                                  "__deregister_frame function not found",
79                                  inconvertibleErrorCode());
80 }
81 #endif
82 
83 #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
84 
85 template <typename HandleFDEFn>
86 Error walkLibunwindEHFrameSection(const char *const SectionStart,
87                                   size_t SectionSize, HandleFDEFn HandleFDE) {
88   const char *CurCFIRecord = SectionStart;
89   const char *End = SectionStart + SectionSize;
90   uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
91 
92   while (CurCFIRecord != End && Size != 0) {
93     const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
94     if (Size == 0xffffffff)
95       Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
96     else
97       Size += 4;
98     uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
99 
100     LLVM_DEBUG({
101       dbgs() << "Registering eh-frame section:\n";
102       dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
103              << (void *)CurCFIRecord << ": [";
104       for (unsigned I = 0; I < Size; ++I)
105         dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
106       dbgs() << " ]\n";
107     });
108 
109     if (Offset != 0)
110       if (auto Err = HandleFDE(CurCFIRecord))
111         return Err;
112 
113     CurCFIRecord += Size;
114 
115     Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
116   }
117 
118   return Error::success();
119 }
120 
121 #endif // HAVE_UNW_ADD_DYNAMIC_FDE || __APPLE__
122 
123 Error registerEHFrameSection(const void *EHFrameSectionAddr,
124                              size_t EHFrameSectionSize) {
125   /* libgcc and libunwind __register_frame behave differently. We use the
126    * presence of __unw_add_dynamic_fde to detect libunwind. */
127 #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
128   // With libunwind, __register_frame has to be called for each FDE entry.
129   return walkLibunwindEHFrameSection(
130       static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
131       registerFrameWrapper);
132 #else
133   // With libgcc, __register_frame takes a single argument:
134   // a pointer to the start of the .eh_frame section.
135 
136   // How can it find the end? Because crtendS.o is linked
137   // in and it has an .eh_frame section with four zero chars.
138   return registerFrameWrapper(EHFrameSectionAddr);
139 #endif
140 }
141 
142 Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
143                                size_t EHFrameSectionSize) {
144 #if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)
145   return walkLibunwindEHFrameSection(
146       static_cast<const char *>(EHFrameSectionAddr), EHFrameSectionSize,
147       deregisterFrameWrapper);
148 #else
149   return deregisterFrameWrapper(EHFrameSectionAddr);
150 #endif
151 }
152 
153 } // end namespace orc
154 } // end namespace llvm
155 
156 static Error registerEHFrameWrapper(ExecutorAddrRange EHFrame) {
157   return llvm::orc::registerEHFrameSection(EHFrame.Start.toPtr<const void *>(),
158                                            EHFrame.size());
159 }
160 
161 static Error deregisterEHFrameWrapper(ExecutorAddrRange EHFrame) {
162   return llvm::orc::deregisterEHFrameSection(
163       EHFrame.Start.toPtr<const void *>(), EHFrame.size());
164 }
165 
166 extern "C" orc::shared::CWrapperFunctionResult
167 llvm_orc_registerEHFrameSectionAllocAction(const char *ArgData,
168                                            size_t ArgSize) {
169   return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
170              ArgData, ArgSize, registerEHFrameWrapper)
171       .release();
172 }
173 
174 extern "C" orc::shared::CWrapperFunctionResult
175 llvm_orc_deregisterEHFrameSectionAllocAction(const char *ArgData,
176                                              size_t ArgSize) {
177   return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
178              ArgData, ArgSize, deregisterEHFrameWrapper)
179       .release();
180 }
181