xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h (revision a0409676120c1e558d0ade943019934e0f15118d)
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/Mangling.h"
21 #include "llvm/ExecutionEngine/Orc/OrcError.h"
22 #include "llvm/ExecutionEngine/RuntimeDyld.h"
23 #include "llvm/Object/Archive.h"
24 #include "llvm/Support/DynamicLibrary.h"
25 #include <algorithm>
26 #include <cstdint>
27 #include <string>
28 #include <utility>
29 #include <vector>
30 
31 namespace llvm {
32 
33 class ConstantArray;
34 class GlobalVariable;
35 class Function;
36 class Module;
37 class TargetMachine;
38 class Value;
39 
40 namespace orc {
41 
42 class ObjectLayer;
43 
44 /// Run a main function, returning the result.
45 ///
46 /// If the optional ProgramName argument is given then it will be inserted
47 /// before the strings in Args as the first argument to the called function.
48 ///
49 /// It is legal to have an empty argument list and no program name, however
50 /// many main functions will expect a name argument at least, and will fail
51 /// if none is provided.
52 int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
53               Optional<StringRef> ProgramName = None);
54 
55 /// This iterator provides a convenient way to iterate over the elements
56 ///        of an llvm.global_ctors/llvm.global_dtors instance.
57 ///
58 ///   The easiest way to get hold of instances of this class is to use the
59 /// getConstructors/getDestructors functions.
60 class CtorDtorIterator {
61 public:
62   /// Accessor for an element of the global_ctors/global_dtors array.
63   ///
64   ///   This class provides a read-only view of the element with any casts on
65   /// the function stripped away.
66   struct Element {
67     Element(unsigned Priority, Function *Func, Value *Data)
68       : Priority(Priority), Func(Func), Data(Data) {}
69 
70     unsigned Priority;
71     Function *Func;
72     Value *Data;
73   };
74 
75   /// Construct an iterator instance. If End is true then this iterator
76   ///        acts as the end of the range, otherwise it is the beginning.
77   CtorDtorIterator(const GlobalVariable *GV, bool End);
78 
79   /// Test iterators for equality.
80   bool operator==(const CtorDtorIterator &Other) const;
81 
82   /// Test iterators for inequality.
83   bool operator!=(const CtorDtorIterator &Other) const;
84 
85   /// Pre-increment iterator.
86   CtorDtorIterator& operator++();
87 
88   /// Post-increment iterator.
89   CtorDtorIterator operator++(int);
90 
91   /// Dereference iterator. The resulting value provides a read-only view
92   ///        of this element of the global_ctors/global_dtors list.
93   Element operator*() const;
94 
95 private:
96   const ConstantArray *InitList;
97   unsigned I;
98 };
99 
100 /// Create an iterator range over the entries of the llvm.global_ctors
101 ///        array.
102 iterator_range<CtorDtorIterator> getConstructors(const Module &M);
103 
104 /// Create an iterator range over the entries of the llvm.global_ctors
105 ///        array.
106 iterator_range<CtorDtorIterator> getDestructors(const Module &M);
107 
108 /// This iterator provides a convenient way to iterate over GlobalValues that
109 /// have initialization effects.
110 class StaticInitGVIterator {
111 public:
112   StaticInitGVIterator() = default;
113 
114   StaticInitGVIterator(Module &M)
115       : I(M.global_values().begin()), E(M.global_values().end()),
116         ObjFmt(Triple(M.getTargetTriple()).getObjectFormat()) {
117     if (I != E) {
118       if (!isStaticInitGlobal(*I))
119         moveToNextStaticInitGlobal();
120     } else
121       I = E = Module::global_value_iterator();
122   }
123 
124   bool operator==(const StaticInitGVIterator &O) const { return I == O.I; }
125   bool operator!=(const StaticInitGVIterator &O) const { return I != O.I; }
126 
127   StaticInitGVIterator &operator++() {
128     assert(I != E && "Increment past end of range");
129     moveToNextStaticInitGlobal();
130     return *this;
131   }
132 
133   GlobalValue &operator*() { return *I; }
134 
135 private:
136   bool isStaticInitGlobal(GlobalValue &GV);
137   void moveToNextStaticInitGlobal() {
138     ++I;
139     while (I != E && !isStaticInitGlobal(*I))
140       ++I;
141     if (I == E)
142       I = E = Module::global_value_iterator();
143   }
144 
145   Module::global_value_iterator I, E;
146   Triple::ObjectFormatType ObjFmt;
147 };
148 
149 /// Create an iterator range over the GlobalValues that contribute to static
150 /// initialization.
151 inline iterator_range<StaticInitGVIterator> getStaticInitGVs(Module &M) {
152   return make_range(StaticInitGVIterator(M), StaticInitGVIterator());
153 }
154 
155 /// Convenience class for recording constructor/destructor names for
156 ///        later execution.
157 template <typename JITLayerT>
158 class LegacyCtorDtorRunner {
159 public:
160   /// Construct a CtorDtorRunner for the given range using the given
161   ///        name mangling function.
162   LLVM_ATTRIBUTE_DEPRECATED(
163       LegacyCtorDtorRunner(std::vector<std::string> CtorDtorNames,
164                            VModuleKey K),
165       "ORCv1 utilities (utilities with the 'Legacy' prefix) are deprecated. "
166       "Please use the ORCv2 CtorDtorRunner utility instead");
167 
168   LegacyCtorDtorRunner(ORCv1DeprecationAcknowledgement,
169                        std::vector<std::string> CtorDtorNames, VModuleKey K)
170       : CtorDtorNames(std::move(CtorDtorNames)), K(K) {}
171 
172   /// Run the recorded constructors/destructors through the given JIT
173   ///        layer.
174   Error runViaLayer(JITLayerT &JITLayer) const {
175     using CtorDtorTy = void (*)();
176 
177     for (const auto &CtorDtorName : CtorDtorNames) {
178       if (auto CtorDtorSym = JITLayer.findSymbolIn(K, CtorDtorName, false)) {
179         if (auto AddrOrErr = CtorDtorSym.getAddress()) {
180           CtorDtorTy CtorDtor =
181             reinterpret_cast<CtorDtorTy>(static_cast<uintptr_t>(*AddrOrErr));
182           CtorDtor();
183         } else
184           return AddrOrErr.takeError();
185       } else {
186         if (auto Err = CtorDtorSym.takeError())
187           return Err;
188         else
189           return make_error<JITSymbolNotFound>(CtorDtorName);
190       }
191     }
192     return Error::success();
193   }
194 
195 private:
196   std::vector<std::string> CtorDtorNames;
197   orc::VModuleKey K;
198 };
199 
200 template <typename JITLayerT>
201 LegacyCtorDtorRunner<JITLayerT>::LegacyCtorDtorRunner(
202     std::vector<std::string> CtorDtorNames, VModuleKey K)
203     : CtorDtorNames(std::move(CtorDtorNames)), K(K) {}
204 
205 class CtorDtorRunner {
206 public:
207   CtorDtorRunner(JITDylib &JD) : JD(JD) {}
208   void add(iterator_range<CtorDtorIterator> CtorDtors);
209   Error run();
210 
211 private:
212   using CtorDtorList = std::vector<SymbolStringPtr>;
213   using CtorDtorPriorityMap = std::map<unsigned, CtorDtorList>;
214 
215   JITDylib &JD;
216   CtorDtorPriorityMap CtorDtorsByPriority;
217 };
218 
219 /// Support class for static dtor execution. For hosted (in-process) JITs
220 ///        only!
221 ///
222 ///   If a __cxa_atexit function isn't found C++ programs that use static
223 /// destructors will fail to link. However, we don't want to use the host
224 /// process's __cxa_atexit, because it will schedule JIT'd destructors to run
225 /// after the JIT has been torn down, which is no good. This class makes it easy
226 /// to override __cxa_atexit (and the related __dso_handle).
227 ///
228 ///   To use, clients should manually call searchOverrides from their symbol
229 /// resolver. This should generally be done after attempting symbol resolution
230 /// inside the JIT, but before searching the host process's symbol table. When
231 /// the client determines that destructors should be run (generally at JIT
232 /// teardown or after a return from main), the runDestructors method should be
233 /// called.
234 class LocalCXXRuntimeOverridesBase {
235 public:
236   /// Run any destructors recorded by the overriden __cxa_atexit function
237   /// (CXAAtExitOverride).
238   void runDestructors();
239 
240 protected:
241   template <typename PtrTy> JITTargetAddress toTargetAddress(PtrTy *P) {
242     return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(P));
243   }
244 
245   using DestructorPtr = void (*)(void *);
246   using CXXDestructorDataPair = std::pair<DestructorPtr, void *>;
247   using CXXDestructorDataPairList = std::vector<CXXDestructorDataPair>;
248   CXXDestructorDataPairList DSOHandleOverride;
249   static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg,
250                                void *DSOHandle);
251 };
252 
253 class LegacyLocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase {
254 public:
255   /// Create a runtime-overrides class.
256   template <typename MangleFtorT>
257   LLVM_ATTRIBUTE_DEPRECATED(
258       LegacyLocalCXXRuntimeOverrides(const MangleFtorT &Mangle),
259       "ORCv1 utilities (utilities with the 'Legacy' prefix) are deprecated. "
260       "Please use the ORCv2 LocalCXXRuntimeOverrides utility instead");
261 
262   template <typename MangleFtorT>
263   LegacyLocalCXXRuntimeOverrides(ORCv1DeprecationAcknowledgement,
264                                  const MangleFtorT &Mangle) {
265     addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride));
266     addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride));
267   }
268 
269   /// Search overrided symbols.
270   JITEvaluatedSymbol searchOverrides(const std::string &Name) {
271     auto I = CXXRuntimeOverrides.find(Name);
272     if (I != CXXRuntimeOverrides.end())
273       return JITEvaluatedSymbol(I->second, JITSymbolFlags::Exported);
274     return nullptr;
275   }
276 
277 private:
278   void addOverride(const std::string &Name, JITTargetAddress Addr) {
279     CXXRuntimeOverrides.insert(std::make_pair(Name, Addr));
280   }
281 
282   StringMap<JITTargetAddress> CXXRuntimeOverrides;
283 };
284 
285 template <typename MangleFtorT>
286 LegacyLocalCXXRuntimeOverrides::LegacyLocalCXXRuntimeOverrides(
287     const MangleFtorT &Mangle) {
288   addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride));
289   addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride));
290 }
291 
292 class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase {
293 public:
294   Error enable(JITDylib &JD, MangleAndInterner &Mangler);
295 };
296 
297 /// An interface for Itanium __cxa_atexit interposer implementations.
298 class ItaniumCXAAtExitSupport {
299 public:
300   struct AtExitRecord {
301     void (*F)(void *);
302     void *Ctx;
303   };
304 
305   void registerAtExit(void (*F)(void *), void *Ctx, void *DSOHandle);
306   void runAtExits(void *DSOHandle);
307 
308 private:
309   std::mutex AtExitsMutex;
310   DenseMap<void *, std::vector<AtExitRecord>> AtExitRecords;
311 };
312 
313 /// A utility class to expose symbols found via dlsym to the JIT.
314 ///
315 /// If an instance of this class is attached to a JITDylib as a fallback
316 /// definition generator, then any symbol found in the given DynamicLibrary that
317 /// passes the 'Allow' predicate will be added to the JITDylib.
318 class DynamicLibrarySearchGenerator : public JITDylib::DefinitionGenerator {
319 public:
320   using SymbolPredicate = std::function<bool(const SymbolStringPtr &)>;
321 
322   /// Create a DynamicLibrarySearchGenerator that searches for symbols in the
323   /// given sys::DynamicLibrary.
324   ///
325   /// If the Allow predicate is given then only symbols matching the predicate
326   /// will be searched for. If the predicate is not given then all symbols will
327   /// be searched for.
328   DynamicLibrarySearchGenerator(sys::DynamicLibrary Dylib, char GlobalPrefix,
329                                 SymbolPredicate Allow = SymbolPredicate());
330 
331   /// Permanently loads the library at the given path and, on success, returns
332   /// a DynamicLibrarySearchGenerator that will search it for symbol definitions
333   /// in the library. On failure returns the reason the library failed to load.
334   static Expected<std::unique_ptr<DynamicLibrarySearchGenerator>>
335   Load(const char *FileName, char GlobalPrefix,
336        SymbolPredicate Allow = SymbolPredicate());
337 
338   /// Creates a DynamicLibrarySearchGenerator that searches for symbols in
339   /// the current process.
340   static Expected<std::unique_ptr<DynamicLibrarySearchGenerator>>
341   GetForCurrentProcess(char GlobalPrefix,
342                        SymbolPredicate Allow = SymbolPredicate()) {
343     return Load(nullptr, GlobalPrefix, std::move(Allow));
344   }
345 
346   Error tryToGenerate(LookupKind K, JITDylib &JD,
347                       JITDylibLookupFlags JDLookupFlags,
348                       const SymbolLookupSet &Symbols) override;
349 
350 private:
351   sys::DynamicLibrary Dylib;
352   SymbolPredicate Allow;
353   char GlobalPrefix;
354 };
355 
356 /// A utility class to expose symbols from a static library.
357 ///
358 /// If an instance of this class is attached to a JITDylib as a fallback
359 /// definition generator, then any symbol found in the archive will result in
360 /// the containing object being added to the JITDylib.
361 class StaticLibraryDefinitionGenerator : public JITDylib::DefinitionGenerator {
362 public:
363   /// Try to create a StaticLibraryDefinitionGenerator from the given path.
364   ///
365   /// This call will succeed if the file at the given path is a static library
366   /// is a valid archive, otherwise it will return an error.
367   static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>>
368   Load(ObjectLayer &L, const char *FileName);
369 
370   /// Try to create a StaticLibraryDefinitionGenerator from the given path.
371   ///
372   /// This call will succeed if the file at the given path is a static library
373   /// or a MachO universal binary containing a static library that is compatible
374   /// with the given triple. Otherwise it will return an error.
375   static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>>
376   Load(ObjectLayer &L, const char *FileName, const Triple &TT);
377 
378   /// Try to create a StaticLibrarySearchGenerator from the given memory buffer.
379   /// This call will succeed if the buffer contains a valid archive, otherwise
380   /// it will return an error.
381   static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>>
382   Create(ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer);
383 
384   Error tryToGenerate(LookupKind K, JITDylib &JD,
385                       JITDylibLookupFlags JDLookupFlags,
386                       const SymbolLookupSet &Symbols) override;
387 
388 private:
389   StaticLibraryDefinitionGenerator(ObjectLayer &L,
390                                    std::unique_ptr<MemoryBuffer> ArchiveBuffer,
391                                    Error &Err);
392 
393   ObjectLayer &L;
394   std::unique_ptr<MemoryBuffer> ArchiveBuffer;
395   std::unique_ptr<object::Archive> Archive;
396 };
397 
398 } // end namespace orc
399 } // end namespace llvm
400 
401 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
402