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