blob: 40dd415d584875a58e42afe98a5e185a08d38ac7 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- ExecutionUtils.h - Utilities for executing code in Orc ---*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
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"
Andrew Scullcdfcccc2018-10-05 20:58:37 +010022#include "llvm/Support/DynamicLibrary.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010023#include <algorithm>
24#include <cstdint>
25#include <string>
26#include <utility>
27#include <vector>
28
29namespace llvm {
30
31class ConstantArray;
32class GlobalVariable;
33class Function;
34class Module;
Andrew Scullcdfcccc2018-10-05 20:58:37 +010035class TargetMachine;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010036class Value;
37
38namespace orc {
39
Andrew Scullcdfcccc2018-10-05 20:58:37 +010040/// This iterator provides a convenient way to iterate over the elements
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010041/// 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.
45class CtorDtorIterator {
46public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +010047 /// Accessor for an element of the global_ctors/global_dtors array.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010048 ///
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
Andrew Scullcdfcccc2018-10-05 20:58:37 +010060 /// Construct an iterator instance. If End is true then this iterator
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010061 /// acts as the end of the range, otherwise it is the beginning.
62 CtorDtorIterator(const GlobalVariable *GV, bool End);
63
Andrew Scullcdfcccc2018-10-05 20:58:37 +010064 /// Test iterators for equality.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010065 bool operator==(const CtorDtorIterator &Other) const;
66
Andrew Scullcdfcccc2018-10-05 20:58:37 +010067 /// Test iterators for inequality.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010068 bool operator!=(const CtorDtorIterator &Other) const;
69
Andrew Scullcdfcccc2018-10-05 20:58:37 +010070 /// Pre-increment iterator.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010071 CtorDtorIterator& operator++();
72
Andrew Scullcdfcccc2018-10-05 20:58:37 +010073 /// Post-increment iterator.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010074 CtorDtorIterator operator++(int);
75
Andrew Scullcdfcccc2018-10-05 20:58:37 +010076 /// Dereference iterator. The resulting value provides a read-only view
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010077 /// of this element of the global_ctors/global_dtors list.
78 Element operator*() const;
79
80private:
81 const ConstantArray *InitList;
82 unsigned I;
83};
84
Andrew Scullcdfcccc2018-10-05 20:58:37 +010085/// Create an iterator range over the entries of the llvm.global_ctors
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010086/// array.
87iterator_range<CtorDtorIterator> getConstructors(const Module &M);
88
Andrew Scullcdfcccc2018-10-05 20:58:37 +010089/// Create an iterator range over the entries of the llvm.global_ctors
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010090/// array.
91iterator_range<CtorDtorIterator> getDestructors(const Module &M);
92
Andrew Scullcdfcccc2018-10-05 20:58:37 +010093/// Convenience class for recording constructor/destructor names for
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010094/// later execution.
95template <typename JITLayerT>
Andrew Walbran16937d02019-10-22 13:54:20 +010096class LegacyCtorDtorRunner {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010097public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +010098 /// Construct a CtorDtorRunner for the given range using the given
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010099 /// name mangling function.
Andrew Walbran16937d02019-10-22 13:54:20 +0100100 LegacyCtorDtorRunner(std::vector<std::string> CtorDtorNames, VModuleKey K)
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100101 : CtorDtorNames(std::move(CtorDtorNames)), K(K) {}
102
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100103 /// Run the recorded constructors/destructors through the given JIT
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100104 /// layer.
105 Error runViaLayer(JITLayerT &JITLayer) const {
106 using CtorDtorTy = void (*)();
107
108 for (const auto &CtorDtorName : CtorDtorNames) {
109 if (auto CtorDtorSym = JITLayer.findSymbolIn(K, CtorDtorName, false)) {
110 if (auto AddrOrErr = CtorDtorSym.getAddress()) {
111 CtorDtorTy CtorDtor =
112 reinterpret_cast<CtorDtorTy>(static_cast<uintptr_t>(*AddrOrErr));
113 CtorDtor();
114 } else
115 return AddrOrErr.takeError();
116 } else {
117 if (auto Err = CtorDtorSym.takeError())
118 return Err;
119 else
120 return make_error<JITSymbolNotFound>(CtorDtorName);
121 }
122 }
123 return Error::success();
124 }
125
126private:
127 std::vector<std::string> CtorDtorNames;
128 orc::VModuleKey K;
129};
130
Andrew Walbran16937d02019-10-22 13:54:20 +0100131class CtorDtorRunner {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100132public:
Andrew Walbran16937d02019-10-22 13:54:20 +0100133 CtorDtorRunner(JITDylib &JD) : JD(JD) {}
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100134 void add(iterator_range<CtorDtorIterator> CtorDtors);
135 Error run();
136
137private:
138 using CtorDtorList = std::vector<SymbolStringPtr>;
139 using CtorDtorPriorityMap = std::map<unsigned, CtorDtorList>;
140
Andrew Scull0372a572018-11-16 15:47:06 +0000141 JITDylib &JD;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100142 CtorDtorPriorityMap CtorDtorsByPriority;
143};
144
145/// Support class for static dtor execution. For hosted (in-process) JITs
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100146/// only!
147///
148/// If a __cxa_atexit function isn't found C++ programs that use static
149/// destructors will fail to link. However, we don't want to use the host
150/// process's __cxa_atexit, because it will schedule JIT'd destructors to run
151/// after the JIT has been torn down, which is no good. This class makes it easy
152/// to override __cxa_atexit (and the related __dso_handle).
153///
154/// To use, clients should manually call searchOverrides from their symbol
155/// resolver. This should generally be done after attempting symbol resolution
156/// inside the JIT, but before searching the host process's symbol table. When
157/// the client determines that destructors should be run (generally at JIT
158/// teardown or after a return from main), the runDestructors method should be
159/// called.
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100160class LocalCXXRuntimeOverridesBase {
161public:
162 /// Run any destructors recorded by the overriden __cxa_atexit function
163 /// (CXAAtExitOverride).
164 void runDestructors();
165
166protected:
167 template <typename PtrTy> JITTargetAddress toTargetAddress(PtrTy *P) {
168 return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(P));
169 }
170
171 using DestructorPtr = void (*)(void *);
172 using CXXDestructorDataPair = std::pair<DestructorPtr, void *>;
173 using CXXDestructorDataPairList = std::vector<CXXDestructorDataPair>;
174 CXXDestructorDataPairList DSOHandleOverride;
175 static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg,
176 void *DSOHandle);
177};
178
Andrew Walbran16937d02019-10-22 13:54:20 +0100179class LegacyLocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100180public:
181 /// Create a runtime-overrides class.
182 template <typename MangleFtorT>
Andrew Walbran16937d02019-10-22 13:54:20 +0100183 LegacyLocalCXXRuntimeOverrides(const MangleFtorT &Mangle) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100184 addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride));
185 addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride));
186 }
187
188 /// Search overrided symbols.
189 JITEvaluatedSymbol searchOverrides(const std::string &Name) {
190 auto I = CXXRuntimeOverrides.find(Name);
191 if (I != CXXRuntimeOverrides.end())
192 return JITEvaluatedSymbol(I->second, JITSymbolFlags::Exported);
193 return nullptr;
194 }
195
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100196private:
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100197 void addOverride(const std::string &Name, JITTargetAddress Addr) {
198 CXXRuntimeOverrides.insert(std::make_pair(Name, Addr));
199 }
200
201 StringMap<JITTargetAddress> CXXRuntimeOverrides;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100202};
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100203
Andrew Walbran16937d02019-10-22 13:54:20 +0100204class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100205public:
Andrew Scull0372a572018-11-16 15:47:06 +0000206 Error enable(JITDylib &JD, MangleAndInterner &Mangler);
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100207};
208
209/// A utility class to expose symbols found via dlsym to the JIT.
210///
Andrew Scull0372a572018-11-16 15:47:06 +0000211/// If an instance of this class is attached to a JITDylib as a fallback
212/// definition generator, then any symbol found in the given DynamicLibrary that
213/// passes the 'Allow' predicate will be added to the JITDylib.
Andrew Walbran16937d02019-10-22 13:54:20 +0100214class DynamicLibrarySearchGenerator {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100215public:
216 using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
Andrew Scull0372a572018-11-16 15:47:06 +0000217
Andrew Walbran16937d02019-10-22 13:54:20 +0100218 /// Create a DynamicLibrarySearchGenerator that searches for symbols in the
Andrew Scull0372a572018-11-16 15:47:06 +0000219 /// given sys::DynamicLibrary.
Andrew Walbran16937d02019-10-22 13:54:20 +0100220 /// If the Allow predicate is given then only symbols matching the predicate
221 /// will be searched for in the DynamicLibrary. If the predicate is not given
222 /// then all symbols will be searched for.
223 DynamicLibrarySearchGenerator(sys::DynamicLibrary Dylib, const DataLayout &DL,
224 SymbolPredicate Allow = SymbolPredicate());
Andrew Scull0372a572018-11-16 15:47:06 +0000225
226 /// Permanently loads the library at the given path and, on success, returns
Andrew Walbran16937d02019-10-22 13:54:20 +0100227 /// a DynamicLibrarySearchGenerator that will search it for symbol definitions
228 /// in the library. On failure returns the reason the library failed to load.
229 static Expected<DynamicLibrarySearchGenerator>
Andrew Scull0372a572018-11-16 15:47:06 +0000230 Load(const char *FileName, const DataLayout &DL,
Andrew Walbran16937d02019-10-22 13:54:20 +0100231 SymbolPredicate Allow = SymbolPredicate());
Andrew Scull0372a572018-11-16 15:47:06 +0000232
Andrew Walbran16937d02019-10-22 13:54:20 +0100233 /// Creates a DynamicLibrarySearchGenerator that searches for symbols in
Andrew Scull0372a572018-11-16 15:47:06 +0000234 /// the current process.
Andrew Walbran16937d02019-10-22 13:54:20 +0100235 static Expected<DynamicLibrarySearchGenerator>
236 GetForCurrentProcess(const DataLayout &DL,
237 SymbolPredicate Allow = SymbolPredicate()) {
Andrew Scull0372a572018-11-16 15:47:06 +0000238 return Load(nullptr, DL, std::move(Allow));
239 }
240
241 SymbolNameSet operator()(JITDylib &JD, const SymbolNameSet &Names);
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100242
243private:
244 sys::DynamicLibrary Dylib;
245 SymbolPredicate Allow;
246 char GlobalPrefix;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100247};
248
249} // end namespace orc
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100250} // end namespace llvm
251
252#endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H