File: | build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp |
Warning: | line 119, column 7 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===---- ExecutionUtils.cpp - Utilities for executing functions in Orc ---===// | ||||
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 | #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" | ||||
10 | #include "llvm/ExecutionEngine/Orc/Layer.h" | ||||
11 | #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" | ||||
12 | #include "llvm/IR/Constants.h" | ||||
13 | #include "llvm/IR/Function.h" | ||||
14 | #include "llvm/IR/GlobalVariable.h" | ||||
15 | #include "llvm/IR/Module.h" | ||||
16 | #include "llvm/MC/TargetRegistry.h" | ||||
17 | #include "llvm/Object/MachOUniversal.h" | ||||
18 | #include "llvm/Support/FormatVariadic.h" | ||||
19 | #include "llvm/Target/TargetMachine.h" | ||||
20 | #include <string> | ||||
21 | |||||
22 | namespace llvm { | ||||
23 | namespace orc { | ||||
24 | |||||
25 | CtorDtorIterator::CtorDtorIterator(const GlobalVariable *GV, bool End) | ||||
26 | : InitList( | ||||
27 | GV ? dyn_cast_or_null<ConstantArray>(GV->getInitializer()) : nullptr), | ||||
28 | I((InitList && End) ? InitList->getNumOperands() : 0) { | ||||
29 | } | ||||
30 | |||||
31 | bool CtorDtorIterator::operator==(const CtorDtorIterator &Other) const { | ||||
32 | assert(InitList == Other.InitList && "Incomparable iterators.")(static_cast <bool> (InitList == Other.InitList && "Incomparable iterators.") ? void (0) : __assert_fail ("InitList == Other.InitList && \"Incomparable iterators.\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 32, __extension__ __PRETTY_FUNCTION__)); | ||||
33 | return I == Other.I; | ||||
34 | } | ||||
35 | |||||
36 | bool CtorDtorIterator::operator!=(const CtorDtorIterator &Other) const { | ||||
37 | return !(*this == Other); | ||||
38 | } | ||||
39 | |||||
40 | CtorDtorIterator& CtorDtorIterator::operator++() { | ||||
41 | ++I; | ||||
42 | return *this; | ||||
43 | } | ||||
44 | |||||
45 | CtorDtorIterator CtorDtorIterator::operator++(int) { | ||||
46 | CtorDtorIterator Temp = *this; | ||||
47 | ++I; | ||||
48 | return Temp; | ||||
49 | } | ||||
50 | |||||
51 | CtorDtorIterator::Element CtorDtorIterator::operator*() const { | ||||
52 | ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(I)); | ||||
53 | assert(CS && "Unrecognized type in llvm.global_ctors/llvm.global_dtors")(static_cast <bool> (CS && "Unrecognized type in llvm.global_ctors/llvm.global_dtors" ) ? void (0) : __assert_fail ("CS && \"Unrecognized type in llvm.global_ctors/llvm.global_dtors\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 53, __extension__ __PRETTY_FUNCTION__)); | ||||
54 | |||||
55 | Constant *FuncC = CS->getOperand(1); | ||||
56 | Function *Func = nullptr; | ||||
57 | |||||
58 | // Extract function pointer, pulling off any casts. | ||||
59 | while (FuncC) { | ||||
60 | if (Function *F = dyn_cast_or_null<Function>(FuncC)) { | ||||
61 | Func = F; | ||||
62 | break; | ||||
63 | } else if (ConstantExpr *CE = dyn_cast_or_null<ConstantExpr>(FuncC)) { | ||||
64 | if (CE->isCast()) | ||||
65 | FuncC = CE->getOperand(0); | ||||
66 | else | ||||
67 | break; | ||||
68 | } else { | ||||
69 | // This isn't anything we recognize. Bail out with Func left set to null. | ||||
70 | break; | ||||
71 | } | ||||
72 | } | ||||
73 | |||||
74 | auto *Priority = cast<ConstantInt>(CS->getOperand(0)); | ||||
75 | Value *Data = CS->getNumOperands() == 3 ? CS->getOperand(2) : nullptr; | ||||
76 | if (Data
| ||||
77 | Data = nullptr; | ||||
78 | return Element(Priority->getZExtValue(), Func, Data); | ||||
79 | } | ||||
80 | |||||
81 | iterator_range<CtorDtorIterator> getConstructors(const Module &M) { | ||||
82 | const GlobalVariable *CtorsList = M.getNamedGlobal("llvm.global_ctors"); | ||||
83 | return make_range(CtorDtorIterator(CtorsList, false), | ||||
84 | CtorDtorIterator(CtorsList, true)); | ||||
85 | } | ||||
86 | |||||
87 | iterator_range<CtorDtorIterator> getDestructors(const Module &M) { | ||||
88 | const GlobalVariable *DtorsList = M.getNamedGlobal("llvm.global_dtors"); | ||||
89 | return make_range(CtorDtorIterator(DtorsList, false), | ||||
90 | CtorDtorIterator(DtorsList, true)); | ||||
91 | } | ||||
92 | |||||
93 | bool StaticInitGVIterator::isStaticInitGlobal(GlobalValue &GV) { | ||||
94 | if (GV.isDeclaration()) | ||||
95 | return false; | ||||
96 | |||||
97 | if (GV.hasName() && (GV.getName() == "llvm.global_ctors" || | ||||
98 | GV.getName() == "llvm.global_dtors")) | ||||
99 | return true; | ||||
100 | |||||
101 | if (ObjFmt == Triple::MachO) { | ||||
102 | // FIXME: These section checks are too strict: We should match first and | ||||
103 | // second word split by comma. | ||||
104 | if (GV.hasSection() && | ||||
105 | (GV.getSection().startswith("__DATA,__objc_classlist") || | ||||
106 | GV.getSection().startswith("__DATA,__objc_selrefs"))) | ||||
107 | return true; | ||||
108 | } | ||||
109 | |||||
110 | return false; | ||||
111 | } | ||||
112 | |||||
113 | void CtorDtorRunner::add(iterator_range<CtorDtorIterator> CtorDtors) { | ||||
114 | if (CtorDtors.empty()) | ||||
| |||||
115 | return; | ||||
116 | |||||
117 | MangleAndInterner Mangle( | ||||
118 | JD.getExecutionSession(), | ||||
119 | (*CtorDtors.begin()).Func->getParent()->getDataLayout()); | ||||
| |||||
120 | |||||
121 | for (auto CtorDtor : CtorDtors) { | ||||
122 | assert(CtorDtor.Func && CtorDtor.Func->hasName() &&(static_cast <bool> (CtorDtor.Func && CtorDtor. Func->hasName() && "Ctor/Dtor function must be named to be runnable under the JIT" ) ? void (0) : __assert_fail ("CtorDtor.Func && CtorDtor.Func->hasName() && \"Ctor/Dtor function must be named to be runnable under the JIT\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 123, __extension__ __PRETTY_FUNCTION__)) | ||||
123 | "Ctor/Dtor function must be named to be runnable under the JIT")(static_cast <bool> (CtorDtor.Func && CtorDtor. Func->hasName() && "Ctor/Dtor function must be named to be runnable under the JIT" ) ? void (0) : __assert_fail ("CtorDtor.Func && CtorDtor.Func->hasName() && \"Ctor/Dtor function must be named to be runnable under the JIT\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 123, __extension__ __PRETTY_FUNCTION__)); | ||||
124 | |||||
125 | // FIXME: Maybe use a symbol promoter here instead. | ||||
126 | if (CtorDtor.Func->hasLocalLinkage()) { | ||||
127 | CtorDtor.Func->setLinkage(GlobalValue::ExternalLinkage); | ||||
128 | CtorDtor.Func->setVisibility(GlobalValue::HiddenVisibility); | ||||
129 | } | ||||
130 | |||||
131 | if (CtorDtor.Data && cast<GlobalValue>(CtorDtor.Data)->isDeclaration()) { | ||||
132 | dbgs() << " Skipping because why now?\n"; | ||||
133 | continue; | ||||
134 | } | ||||
135 | |||||
136 | CtorDtorsByPriority[CtorDtor.Priority].push_back( | ||||
137 | Mangle(CtorDtor.Func->getName())); | ||||
138 | } | ||||
139 | } | ||||
140 | |||||
141 | Error CtorDtorRunner::run() { | ||||
142 | using CtorDtorTy = void (*)(); | ||||
143 | |||||
144 | SymbolLookupSet LookupSet; | ||||
145 | for (auto &KV : CtorDtorsByPriority) | ||||
146 | for (auto &Name : KV.second) | ||||
147 | LookupSet.add(Name); | ||||
148 | assert(!LookupSet.containsDuplicates() &&(static_cast <bool> (!LookupSet.containsDuplicates() && "Ctor/Dtor list contains duplicates") ? void (0) : __assert_fail ("!LookupSet.containsDuplicates() && \"Ctor/Dtor list contains duplicates\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 149, __extension__ __PRETTY_FUNCTION__)) | ||||
149 | "Ctor/Dtor list contains duplicates")(static_cast <bool> (!LookupSet.containsDuplicates() && "Ctor/Dtor list contains duplicates") ? void (0) : __assert_fail ("!LookupSet.containsDuplicates() && \"Ctor/Dtor list contains duplicates\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 149, __extension__ __PRETTY_FUNCTION__)); | ||||
150 | |||||
151 | auto &ES = JD.getExecutionSession(); | ||||
152 | if (auto CtorDtorMap = ES.lookup( | ||||
153 | makeJITDylibSearchOrder(&JD, JITDylibLookupFlags::MatchAllSymbols), | ||||
154 | std::move(LookupSet))) { | ||||
155 | for (auto &KV : CtorDtorsByPriority) { | ||||
156 | for (auto &Name : KV.second) { | ||||
157 | assert(CtorDtorMap->count(Name) && "No entry for Name")(static_cast <bool> (CtorDtorMap->count(Name) && "No entry for Name") ? void (0) : __assert_fail ("CtorDtorMap->count(Name) && \"No entry for Name\"" , "llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp", 157, __extension__ __PRETTY_FUNCTION__)); | ||||
158 | auto CtorDtor = reinterpret_cast<CtorDtorTy>( | ||||
159 | static_cast<uintptr_t>((*CtorDtorMap)[Name].getAddress())); | ||||
160 | CtorDtor(); | ||||
161 | } | ||||
162 | } | ||||
163 | CtorDtorsByPriority.clear(); | ||||
164 | return Error::success(); | ||||
165 | } else | ||||
166 | return CtorDtorMap.takeError(); | ||||
167 | } | ||||
168 | |||||
169 | void LocalCXXRuntimeOverridesBase::runDestructors() { | ||||
170 | auto& CXXDestructorDataPairs = DSOHandleOverride; | ||||
171 | for (auto &P : CXXDestructorDataPairs) | ||||
172 | P.first(P.second); | ||||
173 | CXXDestructorDataPairs.clear(); | ||||
174 | } | ||||
175 | |||||
176 | int LocalCXXRuntimeOverridesBase::CXAAtExitOverride(DestructorPtr Destructor, | ||||
177 | void *Arg, | ||||
178 | void *DSOHandle) { | ||||
179 | auto& CXXDestructorDataPairs = | ||||
180 | *reinterpret_cast<CXXDestructorDataPairList*>(DSOHandle); | ||||
181 | CXXDestructorDataPairs.push_back(std::make_pair(Destructor, Arg)); | ||||
182 | return 0; | ||||
183 | } | ||||
184 | |||||
185 | Error LocalCXXRuntimeOverrides::enable(JITDylib &JD, | ||||
186 | MangleAndInterner &Mangle) { | ||||
187 | SymbolMap RuntimeInterposes; | ||||
188 | RuntimeInterposes[Mangle("__dso_handle")] = | ||||
189 | JITEvaluatedSymbol(toTargetAddress(&DSOHandleOverride), | ||||
190 | JITSymbolFlags::Exported); | ||||
191 | RuntimeInterposes[Mangle("__cxa_atexit")] = | ||||
192 | JITEvaluatedSymbol(toTargetAddress(&CXAAtExitOverride), | ||||
193 | JITSymbolFlags::Exported); | ||||
194 | |||||
195 | return JD.define(absoluteSymbols(std::move(RuntimeInterposes))); | ||||
196 | } | ||||
197 | |||||
198 | void ItaniumCXAAtExitSupport::registerAtExit(void (*F)(void *), void *Ctx, | ||||
199 | void *DSOHandle) { | ||||
200 | std::lock_guard<std::mutex> Lock(AtExitsMutex); | ||||
201 | AtExitRecords[DSOHandle].push_back({F, Ctx}); | ||||
202 | } | ||||
203 | |||||
204 | void ItaniumCXAAtExitSupport::runAtExits(void *DSOHandle) { | ||||
205 | std::vector<AtExitRecord> AtExitsToRun; | ||||
206 | |||||
207 | { | ||||
208 | std::lock_guard<std::mutex> Lock(AtExitsMutex); | ||||
209 | auto I = AtExitRecords.find(DSOHandle); | ||||
210 | if (I != AtExitRecords.end()) { | ||||
211 | AtExitsToRun = std::move(I->second); | ||||
212 | AtExitRecords.erase(I); | ||||
213 | } | ||||
214 | } | ||||
215 | |||||
216 | while (!AtExitsToRun.empty()) { | ||||
217 | AtExitsToRun.back().F(AtExitsToRun.back().Ctx); | ||||
218 | AtExitsToRun.pop_back(); | ||||
219 | } | ||||
220 | } | ||||
221 | |||||
222 | DynamicLibrarySearchGenerator::DynamicLibrarySearchGenerator( | ||||
223 | sys::DynamicLibrary Dylib, char GlobalPrefix, SymbolPredicate Allow) | ||||
224 | : Dylib(std::move(Dylib)), Allow(std::move(Allow)), | ||||
225 | GlobalPrefix(GlobalPrefix) {} | ||||
226 | |||||
227 | Expected<std::unique_ptr<DynamicLibrarySearchGenerator>> | ||||
228 | DynamicLibrarySearchGenerator::Load(const char *FileName, char GlobalPrefix, | ||||
229 | SymbolPredicate Allow) { | ||||
230 | std::string ErrMsg; | ||||
231 | auto Lib = sys::DynamicLibrary::getPermanentLibrary(FileName, &ErrMsg); | ||||
232 | if (!Lib.isValid()) | ||||
233 | return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()); | ||||
234 | return std::make_unique<DynamicLibrarySearchGenerator>( | ||||
235 | std::move(Lib), GlobalPrefix, std::move(Allow)); | ||||
236 | } | ||||
237 | |||||
238 | Error DynamicLibrarySearchGenerator::tryToGenerate( | ||||
239 | LookupState &LS, LookupKind K, JITDylib &JD, | ||||
240 | JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { | ||||
241 | orc::SymbolMap NewSymbols; | ||||
242 | |||||
243 | bool HasGlobalPrefix = (GlobalPrefix != '\0'); | ||||
244 | |||||
245 | for (auto &KV : Symbols) { | ||||
246 | auto &Name = KV.first; | ||||
247 | |||||
248 | if ((*Name).empty()) | ||||
249 | continue; | ||||
250 | |||||
251 | if (Allow && !Allow(Name)) | ||||
252 | continue; | ||||
253 | |||||
254 | if (HasGlobalPrefix && (*Name).front() != GlobalPrefix) | ||||
255 | continue; | ||||
256 | |||||
257 | std::string Tmp((*Name).data() + HasGlobalPrefix, | ||||
258 | (*Name).size() - HasGlobalPrefix); | ||||
259 | if (void *Addr = Dylib.getAddressOfSymbol(Tmp.c_str())) { | ||||
260 | NewSymbols[Name] = JITEvaluatedSymbol( | ||||
261 | static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(Addr)), | ||||
262 | JITSymbolFlags::Exported); | ||||
263 | } | ||||
264 | } | ||||
265 | |||||
266 | if (NewSymbols.empty()) | ||||
267 | return Error::success(); | ||||
268 | |||||
269 | return JD.define(absoluteSymbols(std::move(NewSymbols))); | ||||
270 | } | ||||
271 | |||||
272 | Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> | ||||
273 | StaticLibraryDefinitionGenerator::Load( | ||||
274 | ObjectLayer &L, const char *FileName, | ||||
275 | GetObjectFileInterface GetObjFileInterface) { | ||||
276 | auto ArchiveBuffer = MemoryBuffer::getFile(FileName); | ||||
277 | |||||
278 | if (!ArchiveBuffer) | ||||
279 | return createFileError(FileName, ArchiveBuffer.getError()); | ||||
280 | |||||
281 | return Create(L, std::move(*ArchiveBuffer), std::move(GetObjFileInterface)); | ||||
282 | } | ||||
283 | |||||
284 | Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> | ||||
285 | StaticLibraryDefinitionGenerator::Load( | ||||
286 | ObjectLayer &L, const char *FileName, const Triple &TT, | ||||
287 | GetObjectFileInterface GetObjFileInterface) { | ||||
288 | |||||
289 | auto B = object::createBinary(FileName); | ||||
290 | if (!B) | ||||
291 | return createFileError(FileName, B.takeError()); | ||||
292 | |||||
293 | // If this is a regular archive then create an instance from it. | ||||
294 | if (isa<object::Archive>(B->getBinary())) | ||||
295 | return Create(L, std::move(B->takeBinary().second), | ||||
296 | std::move(GetObjFileInterface)); | ||||
297 | |||||
298 | // If this is a universal binary then search for a slice matching the given | ||||
299 | // Triple. | ||||
300 | if (auto *UB = cast<object::MachOUniversalBinary>(B->getBinary())) { | ||||
301 | for (const auto &Obj : UB->objects()) { | ||||
302 | auto ObjTT = Obj.getTriple(); | ||||
303 | if (ObjTT.getArch() == TT.getArch() && | ||||
304 | ObjTT.getSubArch() == TT.getSubArch() && | ||||
305 | (TT.getVendor() == Triple::UnknownVendor || | ||||
306 | ObjTT.getVendor() == TT.getVendor())) { | ||||
307 | // We found a match. Create an instance from a buffer covering this | ||||
308 | // slice. | ||||
309 | auto SliceBuffer = MemoryBuffer::getFileSlice(FileName, Obj.getSize(), | ||||
310 | Obj.getOffset()); | ||||
311 | if (!SliceBuffer) | ||||
312 | return make_error<StringError>( | ||||
313 | Twine("Could not create buffer for ") + TT.str() + " slice of " + | ||||
314 | FileName + ": [ " + formatv("{0:x}", Obj.getOffset()) + | ||||
315 | " .. " + formatv("{0:x}", Obj.getOffset() + Obj.getSize()) + | ||||
316 | ": " + SliceBuffer.getError().message(), | ||||
317 | SliceBuffer.getError()); | ||||
318 | return Create(L, std::move(*SliceBuffer), | ||||
319 | std::move(GetObjFileInterface)); | ||||
320 | } | ||||
321 | } | ||||
322 | |||||
323 | return make_error<StringError>(Twine("Universal binary ") + FileName + | ||||
324 | " does not contain a slice for " + | ||||
325 | TT.str(), | ||||
326 | inconvertibleErrorCode()); | ||||
327 | } | ||||
328 | |||||
329 | return make_error<StringError>(Twine("Unrecognized file type for ") + | ||||
330 | FileName, | ||||
331 | inconvertibleErrorCode()); | ||||
332 | } | ||||
333 | |||||
334 | Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> | ||||
335 | StaticLibraryDefinitionGenerator::Create( | ||||
336 | ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, | ||||
337 | GetObjectFileInterface GetObjFileInterface) { | ||||
338 | Error Err = Error::success(); | ||||
339 | |||||
340 | std::unique_ptr<StaticLibraryDefinitionGenerator> ADG( | ||||
341 | new StaticLibraryDefinitionGenerator( | ||||
342 | L, std::move(ArchiveBuffer), std::move(GetObjFileInterface), Err)); | ||||
343 | |||||
344 | if (Err) | ||||
345 | return std::move(Err); | ||||
346 | |||||
347 | return std::move(ADG); | ||||
348 | } | ||||
349 | |||||
350 | Error StaticLibraryDefinitionGenerator::tryToGenerate( | ||||
351 | LookupState &LS, LookupKind K, JITDylib &JD, | ||||
352 | JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) { | ||||
353 | |||||
354 | // Don't materialize symbols from static archives unless this is a static | ||||
355 | // lookup. | ||||
356 | if (K != LookupKind::Static) | ||||
357 | return Error::success(); | ||||
358 | |||||
359 | // Bail out early if we've already freed the archive. | ||||
360 | if (!Archive) | ||||
361 | return Error::success(); | ||||
362 | |||||
363 | DenseSet<std::pair<StringRef, StringRef>> ChildBufferInfos; | ||||
364 | |||||
365 | for (const auto &KV : Symbols) { | ||||
366 | const auto &Name = KV.first; | ||||
367 | auto Child = Archive->findSym(*Name); | ||||
368 | if (!Child) | ||||
369 | return Child.takeError(); | ||||
370 | if (*Child == None) | ||||
371 | continue; | ||||
372 | auto ChildBuffer = (*Child)->getMemoryBufferRef(); | ||||
373 | if (!ChildBuffer) | ||||
374 | return ChildBuffer.takeError(); | ||||
375 | ChildBufferInfos.insert( | ||||
376 | {ChildBuffer->getBuffer(), ChildBuffer->getBufferIdentifier()}); | ||||
377 | } | ||||
378 | |||||
379 | for (auto ChildBufferInfo : ChildBufferInfos) { | ||||
380 | MemoryBufferRef ChildBufferRef(ChildBufferInfo.first, | ||||
381 | ChildBufferInfo.second); | ||||
382 | |||||
383 | auto I = GetObjFileInterface(L.getExecutionSession(), ChildBufferRef); | ||||
384 | if (!I) | ||||
385 | return I.takeError(); | ||||
386 | |||||
387 | if (auto Err = L.add(JD, MemoryBuffer::getMemBuffer(ChildBufferRef, false), | ||||
388 | std::move(*I))) | ||||
389 | return Err; | ||||
390 | } | ||||
391 | |||||
392 | return Error::success(); | ||||
393 | } | ||||
394 | |||||
395 | StaticLibraryDefinitionGenerator::StaticLibraryDefinitionGenerator( | ||||
396 | ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, | ||||
397 | GetObjectFileInterface GetObjFileInterface, Error &Err) | ||||
398 | : L(L), GetObjFileInterface(std::move(GetObjFileInterface)), | ||||
399 | ArchiveBuffer(std::move(ArchiveBuffer)), | ||||
400 | Archive(std::make_unique<object::Archive>(*this->ArchiveBuffer, Err)) { | ||||
401 | |||||
402 | if (!this->GetObjFileInterface) | ||||
403 | this->GetObjFileInterface = getObjectFileInterface; | ||||
404 | } | ||||
405 | |||||
406 | } // End namespace orc. | ||||
407 | } // End namespace llvm. |
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/Shared/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 <utility> |
28 | #include <vector> |
29 | |
30 | namespace llvm { |
31 | |
32 | class ConstantArray; |
33 | class GlobalVariable; |
34 | class Function; |
35 | class Module; |
36 | class Value; |
37 | |
38 | namespace orc { |
39 | |
40 | class ObjectLayer; |
41 | |
42 | /// This iterator provides a convenient way to iterate over the elements |
43 | /// of an llvm.global_ctors/llvm.global_dtors instance. |
44 | /// |
45 | /// The easiest way to get hold of instances of this class is to use the |
46 | /// getConstructors/getDestructors functions. |
47 | class CtorDtorIterator { |
48 | public: |
49 | /// Accessor for an element of the global_ctors/global_dtors array. |
50 | /// |
51 | /// This class provides a read-only view of the element with any casts on |
52 | /// the function stripped away. |
53 | struct Element { |
54 | Element(unsigned Priority, Function *Func, Value *Data) |
55 | : Priority(Priority), Func(Func), Data(Data) {} |
56 | |
57 | unsigned Priority; |
58 | Function *Func; |
59 | Value *Data; |
60 | }; |
61 | |
62 | /// Construct an iterator instance. If End is true then this iterator |
63 | /// acts as the end of the range, otherwise it is the beginning. |
64 | CtorDtorIterator(const GlobalVariable *GV, bool End); |
65 | |
66 | /// Test iterators for equality. |
67 | bool operator==(const CtorDtorIterator &Other) const; |
68 | |
69 | /// Test iterators for inequality. |
70 | bool operator!=(const CtorDtorIterator &Other) const; |
71 | |
72 | /// Pre-increment iterator. |
73 | CtorDtorIterator& operator++(); |
74 | |
75 | /// Post-increment iterator. |
76 | CtorDtorIterator operator++(int); |
77 | |
78 | /// Dereference iterator. The resulting value provides a read-only view |
79 | /// of this element of the global_ctors/global_dtors list. |
80 | Element operator*() const; |
81 | |
82 | private: |
83 | const ConstantArray *InitList; |
84 | unsigned I; |
85 | }; |
86 | |
87 | /// Create an iterator range over the entries of the llvm.global_ctors |
88 | /// array. |
89 | iterator_range<CtorDtorIterator> getConstructors(const Module &M); |
90 | |
91 | /// Create an iterator range over the entries of the llvm.global_ctors |
92 | /// array. |
93 | iterator_range<CtorDtorIterator> getDestructors(const Module &M); |
94 | |
95 | /// This iterator provides a convenient way to iterate over GlobalValues that |
96 | /// have initialization effects. |
97 | class StaticInitGVIterator { |
98 | public: |
99 | StaticInitGVIterator() = default; |
100 | |
101 | StaticInitGVIterator(Module &M) |
102 | : I(M.global_values().begin()), E(M.global_values().end()), |
103 | ObjFmt(Triple(M.getTargetTriple()).getObjectFormat()) { |
104 | if (I != E) { |
105 | if (!isStaticInitGlobal(*I)) |
106 | moveToNextStaticInitGlobal(); |
107 | } else |
108 | I = E = Module::global_value_iterator(); |
109 | } |
110 | |
111 | bool operator==(const StaticInitGVIterator &O) const { return I == O.I; } |
112 | bool operator!=(const StaticInitGVIterator &O) const { return I != O.I; } |
113 | |
114 | StaticInitGVIterator &operator++() { |
115 | assert(I != E && "Increment past end of range")(static_cast <bool> (I != E && "Increment past end of range" ) ? void (0) : __assert_fail ("I != E && \"Increment past end of range\"" , "llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h", 115 , __extension__ __PRETTY_FUNCTION__)); |
116 | moveToNextStaticInitGlobal(); |
117 | return *this; |
118 | } |
119 | |
120 | GlobalValue &operator*() { return *I; } |
121 | |
122 | private: |
123 | bool isStaticInitGlobal(GlobalValue &GV); |
124 | void moveToNextStaticInitGlobal() { |
125 | ++I; |
126 | while (I != E && !isStaticInitGlobal(*I)) |
127 | ++I; |
128 | if (I == E) |
129 | I = E = Module::global_value_iterator(); |
130 | } |
131 | |
132 | Module::global_value_iterator I, E; |
133 | Triple::ObjectFormatType ObjFmt; |
134 | }; |
135 | |
136 | /// Create an iterator range over the GlobalValues that contribute to static |
137 | /// initialization. |
138 | inline iterator_range<StaticInitGVIterator> getStaticInitGVs(Module &M) { |
139 | return make_range(StaticInitGVIterator(M), StaticInitGVIterator()); |
140 | } |
141 | |
142 | class CtorDtorRunner { |
143 | public: |
144 | CtorDtorRunner(JITDylib &JD) : JD(JD) {} |
145 | void add(iterator_range<CtorDtorIterator> CtorDtors); |
146 | Error run(); |
147 | |
148 | private: |
149 | using CtorDtorList = std::vector<SymbolStringPtr>; |
150 | using CtorDtorPriorityMap = std::map<unsigned, CtorDtorList>; |
151 | |
152 | JITDylib &JD; |
153 | CtorDtorPriorityMap CtorDtorsByPriority; |
154 | }; |
155 | |
156 | /// Support class for static dtor execution. For hosted (in-process) JITs |
157 | /// only! |
158 | /// |
159 | /// If a __cxa_atexit function isn't found C++ programs that use static |
160 | /// destructors will fail to link. However, we don't want to use the host |
161 | /// process's __cxa_atexit, because it will schedule JIT'd destructors to run |
162 | /// after the JIT has been torn down, which is no good. This class makes it easy |
163 | /// to override __cxa_atexit (and the related __dso_handle). |
164 | /// |
165 | /// To use, clients should manually call searchOverrides from their symbol |
166 | /// resolver. This should generally be done after attempting symbol resolution |
167 | /// inside the JIT, but before searching the host process's symbol table. When |
168 | /// the client determines that destructors should be run (generally at JIT |
169 | /// teardown or after a return from main), the runDestructors method should be |
170 | /// called. |
171 | class LocalCXXRuntimeOverridesBase { |
172 | public: |
173 | /// Run any destructors recorded by the overriden __cxa_atexit function |
174 | /// (CXAAtExitOverride). |
175 | void runDestructors(); |
176 | |
177 | protected: |
178 | template <typename PtrTy> JITTargetAddress toTargetAddress(PtrTy *P) { |
179 | return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(P)); |
180 | } |
181 | |
182 | using DestructorPtr = void (*)(void *); |
183 | using CXXDestructorDataPair = std::pair<DestructorPtr, void *>; |
184 | using CXXDestructorDataPairList = std::vector<CXXDestructorDataPair>; |
185 | CXXDestructorDataPairList DSOHandleOverride; |
186 | static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg, |
187 | void *DSOHandle); |
188 | }; |
189 | |
190 | class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase { |
191 | public: |
192 | Error enable(JITDylib &JD, MangleAndInterner &Mangler); |
193 | }; |
194 | |
195 | /// An interface for Itanium __cxa_atexit interposer implementations. |
196 | class ItaniumCXAAtExitSupport { |
197 | public: |
198 | struct AtExitRecord { |
199 | void (*F)(void *); |
200 | void *Ctx; |
201 | }; |
202 | |
203 | void registerAtExit(void (*F)(void *), void *Ctx, void *DSOHandle); |
204 | void runAtExits(void *DSOHandle); |
205 | |
206 | private: |
207 | std::mutex AtExitsMutex; |
208 | DenseMap<void *, std::vector<AtExitRecord>> AtExitRecords; |
209 | }; |
210 | |
211 | /// A utility class to expose symbols found via dlsym to the JIT. |
212 | /// |
213 | /// If an instance of this class is attached to a JITDylib as a fallback |
214 | /// definition generator, then any symbol found in the given DynamicLibrary that |
215 | /// passes the 'Allow' predicate will be added to the JITDylib. |
216 | class DynamicLibrarySearchGenerator : public DefinitionGenerator { |
217 | public: |
218 | using SymbolPredicate = std::function<bool(const SymbolStringPtr &)>; |
219 | |
220 | /// Create a DynamicLibrarySearchGenerator that searches for symbols in the |
221 | /// given sys::DynamicLibrary. |
222 | /// |
223 | /// If the Allow predicate is given then only symbols matching the predicate |
224 | /// will be searched for. If the predicate is not given then all symbols will |
225 | /// be searched for. |
226 | DynamicLibrarySearchGenerator(sys::DynamicLibrary Dylib, char GlobalPrefix, |
227 | SymbolPredicate Allow = SymbolPredicate()); |
228 | |
229 | /// Permanently loads the library at the given path and, on success, returns |
230 | /// a DynamicLibrarySearchGenerator that will search it for symbol definitions |
231 | /// in the library. On failure returns the reason the library failed to load. |
232 | static Expected<std::unique_ptr<DynamicLibrarySearchGenerator>> |
233 | Load(const char *FileName, char GlobalPrefix, |
234 | SymbolPredicate Allow = SymbolPredicate()); |
235 | |
236 | /// Creates a DynamicLibrarySearchGenerator that searches for symbols in |
237 | /// the current process. |
238 | static Expected<std::unique_ptr<DynamicLibrarySearchGenerator>> |
239 | GetForCurrentProcess(char GlobalPrefix, |
240 | SymbolPredicate Allow = SymbolPredicate()) { |
241 | return Load(nullptr, GlobalPrefix, std::move(Allow)); |
242 | } |
243 | |
244 | Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
245 | JITDylibLookupFlags JDLookupFlags, |
246 | const SymbolLookupSet &Symbols) override; |
247 | |
248 | private: |
249 | sys::DynamicLibrary Dylib; |
250 | SymbolPredicate Allow; |
251 | char GlobalPrefix; |
252 | }; |
253 | |
254 | /// A utility class to expose symbols from a static library. |
255 | /// |
256 | /// If an instance of this class is attached to a JITDylib as a fallback |
257 | /// definition generator, then any symbol found in the archive will result in |
258 | /// the containing object being added to the JITDylib. |
259 | class StaticLibraryDefinitionGenerator : public DefinitionGenerator { |
260 | public: |
261 | // Interface builder function for objects loaded from this archive. |
262 | using GetObjectFileInterface = |
263 | unique_function<Expected<MaterializationUnit::Interface>( |
264 | ExecutionSession &ES, MemoryBufferRef ObjBuffer)>; |
265 | |
266 | /// Try to create a StaticLibraryDefinitionGenerator from the given path. |
267 | /// |
268 | /// This call will succeed if the file at the given path is a static library |
269 | /// is a valid archive, otherwise it will return an error. |
270 | static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> |
271 | Load(ObjectLayer &L, const char *FileName, |
272 | GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); |
273 | |
274 | /// Try to create a StaticLibraryDefinitionGenerator from the given path. |
275 | /// |
276 | /// This call will succeed if the file at the given path is a static library |
277 | /// or a MachO universal binary containing a static library that is compatible |
278 | /// with the given triple. Otherwise it will return an error. |
279 | static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> |
280 | Load(ObjectLayer &L, const char *FileName, const Triple &TT, |
281 | GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); |
282 | |
283 | /// Try to create a StaticLibrarySearchGenerator from the given memory buffer. |
284 | /// This call will succeed if the buffer contains a valid archive, otherwise |
285 | /// it will return an error. |
286 | static Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> |
287 | Create(ObjectLayer &L, std::unique_ptr<MemoryBuffer> ArchiveBuffer, |
288 | GetObjectFileInterface GetObjFileInterface = GetObjectFileInterface()); |
289 | |
290 | Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
291 | JITDylibLookupFlags JDLookupFlags, |
292 | const SymbolLookupSet &Symbols) override; |
293 | |
294 | private: |
295 | StaticLibraryDefinitionGenerator(ObjectLayer &L, |
296 | std::unique_ptr<MemoryBuffer> ArchiveBuffer, |
297 | GetObjectFileInterface GetObjFileInterface, |
298 | Error &Err); |
299 | |
300 | ObjectLayer &L; |
301 | GetObjectFileInterface GetObjFileInterface; |
302 | std::unique_ptr<MemoryBuffer> ArchiveBuffer; |
303 | std::unique_ptr<object::Archive> Archive; |
304 | }; |
305 | |
306 | } // end namespace orc |
307 | } // end namespace llvm |
308 | |
309 | #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H |