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