xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h (revision 6966ac055c3b7a39266fb982493330df7a097997)
1 //===- ExecutionUtils.h - Utilities for executing code in Orc ---*- C++ -*-===//
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 // Contains utilities for executing code in Orc.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
14 #define LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
15 
16 #include "llvm/ADT/StringMap.h"
17 #include "llvm/ADT/iterator_range.h"
18 #include "llvm/ExecutionEngine/JITSymbol.h"
19 #include "llvm/ExecutionEngine/Orc/Core.h"
20 #include "llvm/ExecutionEngine/Orc/OrcError.h"
21 #include "llvm/ExecutionEngine/RuntimeDyld.h"
22 #include "llvm/Support/DynamicLibrary.h"
23 #include <algorithm>
24 #include <cstdint>
25 #include <string>
26 #include <utility>
27 #include <vector>
28 
29 namespace llvm {
30 
31 class ConstantArray;
32 class GlobalVariable;
33 class Function;
34 class Module;
35 class TargetMachine;
36 class Value;
37 
38 namespace orc {
39 
40 /// This iterator provides a convenient way to iterate over the elements
41 ///        of an llvm.global_ctors/llvm.global_dtors instance.
42 ///
43 ///   The easiest way to get hold of instances of this class is to use the
44 /// getConstructors/getDestructors functions.
45 class CtorDtorIterator {
46 public:
47   /// Accessor for an element of the global_ctors/global_dtors array.
48   ///
49   ///   This class provides a read-only view of the element with any casts on
50   /// the function stripped away.
51   struct Element {
52     Element(unsigned Priority, Function *Func, Value *Data)
53       : Priority(Priority), Func(Func), Data(Data) {}
54 
55     unsigned Priority;
56     Function *Func;
57     Value *Data;
58   };
59 
60   /// Construct an iterator instance. If End is true then this iterator
61   ///        acts as the end of the range, otherwise it is the beginning.
62   CtorDtorIterator(const GlobalVariable *GV, bool End);
63 
64   /// Test iterators for equality.
65   bool operator==(const CtorDtorIterator &Other) const;
66 
67   /// Test iterators for inequality.
68   bool operator!=(const CtorDtorIterator &Other) const;
69 
70   /// Pre-increment iterator.
71   CtorDtorIterator& operator++();
72 
73   /// Post-increment iterator.
74   CtorDtorIterator operator++(int);
75 
76   /// Dereference iterator. The resulting value provides a read-only view
77   ///        of this element of the global_ctors/global_dtors list.
78   Element operator*() const;
79 
80 private:
81   const ConstantArray *InitList;
82   unsigned I;
83 };
84 
85 /// Create an iterator range over the entries of the llvm.global_ctors
86 ///        array.
87 iterator_range<CtorDtorIterator> getConstructors(const Module &M);
88 
89 /// Create an iterator range over the entries of the llvm.global_ctors
90 ///        array.
91 iterator_range<CtorDtorIterator> getDestructors(const Module &M);
92 
93 /// Convenience class for recording constructor/destructor names for
94 ///        later execution.
95 template <typename JITLayerT>
96 class LegacyCtorDtorRunner {
97 public:
98   /// Construct a CtorDtorRunner for the given range using the given
99   ///        name mangling function.
100   LLVM_ATTRIBUTE_DEPRECATED(
101       LegacyCtorDtorRunner(std::vector<std::string> CtorDtorNames,
102                            VModuleKey K),
103       "ORCv1 utilities (utilities with the 'Legacy' prefix) are deprecated. "
104       "Please use the ORCv2 CtorDtorRunner utility instead");
105 
106   LegacyCtorDtorRunner(ORCv1DeprecationAcknowledgement,
107                        std::vector<std::string> CtorDtorNames, VModuleKey K)
108       : CtorDtorNames(std::move(CtorDtorNames)), K(K) {}
109 
110   /// Run the recorded constructors/destructors through the given JIT
111   ///        layer.
112   Error runViaLayer(JITLayerT &JITLayer) const {
113     using CtorDtorTy = void (*)();
114 
115     for (const auto &CtorDtorName : CtorDtorNames) {
116       if (auto CtorDtorSym = JITLayer.findSymbolIn(K, CtorDtorName, false)) {
117         if (auto AddrOrErr = CtorDtorSym.getAddress()) {
118           CtorDtorTy CtorDtor =
119             reinterpret_cast<CtorDtorTy>(static_cast<uintptr_t>(*AddrOrErr));
120           CtorDtor();
121         } else
122           return AddrOrErr.takeError();
123       } else {
124         if (auto Err = CtorDtorSym.takeError())
125           return Err;
126         else
127           return make_error<JITSymbolNotFound>(CtorDtorName);
128       }
129     }
130     return Error::success();
131   }
132 
133 private:
134   std::vector<std::string> CtorDtorNames;
135   orc::VModuleKey K;
136 };
137 
138 template <typename JITLayerT>
139 LegacyCtorDtorRunner<JITLayerT>::LegacyCtorDtorRunner(
140     std::vector<std::string> CtorDtorNames, VModuleKey K)
141     : CtorDtorNames(std::move(CtorDtorNames)), K(K) {}
142 
143 class CtorDtorRunner {
144 public:
145   CtorDtorRunner(JITDylib &JD) : JD(JD) {}
146   void add(iterator_range<CtorDtorIterator> CtorDtors);
147   Error run();
148 
149 private:
150   using CtorDtorList = std::vector<SymbolStringPtr>;
151   using CtorDtorPriorityMap = std::map<unsigned, CtorDtorList>;
152 
153   JITDylib &JD;
154   CtorDtorPriorityMap CtorDtorsByPriority;
155 };
156 
157 /// Support class for static dtor execution. For hosted (in-process) JITs
158 ///        only!
159 ///
160 ///   If a __cxa_atexit function isn't found C++ programs that use static
161 /// destructors will fail to link. However, we don't want to use the host
162 /// process's __cxa_atexit, because it will schedule JIT'd destructors to run
163 /// after the JIT has been torn down, which is no good. This class makes it easy
164 /// to override __cxa_atexit (and the related __dso_handle).
165 ///
166 ///   To use, clients should manually call searchOverrides from their symbol
167 /// resolver. This should generally be done after attempting symbol resolution
168 /// inside the JIT, but before searching the host process's symbol table. When
169 /// the client determines that destructors should be run (generally at JIT
170 /// teardown or after a return from main), the runDestructors method should be
171 /// called.
172 class LocalCXXRuntimeOverridesBase {
173 public:
174   /// Run any destructors recorded by the overriden __cxa_atexit function
175   /// (CXAAtExitOverride).
176   void runDestructors();
177 
178 protected:
179   template <typename PtrTy> JITTargetAddress toTargetAddress(PtrTy *P) {
180     return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(P));
181   }
182 
183   using DestructorPtr = void (*)(void *);
184   using CXXDestructorDataPair = std::pair<DestructorPtr, void *>;
185   using CXXDestructorDataPairList = std::vector<CXXDestructorDataPair>;
186   CXXDestructorDataPairList DSOHandleOverride;
187   static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg,
188                                void *DSOHandle);
189 };
190 
191 class LegacyLocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase {
192 public:
193   /// Create a runtime-overrides class.
194   template <typename MangleFtorT>
195   LLVM_ATTRIBUTE_DEPRECATED(
196       LegacyLocalCXXRuntimeOverrides(const MangleFtorT &Mangle),
197       "ORCv1 utilities (utilities with the 'Legacy' prefix) are deprecated. "
198       "Please use the ORCv2 LocalCXXRuntimeOverrides utility instead");
199 
200   template <typename MangleFtorT>
201   LegacyLocalCXXRuntimeOverrides(ORCv1DeprecationAcknowledgement,
202                                  const MangleFtorT &Mangle) {
203     addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride));
204     addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride));
205   }
206 
207   /// Search overrided symbols.
208   JITEvaluatedSymbol searchOverrides(const std::string &Name) {
209     auto I = CXXRuntimeOverrides.find(Name);
210     if (I != CXXRuntimeOverrides.end())
211       return JITEvaluatedSymbol(I->second, JITSymbolFlags::Exported);
212     return nullptr;
213   }
214 
215 private:
216   void addOverride(const std::string &Name, JITTargetAddress Addr) {
217     CXXRuntimeOverrides.insert(std::make_pair(Name, Addr));
218   }
219 
220   StringMap<JITTargetAddress> CXXRuntimeOverrides;
221 };
222 
223 template <typename MangleFtorT>
224 LegacyLocalCXXRuntimeOverrides::LegacyLocalCXXRuntimeOverrides(
225     const MangleFtorT &Mangle) {
226   addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride));
227   addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride));
228 }
229 
230 class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase {
231 public:
232   Error enable(JITDylib &JD, MangleAndInterner &Mangler);
233 };
234 
235 /// A utility class to expose symbols found via dlsym to the JIT.
236 ///
237 /// If an instance of this class is attached to a JITDylib as a fallback
238 /// definition generator, then any symbol found in the given DynamicLibrary that
239 /// passes the 'Allow' predicate will be added to the JITDylib.
240 class DynamicLibrarySearchGenerator {
241 public:
242   using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
243 
244   /// Create a DynamicLibrarySearchGenerator that searches for symbols in the
245   /// given sys::DynamicLibrary.
246   ///
247   /// If the Allow predicate is given then only symbols matching the predicate
248   /// will be searched for. If the predicate is not given then all symbols will
249   /// be searched for.
250   DynamicLibrarySearchGenerator(sys::DynamicLibrary Dylib, char GlobalPrefix,
251                                 SymbolPredicate Allow = SymbolPredicate());
252 
253   /// Permanently loads the library at the given path and, on success, returns
254   /// a DynamicLibrarySearchGenerator that will search it for symbol definitions
255   /// in the library. On failure returns the reason the library failed to load.
256   static Expected<DynamicLibrarySearchGenerator>
257   Load(const char *FileName, char GlobalPrefix,
258        SymbolPredicate Allow = SymbolPredicate());
259 
260   /// Creates a DynamicLibrarySearchGenerator that searches for symbols in
261   /// the current process.
262   static Expected<DynamicLibrarySearchGenerator>
263   GetForCurrentProcess(char GlobalPrefix,
264                        SymbolPredicate Allow = SymbolPredicate()) {
265     return Load(nullptr, GlobalPrefix, std::move(Allow));
266   }
267 
268   Expected<SymbolNameSet> operator()(JITDylib &JD, const SymbolNameSet &Names);
269 
270 private:
271   sys::DynamicLibrary Dylib;
272   SymbolPredicate Allow;
273   char GlobalPrefix;
274 };
275 
276 } // end namespace orc
277 } // end namespace llvm
278 
279 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
280