1 | //===- llvm-jitlink.cpp -- Command line interface/tester for llvm-jitlink -===// |
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 | // This utility provides a simple command line interface to the llvm jitlink |
10 | // library, which makes relocatable object files executable in memory. Its |
11 | // primary function is as a testing utility for the jitlink library. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "llvm-jitlink.h" |
16 | #include "llvm/BinaryFormat/Magic.h" |
17 | #include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX, LLVM_ENABLE_THREADS |
18 | #include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h" |
19 | #include "llvm/ExecutionEngine/Orc/COFFPlatform.h" |
20 | #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" |
21 | #include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h" |
22 | #include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupportPlugin.h" |
23 | #include "llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h" |
24 | #include "llvm/ExecutionEngine/Orc/Debugging/VTuneSupportPlugin.h" |
25 | #include "llvm/ExecutionEngine/Orc/EHFrameRegistrationPlugin.h" |
26 | #include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h" |
27 | #include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h" |
28 | #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h" |
29 | #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" |
30 | #include "llvm/ExecutionEngine/Orc/GetDylibInterface.h" |
31 | #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" |
32 | #include "llvm/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.h" |
33 | #include "llvm/ExecutionEngine/Orc/JITLinkReentryTrampolines.h" |
34 | #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" |
35 | #include "llvm/ExecutionEngine/Orc/LoadLinkableFile.h" |
36 | #include "llvm/ExecutionEngine/Orc/MachO.h" |
37 | #include "llvm/ExecutionEngine/Orc/MachOPlatform.h" |
38 | #include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h" |
39 | #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" |
40 | #include "llvm/ExecutionEngine/Orc/SectCreate.h" |
41 | #include "llvm/ExecutionEngine/Orc/SelfExecutorProcessControl.h" |
42 | #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" |
43 | #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" |
44 | #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderPerf.h" |
45 | #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.h" |
46 | #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" |
47 | #include "llvm/ExecutionEngine/Orc/UnwindInfoRegistrationPlugin.h" |
48 | #include "llvm/MC/MCAsmInfo.h" |
49 | #include "llvm/MC/MCContext.h" |
50 | #include "llvm/MC/MCDisassembler/MCDisassembler.h" |
51 | #include "llvm/MC/MCInstPrinter.h" |
52 | #include "llvm/MC/MCInstrAnalysis.h" |
53 | #include "llvm/MC/MCInstrInfo.h" |
54 | #include "llvm/MC/MCRegisterInfo.h" |
55 | #include "llvm/MC/MCSubtargetInfo.h" |
56 | #include "llvm/MC/MCTargetOptions.h" |
57 | #include "llvm/MC/TargetRegistry.h" |
58 | #include "llvm/Object/COFF.h" |
59 | #include "llvm/Object/MachO.h" |
60 | #include "llvm/Object/ObjectFile.h" |
61 | #include "llvm/Object/TapiUniversal.h" |
62 | #include "llvm/Support/CommandLine.h" |
63 | #include "llvm/Support/Debug.h" |
64 | #include "llvm/Support/InitLLVM.h" |
65 | #include "llvm/Support/MemoryBuffer.h" |
66 | #include "llvm/Support/Path.h" |
67 | #include "llvm/Support/Process.h" |
68 | #include "llvm/Support/TargetSelect.h" |
69 | #include "llvm/Support/Timer.h" |
70 | #include <cstring> |
71 | #include <deque> |
72 | #include <string> |
73 | |
74 | #ifdef LLVM_ON_UNIX |
75 | #include <netdb.h> |
76 | #include <netinet/in.h> |
77 | #include <sys/socket.h> |
78 | #include <unistd.h> |
79 | #endif // LLVM_ON_UNIX |
80 | |
81 | #define DEBUG_TYPE "llvm_jitlink" |
82 | |
83 | using namespace llvm; |
84 | using namespace llvm::jitlink; |
85 | using namespace llvm::orc; |
86 | |
87 | static cl::OptionCategory JITLinkCategory("JITLink Options" ); |
88 | |
89 | static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore, |
90 | cl::desc("input files" ), |
91 | cl::cat(JITLinkCategory)); |
92 | |
93 | static cl::list<bool> LazyLink("lazy" , |
94 | cl::desc("Link the following file lazily" ), |
95 | cl::cat(JITLinkCategory)); |
96 | |
97 | enum class SpeculateKind { None, Simple }; |
98 | |
99 | static cl::opt<SpeculateKind> Speculate( |
100 | "speculate" , cl::desc("Choose speculation scheme" ), |
101 | cl::init(Val: SpeculateKind::None), |
102 | cl::values(clEnumValN(SpeculateKind::None, "none" , "No speculation" ), |
103 | clEnumValN(SpeculateKind::Simple, "simple" , |
104 | "Simple speculation" )), |
105 | cl::cat(JITLinkCategory)); |
106 | |
107 | static cl::opt<std::string> SpeculateOrder( |
108 | "speculate-order" , |
109 | cl::desc("A CSV file containing (JITDylib, Function) pairs to" |
110 | "speculatively look up" ), |
111 | cl::cat(JITLinkCategory)); |
112 | |
113 | static cl::opt<std::string> RecordLazyExecs( |
114 | "record-lazy-execs" , |
115 | cl::desc("Write lazy-function executions to a CSV file as (JITDylib, " |
116 | "function) pairs" ), |
117 | cl::cat(JITLinkCategory)); |
118 | |
119 | static cl::opt<size_t> MaterializationThreads( |
120 | "num-threads" , cl::desc("Number of materialization threads to use" ), |
121 | cl::init(Val: std::numeric_limits<size_t>::max()), cl::cat(JITLinkCategory)); |
122 | |
123 | static cl::list<std::string> |
124 | LibrarySearchPaths("L" , |
125 | cl::desc("Add dir to the list of library search paths" ), |
126 | cl::Prefix, cl::cat(JITLinkCategory)); |
127 | |
128 | static cl::list<std::string> |
129 | Libraries("l" , |
130 | cl::desc("Link against library X in the library search paths" ), |
131 | cl::Prefix, cl::cat(JITLinkCategory)); |
132 | |
133 | static cl::list<std::string> |
134 | LibrariesHidden("hidden-l" , |
135 | cl::desc("Link against library X in the library search " |
136 | "paths with hidden visibility" ), |
137 | cl::Prefix, cl::cat(JITLinkCategory)); |
138 | |
139 | static cl::list<std::string> |
140 | LoadHidden("load_hidden" , |
141 | cl::desc("Link against library X with hidden visibility" ), |
142 | cl::cat(JITLinkCategory)); |
143 | |
144 | static cl::list<std::string> |
145 | LibrariesWeak("weak-l" , |
146 | cl::desc("Emulate weak link against library X. Must resolve " |
147 | "to a TextAPI file, and all symbols in the " |
148 | "interface will resolve to null." ), |
149 | cl::Prefix, cl::cat(JITLinkCategory)); |
150 | |
151 | static cl::list<std::string> WeakLibraries( |
152 | "weak_library" , |
153 | cl::desc("Emulate weak link against library X. X must point to a " |
154 | "TextAPI file, and all symbols in the interface will " |
155 | "resolve to null" ), |
156 | cl::cat(JITLinkCategory)); |
157 | |
158 | static cl::opt<bool> SearchSystemLibrary( |
159 | "search-sys-lib" , |
160 | cl::desc("Add system library paths to library search paths" ), |
161 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
162 | |
163 | static cl::opt<bool> NoExec("noexec" , cl::desc("Do not execute loaded code" ), |
164 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
165 | |
166 | static cl::list<std::string> |
167 | CheckFiles("check" , cl::desc("File containing verifier checks" ), |
168 | cl::cat(JITLinkCategory)); |
169 | |
170 | static cl::opt<std::string> |
171 | CheckName("check-name" , cl::desc("Name of checks to match against" ), |
172 | cl::init(Val: "jitlink-check" ), cl::cat(JITLinkCategory)); |
173 | |
174 | static cl::opt<std::string> |
175 | EntryPointName("entry" , cl::desc("Symbol to call as main entry point" ), |
176 | cl::init(Val: "" ), cl::cat(JITLinkCategory)); |
177 | |
178 | static cl::list<std::string> JITDylibs( |
179 | "jd" , |
180 | cl::desc("Specifies the JITDylib to be used for any subsequent " |
181 | "input file, -L<seacrh-path>, and -l<library> arguments" ), |
182 | cl::cat(JITLinkCategory)); |
183 | |
184 | static cl::list<std::string> |
185 | Dylibs("preload" , |
186 | cl::desc("Pre-load dynamic libraries (e.g. language runtimes " |
187 | "required by the ORC runtime)" ), |
188 | cl::cat(JITLinkCategory)); |
189 | |
190 | static cl::list<std::string> InputArgv("args" , cl::Positional, |
191 | cl::desc("<program arguments>..." ), |
192 | cl::PositionalEatsArgs, |
193 | cl::cat(JITLinkCategory)); |
194 | |
195 | static cl::opt<bool> |
196 | DebuggerSupport("debugger-support" , |
197 | cl::desc("Enable debugger suppport (default = !-noexec)" ), |
198 | cl::init(Val: true), cl::Hidden, cl::cat(JITLinkCategory)); |
199 | |
200 | static cl::opt<bool> PerfSupport("perf-support" , |
201 | cl::desc("Enable perf profiling support" ), |
202 | cl::init(Val: false), cl::Hidden, |
203 | cl::cat(JITLinkCategory)); |
204 | |
205 | static cl::opt<bool> VTuneSupport("vtune-support" , |
206 | cl::desc("Enable vtune profiling support" ), |
207 | cl::init(Val: false), cl::Hidden, |
208 | cl::cat(JITLinkCategory)); |
209 | static cl::opt<bool> |
210 | NoProcessSymbols("no-process-syms" , |
211 | cl::desc("Do not resolve to llvm-jitlink process symbols" ), |
212 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
213 | |
214 | static cl::list<std::string> AbsoluteDefs( |
215 | "abs" , |
216 | cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)" ), |
217 | cl::cat(JITLinkCategory)); |
218 | |
219 | static cl::list<std::string> |
220 | Aliases("alias" , |
221 | cl::desc("Inject symbol aliases (syntax: <alias-name>=<aliasee>)" ), |
222 | cl::cat(JITLinkCategory)); |
223 | |
224 | static cl::list<std::string> |
225 | SectCreate("sectcreate" , |
226 | cl::desc("given <sectname>,<filename>[@<sym>=<offset>,...] " |
227 | "add the content of <filename> to <sectname>" ), |
228 | cl::cat(JITLinkCategory)); |
229 | |
230 | static cl::list<std::string> TestHarnesses("harness" , cl::Positional, |
231 | cl::desc("Test harness files" ), |
232 | cl::PositionalEatsArgs, |
233 | cl::cat(JITLinkCategory)); |
234 | |
235 | static cl::opt<bool> |
236 | ShowLinkedFiles("show-linked-files" , |
237 | cl::desc("List each file/graph name if/when it is linked" ), |
238 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
239 | |
240 | static cl::opt<bool> ShowInitialExecutionSessionState( |
241 | "show-init-es" , |
242 | cl::desc("Print ExecutionSession state before resolving entry point" ), |
243 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
244 | |
245 | static cl::opt<bool> ShowEntryExecutionSessionState( |
246 | "show-entry-es" , |
247 | cl::desc("Print ExecutionSession state after resolving entry point" ), |
248 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
249 | |
250 | static cl::opt<bool> ShowAddrs( |
251 | "show-addrs" , |
252 | cl::desc("Print registered symbol, section, got and stub addresses" ), |
253 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
254 | |
255 | static cl::opt<std::string> ShowLinkGraphs( |
256 | "show-graphs" , |
257 | cl::desc("Takes a posix regex and prints the link graphs of all files " |
258 | "matching that regex after fixups have been applied" ), |
259 | cl::Optional, cl::cat(JITLinkCategory)); |
260 | |
261 | static cl::opt<bool> ShowTimes("show-times" , |
262 | cl::desc("Show times for llvm-jitlink phases" ), |
263 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
264 | |
265 | static cl::opt<std::string> SlabAllocateSizeString( |
266 | "slab-allocate" , |
267 | cl::desc("Allocate from a slab of the given size " |
268 | "(allowable suffixes: Kb, Mb, Gb. default = " |
269 | "Kb)" ), |
270 | cl::init(Val: "" ), cl::cat(JITLinkCategory)); |
271 | |
272 | static cl::opt<uint64_t> SlabAddress( |
273 | "slab-address" , |
274 | cl::desc("Set slab target address (requires -slab-allocate and -noexec)" ), |
275 | cl::init(Val: ~0ULL), cl::cat(JITLinkCategory)); |
276 | |
277 | static cl::opt<uint64_t> SlabPageSize( |
278 | "slab-page-size" , |
279 | cl::desc("Set page size for slab (requires -slab-allocate and -noexec)" ), |
280 | cl::init(Val: 0), cl::cat(JITLinkCategory)); |
281 | |
282 | static cl::opt<bool> ShowRelocatedSectionContents( |
283 | "show-relocated-section-contents" , |
284 | cl::desc("show section contents after fixups have been applied" ), |
285 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
286 | |
287 | static cl::opt<bool> PhonyExternals( |
288 | "phony-externals" , |
289 | cl::desc("resolve all otherwise unresolved externals to null" ), |
290 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
291 | |
292 | static cl::opt<std::string> OutOfProcessExecutor( |
293 | "oop-executor" , cl::desc("Launch an out-of-process executor to run code" ), |
294 | cl::ValueOptional, cl::cat(JITLinkCategory)); |
295 | |
296 | static cl::opt<std::string> OutOfProcessExecutorConnect( |
297 | "oop-executor-connect" , |
298 | cl::desc("Connect to an out-of-process executor via TCP" ), |
299 | cl::cat(JITLinkCategory)); |
300 | |
301 | static cl::opt<std::string> |
302 | OrcRuntime("orc-runtime" , cl::desc("Use ORC runtime from given path" ), |
303 | cl::init(Val: "" ), cl::cat(JITLinkCategory)); |
304 | |
305 | static cl::opt<bool> AddSelfRelocations( |
306 | "add-self-relocations" , |
307 | cl::desc("Add relocations to function pointers to the current function" ), |
308 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
309 | |
310 | static cl::opt<bool> |
311 | ShowErrFailedToMaterialize("show-err-failed-to-materialize" , |
312 | cl::desc("Show FailedToMaterialize errors" ), |
313 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
314 | |
315 | static cl::opt<bool> UseSharedMemory( |
316 | "use-shared-memory" , |
317 | cl::desc("Use shared memory to transfer generated code and data" ), |
318 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
319 | |
320 | static cl::opt<std::string> |
321 | OverrideTriple("triple" , cl::desc("Override target triple detection" ), |
322 | cl::init(Val: "" ), cl::cat(JITLinkCategory)); |
323 | |
324 | static cl::opt<bool> AllLoad("all_load" , |
325 | cl::desc("Load all members of static archives" ), |
326 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
327 | |
328 | static cl::opt<bool> ForceLoadObjC( |
329 | "ObjC" , |
330 | cl::desc("Load all members of static archives that implement " |
331 | "Objective-C classes or categories, or Swift structs, " |
332 | "classes or extensions" ), |
333 | cl::init(Val: false), cl::cat(JITLinkCategory)); |
334 | |
335 | static ExitOnError ExitOnErr; |
336 | |
337 | static LLVM_ATTRIBUTE_USED void linkComponents() { |
338 | errs() << "Linking in runtime functions\n" |
339 | << (void *)&llvm_orc_registerEHFrameSectionAllocAction << '\n' |
340 | << (void *)&llvm_orc_deregisterEHFrameSectionAllocAction << '\n' |
341 | << (void *)&llvm_orc_registerJITLoaderGDBWrapper << '\n' |
342 | << (void *)&llvm_orc_registerJITLoaderGDBAllocAction << '\n' |
343 | << (void *)&llvm_orc_registerJITLoaderPerfStart << '\n' |
344 | << (void *)&llvm_orc_registerJITLoaderPerfEnd << '\n' |
345 | << (void *)&llvm_orc_registerJITLoaderPerfImpl << '\n' |
346 | << (void *)&llvm_orc_registerVTuneImpl << '\n' |
347 | << (void *)&llvm_orc_unregisterVTuneImpl << '\n' |
348 | << (void *)&llvm_orc_test_registerVTuneImpl << '\n'; |
349 | } |
350 | |
351 | static bool UseTestResultOverride = false; |
352 | static int64_t TestResultOverride = 0; |
353 | |
354 | extern "C" LLVM_ATTRIBUTE_USED void |
355 | llvm_jitlink_setTestResultOverride(int64_t Value) { |
356 | TestResultOverride = Value; |
357 | UseTestResultOverride = true; |
358 | } |
359 | |
360 | static Error addSelfRelocations(LinkGraph &G); |
361 | |
362 | namespace { |
363 | |
364 | template <typename ErrT> |
365 | |
366 | class ConditionalPrintErr { |
367 | public: |
368 | ConditionalPrintErr(bool C) : C(C) {} |
369 | void operator()(ErrT &EI) { |
370 | if (C) { |
371 | errs() << "llvm-jitlink error: " ; |
372 | EI.log(errs()); |
373 | errs() << "\n" ; |
374 | } |
375 | } |
376 | |
377 | private: |
378 | bool C; |
379 | }; |
380 | |
381 | Expected<std::unique_ptr<MemoryBuffer>> getFile(const Twine &FileName) { |
382 | if (auto F = MemoryBuffer::getFile(Filename: FileName)) |
383 | return std::move(*F); |
384 | else |
385 | return createFileError(F: FileName, EC: F.getError()); |
386 | } |
387 | |
388 | void reportLLVMJITLinkError(Error Err) { |
389 | handleAllErrors( |
390 | E: std::move(Err), |
391 | Handlers: ConditionalPrintErr<orc::FailedToMaterialize>(ShowErrFailedToMaterialize), |
392 | Handlers: ConditionalPrintErr<ErrorInfoBase>(true)); |
393 | } |
394 | |
395 | } // end anonymous namespace |
396 | |
397 | namespace llvm { |
398 | |
399 | static raw_ostream & |
400 | operator<<(raw_ostream &OS, const Session::MemoryRegionInfo &MRI) { |
401 | return OS << "target addr = " |
402 | << format(Fmt: "0x%016" PRIx64, Vals: MRI.getTargetAddress()) |
403 | << ", content: " << (const void *)MRI.getContent().data() << " -- " |
404 | << (const void *)(MRI.getContent().data() + MRI.getContent().size()) |
405 | << " (" << MRI.getContent().size() << " bytes)" ; |
406 | } |
407 | |
408 | static raw_ostream & |
409 | operator<<(raw_ostream &OS, const Session::SymbolInfoMap &SIM) { |
410 | OS << "Symbols:\n" ; |
411 | for (auto &SKV : SIM) |
412 | OS << " \"" << SKV.first << "\" " << SKV.second << "\n" ; |
413 | return OS; |
414 | } |
415 | |
416 | static raw_ostream & |
417 | operator<<(raw_ostream &OS, const Session::FileInfo &FI) { |
418 | for (auto &SIKV : FI.SectionInfos) |
419 | OS << " Section \"" << SIKV.first() << "\": " << SIKV.second << "\n" ; |
420 | for (auto &GOTKV : FI.GOTEntryInfos) |
421 | OS << " GOT \"" << GOTKV.first() << "\": " << GOTKV.second << "\n" ; |
422 | for (auto &StubKVs : FI.StubInfos) { |
423 | OS << " Stubs \"" << StubKVs.first() << "\":" ; |
424 | for (auto MemRegion : StubKVs.second) |
425 | OS << " " << MemRegion; |
426 | OS << "\n" ; |
427 | } |
428 | return OS; |
429 | } |
430 | |
431 | static raw_ostream & |
432 | operator<<(raw_ostream &OS, const Session::FileInfoMap &FIM) { |
433 | for (auto &FIKV : FIM) |
434 | OS << "File \"" << FIKV.first() << "\":\n" << FIKV.second; |
435 | return OS; |
436 | } |
437 | |
438 | bool lazyLinkingRequested() { |
439 | for (auto LL : LazyLink) |
440 | if (LL) |
441 | return true; |
442 | return false; |
443 | } |
444 | |
445 | static Error applyLibraryLinkModifiers(Session &S, LinkGraph &G) { |
446 | // If there are hidden archives and this graph is an archive |
447 | // member then apply hidden modifier. |
448 | if (!S.HiddenArchives.empty()) { |
449 | StringRef ObjName(G.getName()); |
450 | if (ObjName.ends_with(Suffix: ')')) { |
451 | auto LibName = ObjName.split(Separator: '[').first; |
452 | if (S.HiddenArchives.count(Key: LibName)) { |
453 | for (auto *Sym : G.defined_symbols()) |
454 | Sym->setScope(std::max(a: Sym->getScope(), b: Scope::Hidden)); |
455 | } |
456 | } |
457 | } |
458 | |
459 | return Error::success(); |
460 | } |
461 | |
462 | static Error applyHarnessPromotions(Session &S, LinkGraph &G) { |
463 | std::lock_guard<std::mutex> Lock(S.M); |
464 | |
465 | // If this graph is part of the test harness there's nothing to do. |
466 | if (S.HarnessFiles.empty() || S.HarnessFiles.count(Key: G.getName())) |
467 | return Error::success(); |
468 | |
469 | LLVM_DEBUG(dbgs() << "Applying promotions to graph " << G.getName() << "\n" ); |
470 | |
471 | // If this graph is part of the test then promote any symbols referenced by |
472 | // the harness to default scope, remove all symbols that clash with harness |
473 | // definitions. |
474 | std::vector<Symbol *> DefinitionsToRemove; |
475 | for (auto *Sym : G.defined_symbols()) { |
476 | |
477 | if (!Sym->hasName()) |
478 | continue; |
479 | |
480 | if (Sym->getLinkage() == Linkage::Weak) { |
481 | auto It = S.CanonicalWeakDefs.find(Val: *Sym->getName()); |
482 | if (It == S.CanonicalWeakDefs.end() || It->second != G.getName()) { |
483 | LLVM_DEBUG({ |
484 | dbgs() << " Externalizing weak symbol " << Sym->getName() << "\n" ; |
485 | }); |
486 | DefinitionsToRemove.push_back(x: Sym); |
487 | } else { |
488 | LLVM_DEBUG({ |
489 | dbgs() << " Making weak symbol " << Sym->getName() << " strong\n" ; |
490 | }); |
491 | if (S.HarnessExternals.count(Key: *Sym->getName())) |
492 | Sym->setScope(Scope::Default); |
493 | else |
494 | Sym->setScope(Scope::Hidden); |
495 | Sym->setLinkage(Linkage::Strong); |
496 | } |
497 | } else if (S.HarnessExternals.count(Key: *Sym->getName())) { |
498 | LLVM_DEBUG(dbgs() << " Promoting " << Sym->getName() << "\n" ); |
499 | Sym->setScope(Scope::Default); |
500 | Sym->setLive(true); |
501 | continue; |
502 | } else if (S.HarnessDefinitions.count(Key: *Sym->getName())) { |
503 | LLVM_DEBUG(dbgs() << " Externalizing " << Sym->getName() << "\n" ); |
504 | DefinitionsToRemove.push_back(x: Sym); |
505 | } |
506 | } |
507 | |
508 | for (auto *Sym : DefinitionsToRemove) |
509 | G.makeExternal(Sym&: *Sym); |
510 | |
511 | return Error::success(); |
512 | } |
513 | |
514 | static void dumpSectionContents(raw_ostream &OS, Session &S, LinkGraph &G) { |
515 | std::lock_guard<std::mutex> Lock(S.M); |
516 | |
517 | outs() << "Relocated section contents for " << G.getName() << ":\n" ; |
518 | |
519 | constexpr orc::ExecutorAddrDiff DumpWidth = 16; |
520 | static_assert(isPowerOf2_64(Value: DumpWidth), "DumpWidth must be a power of two" ); |
521 | |
522 | // Put sections in address order. |
523 | std::vector<Section *> Sections; |
524 | for (auto &S : G.sections()) |
525 | Sections.push_back(x: &S); |
526 | |
527 | llvm::sort(C&: Sections, Comp: [](const Section *LHS, const Section *RHS) { |
528 | if (LHS->symbols().empty() && RHS->symbols().empty()) |
529 | return false; |
530 | if (LHS->symbols().empty()) |
531 | return false; |
532 | if (RHS->symbols().empty()) |
533 | return true; |
534 | SectionRange LHSRange(*LHS); |
535 | SectionRange RHSRange(*RHS); |
536 | return LHSRange.getStart() < RHSRange.getStart(); |
537 | }); |
538 | |
539 | for (auto *S : Sections) { |
540 | OS << S->getName() << " content:" ; |
541 | if (S->symbols().empty()) { |
542 | OS << "\n section empty\n" ; |
543 | continue; |
544 | } |
545 | |
546 | // Sort symbols into order, then render. |
547 | std::vector<Symbol *> Syms(S->symbols().begin(), S->symbols().end()); |
548 | llvm::sort(C&: Syms, Comp: [](const Symbol *LHS, const Symbol *RHS) { |
549 | return LHS->getAddress() < RHS->getAddress(); |
550 | }); |
551 | |
552 | orc::ExecutorAddr NextAddr(Syms.front()->getAddress().getValue() & |
553 | ~(DumpWidth - 1)); |
554 | for (auto *Sym : Syms) { |
555 | bool IsZeroFill = Sym->getBlock().isZeroFill(); |
556 | auto SymStart = Sym->getAddress(); |
557 | auto SymSize = Sym->getSize(); |
558 | auto SymEnd = SymStart + SymSize; |
559 | const uint8_t *SymData = IsZeroFill ? nullptr |
560 | : reinterpret_cast<const uint8_t *>( |
561 | Sym->getSymbolContent().data()); |
562 | |
563 | // Pad any space before the symbol starts. |
564 | while (NextAddr != SymStart) { |
565 | if (NextAddr % DumpWidth == 0) |
566 | OS << formatv(Fmt: "\n{0:x16}:" , Vals&: NextAddr); |
567 | OS << " " ; |
568 | ++NextAddr; |
569 | } |
570 | |
571 | // Render the symbol content. |
572 | while (NextAddr != SymEnd) { |
573 | if (NextAddr % DumpWidth == 0) |
574 | OS << formatv(Fmt: "\n{0:x16}:" , Vals&: NextAddr); |
575 | if (IsZeroFill) |
576 | OS << " 00" ; |
577 | else |
578 | OS << formatv(Fmt: " {0:x-2}" , Vals: SymData[NextAddr - SymStart]); |
579 | ++NextAddr; |
580 | } |
581 | } |
582 | OS << "\n" ; |
583 | } |
584 | } |
585 | |
586 | // A memory mapper with a fake offset applied only used for -noexec testing |
587 | class InProcessDeltaMapper final : public InProcessMemoryMapper { |
588 | public: |
589 | InProcessDeltaMapper(size_t PageSize, uint64_t TargetAddr) |
590 | : InProcessMemoryMapper(PageSize), TargetMapAddr(TargetAddr), |
591 | DeltaAddr(0) {} |
592 | |
593 | static Expected<std::unique_ptr<InProcessDeltaMapper>> Create() { |
594 | size_t PageSize = SlabPageSize; |
595 | if (!PageSize) { |
596 | if (auto PageSizeOrErr = sys::Process::getPageSize()) |
597 | PageSize = *PageSizeOrErr; |
598 | else |
599 | return PageSizeOrErr.takeError(); |
600 | } |
601 | |
602 | if (PageSize == 0) |
603 | return make_error<StringError>(Args: "Page size is zero" , |
604 | Args: inconvertibleErrorCode()); |
605 | |
606 | return std::make_unique<InProcessDeltaMapper>(args&: PageSize, args&: SlabAddress); |
607 | } |
608 | |
609 | void reserve(size_t NumBytes, OnReservedFunction OnReserved) override { |
610 | InProcessMemoryMapper::reserve( |
611 | NumBytes, OnReserved: [this, OnReserved = std::move(OnReserved)]( |
612 | Expected<ExecutorAddrRange> Result) mutable { |
613 | if (!Result) |
614 | return OnReserved(Result.takeError()); |
615 | |
616 | assert(DeltaAddr == 0 && "Overwriting previous offset" ); |
617 | if (TargetMapAddr != ~0ULL) |
618 | DeltaAddr = TargetMapAddr - Result->Start.getValue(); |
619 | auto OffsetRange = ExecutorAddrRange(Result->Start + DeltaAddr, |
620 | Result->End + DeltaAddr); |
621 | |
622 | OnReserved(OffsetRange); |
623 | }); |
624 | } |
625 | |
626 | char *prepare(ExecutorAddr Addr, size_t ContentSize) override { |
627 | return InProcessMemoryMapper::prepare(Addr: Addr - DeltaAddr, ContentSize); |
628 | } |
629 | |
630 | void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override { |
631 | // Slide mapping based on delta, make all segments read-writable, and |
632 | // discard allocation actions. |
633 | auto FixedAI = std::move(AI); |
634 | FixedAI.MappingBase -= DeltaAddr; |
635 | for (auto &Seg : FixedAI.Segments) |
636 | Seg.AG = {MemProt::Read | MemProt::Write, Seg.AG.getMemLifetime()}; |
637 | FixedAI.Actions.clear(); |
638 | InProcessMemoryMapper::initialize( |
639 | AI&: FixedAI, OnInitialized: [this, OnInitialized = std::move(OnInitialized)]( |
640 | Expected<ExecutorAddr> Result) mutable { |
641 | if (!Result) |
642 | return OnInitialized(Result.takeError()); |
643 | |
644 | OnInitialized(ExecutorAddr(Result->getValue() + DeltaAddr)); |
645 | }); |
646 | } |
647 | |
648 | void deinitialize(ArrayRef<ExecutorAddr> Allocations, |
649 | OnDeinitializedFunction OnDeInitialized) override { |
650 | std::vector<ExecutorAddr> Addrs(Allocations.size()); |
651 | for (const auto Base : Allocations) { |
652 | Addrs.push_back(x: Base - DeltaAddr); |
653 | } |
654 | |
655 | InProcessMemoryMapper::deinitialize(Allocations: Addrs, OnDeInitialized: std::move(OnDeInitialized)); |
656 | } |
657 | |
658 | void release(ArrayRef<ExecutorAddr> Reservations, |
659 | OnReleasedFunction OnRelease) override { |
660 | std::vector<ExecutorAddr> Addrs(Reservations.size()); |
661 | for (const auto Base : Reservations) { |
662 | Addrs.push_back(x: Base - DeltaAddr); |
663 | } |
664 | InProcessMemoryMapper::release(Reservations: Addrs, OnRelease: std::move(OnRelease)); |
665 | } |
666 | |
667 | private: |
668 | uint64_t TargetMapAddr; |
669 | uint64_t DeltaAddr; |
670 | }; |
671 | |
672 | Expected<uint64_t> getSlabAllocSize(StringRef SizeString) { |
673 | SizeString = SizeString.trim(); |
674 | |
675 | uint64_t Units = 1024; |
676 | |
677 | if (SizeString.ends_with_insensitive(Suffix: "kb" )) |
678 | SizeString = SizeString.drop_back(N: 2).rtrim(); |
679 | else if (SizeString.ends_with_insensitive(Suffix: "mb" )) { |
680 | Units = 1024 * 1024; |
681 | SizeString = SizeString.drop_back(N: 2).rtrim(); |
682 | } else if (SizeString.ends_with_insensitive(Suffix: "gb" )) { |
683 | Units = 1024 * 1024 * 1024; |
684 | SizeString = SizeString.drop_back(N: 2).rtrim(); |
685 | } |
686 | |
687 | uint64_t SlabSize = 0; |
688 | if (SizeString.getAsInteger(Radix: 10, Result&: SlabSize)) |
689 | return make_error<StringError>(Args: "Invalid numeric format for slab size" , |
690 | Args: inconvertibleErrorCode()); |
691 | |
692 | return SlabSize * Units; |
693 | } |
694 | |
695 | static std::unique_ptr<JITLinkMemoryManager> createInProcessMemoryManager() { |
696 | uint64_t SlabSize; |
697 | #ifdef _WIN32 |
698 | SlabSize = 1024 * 1024; |
699 | #else |
700 | SlabSize = 1024 * 1024 * 1024; |
701 | #endif |
702 | |
703 | if (!SlabAllocateSizeString.empty()) |
704 | SlabSize = ExitOnErr(getSlabAllocSize(SizeString: SlabAllocateSizeString)); |
705 | |
706 | // If this is a -no-exec case and we're tweaking the slab address or size then |
707 | // use the delta mapper. |
708 | if (NoExec && (SlabAddress || SlabPageSize)) |
709 | return ExitOnErr( |
710 | MapperJITLinkMemoryManager::CreateWithMapper<InProcessDeltaMapper>( |
711 | ReservationGranularity: SlabSize)); |
712 | |
713 | // Otherwise use the standard in-process mapper. |
714 | return ExitOnErr( |
715 | MapperJITLinkMemoryManager::CreateWithMapper<InProcessMemoryMapper>( |
716 | ReservationGranularity: SlabSize)); |
717 | } |
718 | |
719 | Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>> |
720 | createSharedMemoryManager(SimpleRemoteEPC &SREPC) { |
721 | SharedMemoryMapper::SymbolAddrs SAs; |
722 | if (auto Err = SREPC.getBootstrapSymbols( |
723 | Pairs: {{SAs.Instance, rt::ExecutorSharedMemoryMapperServiceInstanceName}, |
724 | {SAs.Reserve, |
725 | rt::ExecutorSharedMemoryMapperServiceReserveWrapperName}, |
726 | {SAs.Initialize, |
727 | rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName}, |
728 | {SAs.Deinitialize, |
729 | rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName}, |
730 | {SAs.Release, |
731 | rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName}})) |
732 | return std::move(Err); |
733 | |
734 | #ifdef _WIN32 |
735 | size_t SlabSize = 1024 * 1024; |
736 | #else |
737 | size_t SlabSize = 1024 * 1024 * 1024; |
738 | #endif |
739 | |
740 | if (!SlabAllocateSizeString.empty()) |
741 | SlabSize = ExitOnErr(getSlabAllocSize(SizeString: SlabAllocateSizeString)); |
742 | |
743 | return MapperJITLinkMemoryManager::CreateWithMapper<SharedMemoryMapper>( |
744 | ReservationGranularity: SlabSize, A&: SREPC, A&: SAs); |
745 | } |
746 | |
747 | |
748 | static Expected<MaterializationUnit::Interface> |
749 | getTestObjectFileInterface(Session &S, MemoryBufferRef O) { |
750 | |
751 | // Get the standard interface for this object, but ignore the symbols field. |
752 | // We'll handle that manually to include promotion. |
753 | auto I = getObjectFileInterface(ES&: S.ES, ObjBuffer: O); |
754 | if (!I) |
755 | return I.takeError(); |
756 | I->SymbolFlags.clear(); |
757 | |
758 | // If creating an object file was going to fail it would have happened above, |
759 | // so we can 'cantFail' this. |
760 | auto Obj = cantFail(ValOrErr: object::ObjectFile::createObjectFile(Object: O)); |
761 | |
762 | // The init symbol must be included in the SymbolFlags map if present. |
763 | if (I->InitSymbol) |
764 | I->SymbolFlags[I->InitSymbol] = |
765 | JITSymbolFlags::MaterializationSideEffectsOnly; |
766 | |
767 | for (auto &Sym : Obj->symbols()) { |
768 | Expected<uint32_t> SymFlagsOrErr = Sym.getFlags(); |
769 | if (!SymFlagsOrErr) |
770 | // TODO: Test this error. |
771 | return SymFlagsOrErr.takeError(); |
772 | |
773 | // Skip symbols not defined in this object file. |
774 | if ((*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined)) |
775 | continue; |
776 | |
777 | auto Name = Sym.getName(); |
778 | if (!Name) |
779 | return Name.takeError(); |
780 | |
781 | // Skip symbols that have type SF_File. |
782 | if (auto SymType = Sym.getType()) { |
783 | if (*SymType == object::SymbolRef::ST_File) |
784 | continue; |
785 | } else |
786 | return SymType.takeError(); |
787 | |
788 | auto SymFlags = JITSymbolFlags::fromObjectSymbol(Symbol: Sym); |
789 | if (!SymFlags) |
790 | return SymFlags.takeError(); |
791 | |
792 | if (SymFlags->isWeak()) { |
793 | // If this is a weak symbol that's not defined in the harness then we |
794 | // need to either mark it as strong (if this is the first definition |
795 | // that we've seen) or discard it. |
796 | if (S.HarnessDefinitions.count(Key: *Name) || S.CanonicalWeakDefs.count(Val: *Name)) |
797 | continue; |
798 | S.CanonicalWeakDefs[*Name] = O.getBufferIdentifier(); |
799 | *SymFlags &= ~JITSymbolFlags::Weak; |
800 | if (!S.HarnessExternals.count(Key: *Name)) |
801 | *SymFlags &= ~JITSymbolFlags::Exported; |
802 | } else if (S.HarnessExternals.count(Key: *Name)) { |
803 | *SymFlags |= JITSymbolFlags::Exported; |
804 | } else if (S.HarnessDefinitions.count(Key: *Name) || |
805 | !(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) |
806 | continue; |
807 | |
808 | I->SymbolFlags[S.ES.intern(SymName: *Name)] = std::move(*SymFlags); |
809 | } |
810 | |
811 | return I; |
812 | } |
813 | |
814 | static Error loadProcessSymbols(Session &S) { |
815 | S.ProcessSymsJD = &S.ES.createBareJITDylib(Name: "Process" ); |
816 | auto FilterMainEntryPoint = |
817 | [EPName = S.ES.intern(SymName: EntryPointName)](SymbolStringPtr Name) { |
818 | return Name != EPName; |
819 | }; |
820 | S.ProcessSymsJD->addGenerator( |
821 | DefGenerator: ExitOnErr(orc::EPCDynamicLibrarySearchGenerator::GetForTargetProcess( |
822 | ES&: S.ES, Allow: std::move(FilterMainEntryPoint)))); |
823 | |
824 | return Error::success(); |
825 | } |
826 | |
827 | static Error loadDylibs(Session &S) { |
828 | LLVM_DEBUG(dbgs() << "Loading dylibs...\n" ); |
829 | for (const auto &Dylib : Dylibs) { |
830 | LLVM_DEBUG(dbgs() << " " << Dylib << "\n" ); |
831 | auto DL = S.getOrLoadDynamicLibrary(LibPath: Dylib); |
832 | if (!DL) |
833 | return DL.takeError(); |
834 | } |
835 | |
836 | return Error::success(); |
837 | } |
838 | |
839 | static Expected<std::unique_ptr<ExecutorProcessControl>> launchExecutor() { |
840 | #ifndef LLVM_ON_UNIX |
841 | // FIXME: Add support for Windows. |
842 | return make_error<StringError>("-" + OutOfProcessExecutor.ArgStr + |
843 | " not supported on non-unix platforms" , |
844 | inconvertibleErrorCode()); |
845 | #elif !LLVM_ENABLE_THREADS |
846 | // Out of process mode using SimpleRemoteEPC depends on threads. |
847 | return make_error<StringError>( |
848 | "-" + OutOfProcessExecutor.ArgStr + |
849 | " requires threads, but LLVM was built with " |
850 | "LLVM_ENABLE_THREADS=Off" , |
851 | inconvertibleErrorCode()); |
852 | #else |
853 | |
854 | constexpr int ReadEnd = 0; |
855 | constexpr int WriteEnd = 1; |
856 | |
857 | // Pipe FDs. |
858 | int ToExecutor[2]; |
859 | int FromExecutor[2]; |
860 | |
861 | pid_t ChildPID; |
862 | |
863 | // Create pipes to/from the executor.. |
864 | if (pipe(pipedes: ToExecutor) != 0 || pipe(pipedes: FromExecutor) != 0) |
865 | return make_error<StringError>(Args: "Unable to create pipe for executor" , |
866 | Args: inconvertibleErrorCode()); |
867 | |
868 | ChildPID = fork(); |
869 | |
870 | if (ChildPID == 0) { |
871 | // In the child... |
872 | |
873 | // Close the parent ends of the pipes |
874 | close(fd: ToExecutor[WriteEnd]); |
875 | close(fd: FromExecutor[ReadEnd]); |
876 | |
877 | // Execute the child process. |
878 | std::unique_ptr<char[]> ExecutorPath, FDSpecifier; |
879 | { |
880 | ExecutorPath = std::make_unique<char[]>(num: OutOfProcessExecutor.size() + 1); |
881 | strcpy(dest: ExecutorPath.get(), src: OutOfProcessExecutor.data()); |
882 | |
883 | std::string FDSpecifierStr("filedescs=" ); |
884 | FDSpecifierStr += utostr(X: ToExecutor[ReadEnd]); |
885 | FDSpecifierStr += ','; |
886 | FDSpecifierStr += utostr(X: FromExecutor[WriteEnd]); |
887 | FDSpecifier = std::make_unique<char[]>(num: FDSpecifierStr.size() + 1); |
888 | strcpy(dest: FDSpecifier.get(), src: FDSpecifierStr.c_str()); |
889 | } |
890 | |
891 | char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr}; |
892 | int RC = execvp(file: ExecutorPath.get(), argv: Args); |
893 | if (RC != 0) { |
894 | errs() << "unable to launch out-of-process executor \"" |
895 | << ExecutorPath.get() << "\"\n" ; |
896 | exit(status: 1); |
897 | } |
898 | } |
899 | // else we're the parent... |
900 | |
901 | // Close the child ends of the pipes |
902 | close(fd: ToExecutor[ReadEnd]); |
903 | close(fd: FromExecutor[WriteEnd]); |
904 | |
905 | auto S = SimpleRemoteEPC::Setup(); |
906 | if (UseSharedMemory) |
907 | S.CreateMemoryManager = createSharedMemoryManager; |
908 | |
909 | return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>( |
910 | D: std::make_unique<DynamicThreadPoolTaskDispatcher>(args&: MaterializationThreads), |
911 | S: std::move(S), TransportTCtorArgs&: FromExecutor[ReadEnd], TransportTCtorArgs&: ToExecutor[WriteEnd]); |
912 | #endif |
913 | } |
914 | |
915 | #if LLVM_ON_UNIX && LLVM_ENABLE_THREADS |
916 | static Error createTCPSocketError(Twine Details) { |
917 | return make_error<StringError>( |
918 | Args: formatv(Fmt: "Failed to connect TCP socket '{0}': {1}" , |
919 | Vals&: OutOfProcessExecutorConnect, Vals&: Details), |
920 | Args: inconvertibleErrorCode()); |
921 | } |
922 | |
923 | static Expected<int> connectTCPSocket(std::string Host, std::string PortStr) { |
924 | addrinfo *AI; |
925 | addrinfo Hints{}; |
926 | Hints.ai_family = AF_INET; |
927 | Hints.ai_socktype = SOCK_STREAM; |
928 | Hints.ai_flags = AI_NUMERICSERV; |
929 | |
930 | if (int EC = getaddrinfo(name: Host.c_str(), service: PortStr.c_str(), req: &Hints, pai: &AI)) |
931 | return createTCPSocketError(Details: "Address resolution failed (" + |
932 | StringRef(gai_strerror(ecode: EC)) + ")" ); |
933 | |
934 | // Cycle through the returned addrinfo structures and connect to the first |
935 | // reachable endpoint. |
936 | int SockFD; |
937 | addrinfo *Server; |
938 | for (Server = AI; Server != nullptr; Server = Server->ai_next) { |
939 | // socket might fail, e.g. if the address family is not supported. Skip to |
940 | // the next addrinfo structure in such a case. |
941 | if ((SockFD = socket(domain: AI->ai_family, type: AI->ai_socktype, protocol: AI->ai_protocol)) < 0) |
942 | continue; |
943 | |
944 | // If connect returns null, we exit the loop with a working socket. |
945 | if (connect(fd: SockFD, addr: Server->ai_addr, len: Server->ai_addrlen) == 0) |
946 | break; |
947 | |
948 | close(fd: SockFD); |
949 | } |
950 | freeaddrinfo(ai: AI); |
951 | |
952 | // If we reached the end of the loop without connecting to a valid endpoint, |
953 | // dump the last error that was logged in socket() or connect(). |
954 | if (Server == nullptr) |
955 | return createTCPSocketError(Details: std::strerror(errno)); |
956 | |
957 | return SockFD; |
958 | } |
959 | #endif |
960 | |
961 | static Expected<std::unique_ptr<ExecutorProcessControl>> connectToExecutor() { |
962 | #ifndef LLVM_ON_UNIX |
963 | // FIXME: Add TCP support for Windows. |
964 | return make_error<StringError>("-" + OutOfProcessExecutorConnect.ArgStr + |
965 | " not supported on non-unix platforms" , |
966 | inconvertibleErrorCode()); |
967 | #elif !LLVM_ENABLE_THREADS |
968 | // Out of process mode using SimpleRemoteEPC depends on threads. |
969 | return make_error<StringError>( |
970 | "-" + OutOfProcessExecutorConnect.ArgStr + |
971 | " requires threads, but LLVM was built with " |
972 | "LLVM_ENABLE_THREADS=Off" , |
973 | inconvertibleErrorCode()); |
974 | #else |
975 | |
976 | StringRef Host, PortStr; |
977 | std::tie(args&: Host, args&: PortStr) = StringRef(OutOfProcessExecutorConnect).split(Separator: ':'); |
978 | if (Host.empty()) |
979 | return createTCPSocketError(Details: "Host name for -" + |
980 | OutOfProcessExecutorConnect.ArgStr + |
981 | " can not be empty" ); |
982 | if (PortStr.empty()) |
983 | return createTCPSocketError(Details: "Port number in -" + |
984 | OutOfProcessExecutorConnect.ArgStr + |
985 | " can not be empty" ); |
986 | int Port = 0; |
987 | if (PortStr.getAsInteger(Radix: 10, Result&: Port)) |
988 | return createTCPSocketError(Details: "Port number '" + PortStr + |
989 | "' is not a valid integer" ); |
990 | |
991 | Expected<int> SockFD = connectTCPSocket(Host: Host.str(), PortStr: PortStr.str()); |
992 | if (!SockFD) |
993 | return SockFD.takeError(); |
994 | |
995 | auto S = SimpleRemoteEPC::Setup(); |
996 | if (UseSharedMemory) |
997 | S.CreateMemoryManager = createSharedMemoryManager; |
998 | |
999 | return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>( |
1000 | D: std::make_unique<DynamicThreadPoolTaskDispatcher>(args: std::nullopt), |
1001 | S: std::move(S), TransportTCtorArgs&: *SockFD, TransportTCtorArgs&: *SockFD); |
1002 | #endif |
1003 | } |
1004 | |
1005 | class PhonyExternalsGenerator : public DefinitionGenerator { |
1006 | public: |
1007 | Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, |
1008 | JITDylibLookupFlags JDLookupFlags, |
1009 | const SymbolLookupSet &LookupSet) override { |
1010 | SymbolMap PhonySymbols; |
1011 | for (auto &KV : LookupSet) |
1012 | PhonySymbols[KV.first] = {ExecutorAddr(), JITSymbolFlags::Exported}; |
1013 | return JD.define(MU: absoluteSymbols(Symbols: std::move(PhonySymbols))); |
1014 | } |
1015 | }; |
1016 | |
1017 | Expected<std::unique_ptr<Session::LazyLinkingSupport>> |
1018 | createLazyLinkingSupport(Session &S) { |
1019 | auto RSMgr = JITLinkRedirectableSymbolManager::Create(ObjLinkingLayer&: S.ObjLayer); |
1020 | if (!RSMgr) |
1021 | return RSMgr.takeError(); |
1022 | |
1023 | std::shared_ptr<SimpleLazyReexportsSpeculator> Speculator; |
1024 | switch (Speculate) { |
1025 | case SpeculateKind::None: |
1026 | break; |
1027 | case SpeculateKind::Simple: |
1028 | SimpleLazyReexportsSpeculator::RecordExecutionFunction RecordExecs; |
1029 | |
1030 | if (!RecordLazyExecs.empty()) |
1031 | RecordExecs = [&S](const LazyReexportsManager::CallThroughInfo &CTI) { |
1032 | S.LazyFnExecOrder.push_back(x: {CTI.JD->getName(), CTI.BodyName}); |
1033 | }; |
1034 | |
1035 | Speculator = |
1036 | SimpleLazyReexportsSpeculator::Create(ES&: S.ES, RecordExec: std::move(RecordExecs)); |
1037 | break; |
1038 | } |
1039 | |
1040 | auto LRMgr = createJITLinkLazyReexportsManager( |
1041 | ObjLinkingLayer&: S.ObjLayer, RSMgr&: **RSMgr, PlatformJD&: *S.PlatformJD, L: Speculator.get()); |
1042 | if (!LRMgr) |
1043 | return LRMgr.takeError(); |
1044 | |
1045 | return std::make_unique<Session::LazyLinkingSupport>( |
1046 | args: std::move(*RSMgr), args: std::move(Speculator), args: std::move(*LRMgr), args&: S.ObjLayer); |
1047 | } |
1048 | |
1049 | static Error writeLazyExecOrder(Session &S) { |
1050 | if (RecordLazyExecs.empty()) |
1051 | return Error::success(); |
1052 | |
1053 | std::error_code EC; |
1054 | raw_fd_ostream ExecOrderOut(RecordLazyExecs, EC); |
1055 | if (EC) |
1056 | return createFileError(F: RecordLazyExecs, EC); |
1057 | |
1058 | for (auto &[JDName, FunctionName] : S.LazyFnExecOrder) |
1059 | ExecOrderOut << JDName << ", " << FunctionName << "\n" ; |
1060 | |
1061 | return Error::success(); |
1062 | } |
1063 | |
1064 | Expected<std::unique_ptr<Session>> Session::Create(Triple TT, |
1065 | SubtargetFeatures Features) { |
1066 | |
1067 | std::unique_ptr<ExecutorProcessControl> EPC; |
1068 | if (OutOfProcessExecutor.getNumOccurrences()) { |
1069 | /// If -oop-executor is passed then launch the executor. |
1070 | if (auto REPC = launchExecutor()) |
1071 | EPC = std::move(*REPC); |
1072 | else |
1073 | return REPC.takeError(); |
1074 | } else if (OutOfProcessExecutorConnect.getNumOccurrences()) { |
1075 | /// If -oop-executor-connect is passed then connect to the executor. |
1076 | if (auto REPC = connectToExecutor()) |
1077 | EPC = std::move(*REPC); |
1078 | else |
1079 | return REPC.takeError(); |
1080 | } else { |
1081 | /// Otherwise use SelfExecutorProcessControl to target the current process. |
1082 | auto PageSize = sys::Process::getPageSize(); |
1083 | if (!PageSize) |
1084 | return PageSize.takeError(); |
1085 | std::unique_ptr<TaskDispatcher> Dispatcher; |
1086 | if (MaterializationThreads == 0) |
1087 | Dispatcher = std::make_unique<InPlaceTaskDispatcher>(); |
1088 | else { |
1089 | #if LLVM_ENABLE_THREADS |
1090 | Dispatcher = std::make_unique<DynamicThreadPoolTaskDispatcher>( |
1091 | args&: MaterializationThreads); |
1092 | #else |
1093 | llvm_unreachable("MaterializationThreads should be 0" ); |
1094 | #endif |
1095 | } |
1096 | |
1097 | EPC = std::make_unique<SelfExecutorProcessControl>( |
1098 | args: std::make_shared<SymbolStringPool>(), args: std::move(Dispatcher), |
1099 | args: std::move(TT), args&: *PageSize, args: createInProcessMemoryManager()); |
1100 | } |
1101 | |
1102 | Error Err = Error::success(); |
1103 | std::unique_ptr<Session> S(new Session(std::move(EPC), Err)); |
1104 | if (Err) |
1105 | return std::move(Err); |
1106 | S->Features = std::move(Features); |
1107 | |
1108 | if (lazyLinkingRequested()) { |
1109 | if (auto LazyLinking = createLazyLinkingSupport(S&: *S)) |
1110 | S->LazyLinking = std::move(*LazyLinking); |
1111 | else |
1112 | return LazyLinking.takeError(); |
1113 | } |
1114 | |
1115 | return std::move(S); |
1116 | } |
1117 | |
1118 | Session::~Session() { |
1119 | if (auto Err = writeLazyExecOrder(S&: *this)) |
1120 | ES.reportError(Err: std::move(Err)); |
1121 | |
1122 | if (auto Err = ES.endSession()) |
1123 | ES.reportError(Err: std::move(Err)); |
1124 | } |
1125 | |
1126 | Session::Session(std::unique_ptr<ExecutorProcessControl> EPC, Error &Err) |
1127 | : ES(std::move(EPC)), |
1128 | ObjLayer(ES, ES.getExecutorProcessControl().getMemMgr()) { |
1129 | |
1130 | /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the |
1131 | /// Session. |
1132 | class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin { |
1133 | public: |
1134 | JITLinkSessionPlugin(Session &S) : S(S) {} |
1135 | void modifyPassConfig(MaterializationResponsibility &MR, LinkGraph &G, |
1136 | PassConfiguration &PassConfig) override { |
1137 | S.modifyPassConfig(G, PassConfig); |
1138 | } |
1139 | |
1140 | Error notifyFailed(MaterializationResponsibility &MR) override { |
1141 | return Error::success(); |
1142 | } |
1143 | Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override { |
1144 | return Error::success(); |
1145 | } |
1146 | void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, |
1147 | ResourceKey SrcKey) override {} |
1148 | |
1149 | private: |
1150 | Session &S; |
1151 | }; |
1152 | |
1153 | ErrorAsOutParameter _(&Err); |
1154 | |
1155 | ES.setErrorReporter(reportLLVMJITLinkError); |
1156 | |
1157 | if (!NoProcessSymbols) |
1158 | ExitOnErr(loadProcessSymbols(S&: *this)); |
1159 | |
1160 | ExitOnErr(loadDylibs(S&: *this)); |
1161 | |
1162 | auto &TT = ES.getTargetTriple(); |
1163 | |
1164 | if (DebuggerSupport && TT.isOSBinFormatMachO()) { |
1165 | if (!ProcessSymsJD) { |
1166 | Err = make_error<StringError>(Args: "MachO debugging requires process symbols" , |
1167 | Args: inconvertibleErrorCode()); |
1168 | return; |
1169 | } |
1170 | ObjLayer.addPlugin(P: ExitOnErr(GDBJITDebugInfoRegistrationPlugin::Create( |
1171 | ES&: this->ES, ProcessJD&: *ProcessSymsJD, TT))); |
1172 | } |
1173 | |
1174 | if (PerfSupport && TT.isOSBinFormatELF()) { |
1175 | if (!ProcessSymsJD) { |
1176 | Err = make_error<StringError>(Args: "MachO debugging requires process symbols" , |
1177 | Args: inconvertibleErrorCode()); |
1178 | return; |
1179 | } |
1180 | ObjLayer.addPlugin(P: ExitOnErr(DebugInfoPreservationPlugin::Create())); |
1181 | ObjLayer.addPlugin(P: ExitOnErr(PerfSupportPlugin::Create( |
1182 | EPC&: this->ES.getExecutorProcessControl(), JD&: *ProcessSymsJD, EmitDebugInfo: true, EmitUnwindInfo: true))); |
1183 | } |
1184 | |
1185 | if (VTuneSupport && TT.isOSBinFormatELF()) { |
1186 | ObjLayer.addPlugin(P: ExitOnErr(DebugInfoPreservationPlugin::Create())); |
1187 | ObjLayer.addPlugin(P: ExitOnErr( |
1188 | VTuneSupportPlugin::Create(EPC&: this->ES.getExecutorProcessControl(), |
1189 | JD&: *ProcessSymsJD, /*EmitDebugInfo=*/true, |
1190 | /*TestMode=*/true))); |
1191 | } |
1192 | |
1193 | // Set up the platform. |
1194 | if (!OrcRuntime.empty()) { |
1195 | assert(ProcessSymsJD && "ProcessSymsJD should have been set" ); |
1196 | PlatformJD = &ES.createBareJITDylib(Name: "Platform" ); |
1197 | PlatformJD->addToLinkOrder(JD&: *ProcessSymsJD); |
1198 | |
1199 | if (TT.isOSBinFormatMachO()) { |
1200 | if (auto P = |
1201 | MachOPlatform::Create(ObjLinkingLayer&: ObjLayer, PlatformJD&: *PlatformJD, OrcRuntimePath: OrcRuntime.c_str())) |
1202 | ES.setPlatform(std::move(*P)); |
1203 | else { |
1204 | Err = P.takeError(); |
1205 | return; |
1206 | } |
1207 | } else if (TT.isOSBinFormatELF()) { |
1208 | if (auto P = |
1209 | ELFNixPlatform::Create(ObjLinkingLayer&: ObjLayer, PlatformJD&: *PlatformJD, OrcRuntimePath: OrcRuntime.c_str())) |
1210 | ES.setPlatform(std::move(*P)); |
1211 | else { |
1212 | Err = P.takeError(); |
1213 | return; |
1214 | } |
1215 | } else if (TT.isOSBinFormatCOFF()) { |
1216 | auto LoadDynLibrary = [&, this](JITDylib &JD, |
1217 | StringRef DLLName) -> Error { |
1218 | if (!DLLName.ends_with_insensitive(Suffix: ".dll" )) |
1219 | return make_error<StringError>(Args: "DLLName not ending with .dll" , |
1220 | Args: inconvertibleErrorCode()); |
1221 | return loadAndLinkDynamicLibrary(JD, LibPath: DLLName); |
1222 | }; |
1223 | |
1224 | if (auto P = |
1225 | COFFPlatform::Create(ObjLinkingLayer&: ObjLayer, PlatformJD&: *PlatformJD, OrcRuntimePath: OrcRuntime.c_str(), |
1226 | LoadDynLibrary: std::move(LoadDynLibrary))) |
1227 | ES.setPlatform(std::move(*P)); |
1228 | else { |
1229 | Err = P.takeError(); |
1230 | return; |
1231 | } |
1232 | } else { |
1233 | Err = make_error<StringError>( |
1234 | Args: "-" + OrcRuntime.ArgStr + " specified, but format " + |
1235 | Triple::getObjectFormatTypeName(ObjectFormat: TT.getObjectFormat()) + |
1236 | " not supported" , |
1237 | Args: inconvertibleErrorCode()); |
1238 | return; |
1239 | } |
1240 | } else if (TT.isOSBinFormatMachO()) { |
1241 | if (!NoExec) { |
1242 | std::optional<bool> ForceEHFrames; |
1243 | if ((Err = ES.getBootstrapMapValue<bool, bool>(Key: "darwin-use-ehframes-only" , |
1244 | Val&: ForceEHFrames))) |
1245 | return; |
1246 | bool UseEHFrames = ForceEHFrames.value_or(u: false); |
1247 | if (!UseEHFrames) |
1248 | ObjLayer.addPlugin(P: ExitOnErr(UnwindInfoRegistrationPlugin::Create(ES))); |
1249 | else |
1250 | ObjLayer.addPlugin(P: ExitOnErr(EHFrameRegistrationPlugin::Create(ES))); |
1251 | } |
1252 | } else if (TT.isOSBinFormatELF()) { |
1253 | if (!NoExec) |
1254 | ObjLayer.addPlugin(P: ExitOnErr(EHFrameRegistrationPlugin::Create(ES))); |
1255 | if (DebuggerSupport) |
1256 | ObjLayer.addPlugin(P: std::make_unique<DebugObjectManagerPlugin>( |
1257 | args&: ES, args: ExitOnErr(createJITLoaderGDBRegistrar(ES&: this->ES)), args: true, args: true)); |
1258 | } |
1259 | |
1260 | if (auto MainJDOrErr = ES.createJITDylib(Name: "main" )) |
1261 | MainJD = &*MainJDOrErr; |
1262 | else { |
1263 | Err = MainJDOrErr.takeError(); |
1264 | return; |
1265 | } |
1266 | |
1267 | if (NoProcessSymbols) { |
1268 | // This symbol is used in testcases, but we're not reflecting process |
1269 | // symbols so we'll need to make it available some other way. |
1270 | auto &TestResultJD = ES.createBareJITDylib(Name: "<TestResultJD>" ); |
1271 | ExitOnErr(TestResultJD.define(MU: absoluteSymbols( |
1272 | Symbols: {{ES.intern(SymName: "llvm_jitlink_setTestResultOverride" ), |
1273 | {ExecutorAddr::fromPtr(Ptr: llvm_jitlink_setTestResultOverride), |
1274 | JITSymbolFlags::Exported}}}))); |
1275 | MainJD->addToLinkOrder(JD&: TestResultJD); |
1276 | } |
1277 | |
1278 | ObjLayer.addPlugin(P: std::make_unique<JITLinkSessionPlugin>(args&: *this)); |
1279 | |
1280 | // Process any harness files. |
1281 | for (auto &HarnessFile : TestHarnesses) { |
1282 | HarnessFiles.insert(key: HarnessFile); |
1283 | |
1284 | auto ObjBuffer = |
1285 | ExitOnErr(loadLinkableFile(Path: HarnessFile, TT: ES.getTargetTriple(), |
1286 | LA: LoadArchives::Never)) |
1287 | .first; |
1288 | |
1289 | auto ObjInterface = |
1290 | ExitOnErr(getObjectFileInterface(ES, ObjBuffer: ObjBuffer->getMemBufferRef())); |
1291 | |
1292 | for (auto &KV : ObjInterface.SymbolFlags) |
1293 | HarnessDefinitions.insert(key: *KV.first); |
1294 | |
1295 | auto Obj = ExitOnErr( |
1296 | object::ObjectFile::createObjectFile(Object: ObjBuffer->getMemBufferRef())); |
1297 | |
1298 | for (auto &Sym : Obj->symbols()) { |
1299 | uint32_t SymFlags = ExitOnErr(Sym.getFlags()); |
1300 | auto Name = ExitOnErr(Sym.getName()); |
1301 | |
1302 | if (Name.empty()) |
1303 | continue; |
1304 | |
1305 | if (SymFlags & object::BasicSymbolRef::SF_Undefined) |
1306 | HarnessExternals.insert(key: Name); |
1307 | } |
1308 | } |
1309 | |
1310 | // If a name is defined by some harness file then it's a definition, not an |
1311 | // external. |
1312 | for (auto &DefName : HarnessDefinitions) |
1313 | HarnessExternals.erase(Key: DefName.getKey()); |
1314 | |
1315 | if (!ShowLinkGraphs.empty()) |
1316 | ShowGraphsRegex = Regex(ShowLinkGraphs); |
1317 | } |
1318 | |
1319 | void Session::dumpSessionInfo(raw_ostream &OS) { |
1320 | OS << "Registered addresses:\n" << SymbolInfos << FileInfos; |
1321 | } |
1322 | |
1323 | void Session::modifyPassConfig(LinkGraph &G, PassConfiguration &PassConfig) { |
1324 | |
1325 | if (ShowLinkedFiles) |
1326 | outs() << "Linking " << G.getName() << "\n" ; |
1327 | |
1328 | if (!CheckFiles.empty()) |
1329 | PassConfig.PostFixupPasses.push_back(x: [this](LinkGraph &G) { |
1330 | if (ES.getTargetTriple().getObjectFormat() == Triple::ELF) |
1331 | return registerELFGraphInfo(S&: *this, G); |
1332 | |
1333 | if (ES.getTargetTriple().getObjectFormat() == Triple::MachO) |
1334 | return registerMachOGraphInfo(S&: *this, G); |
1335 | |
1336 | if (ES.getTargetTriple().getObjectFormat() == Triple::COFF) |
1337 | return registerCOFFGraphInfo(S&: *this, G); |
1338 | |
1339 | return make_error<StringError>(Args: "Unsupported object format for GOT/stub " |
1340 | "registration" , |
1341 | Args: inconvertibleErrorCode()); |
1342 | }); |
1343 | |
1344 | if (ShowGraphsRegex) |
1345 | PassConfig.PostFixupPasses.push_back(x: [this](LinkGraph &G) -> Error { |
1346 | std::lock_guard<std::mutex> Lock(M); |
1347 | // Print graph if ShowLinkGraphs is specified-but-empty, or if |
1348 | // it contains the given graph. |
1349 | if (ShowGraphsRegex->match(String: G.getName())) { |
1350 | outs() << "Link graph \"" << G.getName() << "\" post-fixup:\n" ; |
1351 | G.dump(OS&: outs()); |
1352 | } |
1353 | return Error::success(); |
1354 | }); |
1355 | |
1356 | PassConfig.PrePrunePasses.push_back(x: [this](LinkGraph &G) { |
1357 | std::lock_guard<std::mutex> Lock(M); |
1358 | ++ActiveLinks; |
1359 | return Error::success(); |
1360 | }); |
1361 | PassConfig.PrePrunePasses.push_back( |
1362 | x: [this](LinkGraph &G) { return applyLibraryLinkModifiers(S&: *this, G); }); |
1363 | PassConfig.PrePrunePasses.push_back( |
1364 | x: [this](LinkGraph &G) { return applyHarnessPromotions(S&: *this, G); }); |
1365 | |
1366 | if (ShowRelocatedSectionContents) |
1367 | PassConfig.PostFixupPasses.push_back(x: [this](LinkGraph &G) -> Error { |
1368 | dumpSectionContents(OS&: outs(), S&: *this, G); |
1369 | return Error::success(); |
1370 | }); |
1371 | |
1372 | if (AddSelfRelocations) |
1373 | PassConfig.PostPrunePasses.push_back(x: addSelfRelocations); |
1374 | |
1375 | PassConfig.PostFixupPasses.push_back(x: [this](LinkGraph &G) { |
1376 | std::lock_guard<std::mutex> Lock(M); |
1377 | if (--ActiveLinks == 0) |
1378 | ActiveLinksCV.notify_all(); |
1379 | return Error::success(); |
1380 | }); |
1381 | } |
1382 | |
1383 | Expected<JITDylib *> Session::getOrLoadDynamicLibrary(StringRef LibPath) { |
1384 | auto It = DynLibJDs.find(x: LibPath); |
1385 | if (It != DynLibJDs.end()) { |
1386 | return It->second; |
1387 | } |
1388 | auto G = EPCDynamicLibrarySearchGenerator::Load(ES, LibraryPath: LibPath.data()); |
1389 | if (!G) |
1390 | return G.takeError(); |
1391 | auto JD = &ES.createBareJITDylib(Name: LibPath.str()); |
1392 | |
1393 | JD->addGenerator(DefGenerator: std::move(*G)); |
1394 | DynLibJDs.emplace(args: LibPath.str(), args&: JD); |
1395 | LLVM_DEBUG({ |
1396 | dbgs() << "Loaded dynamic library " << LibPath.data() << " for " << LibPath |
1397 | << "\n" ; |
1398 | }); |
1399 | return JD; |
1400 | } |
1401 | |
1402 | Error Session::loadAndLinkDynamicLibrary(JITDylib &JD, StringRef LibPath) { |
1403 | auto DL = getOrLoadDynamicLibrary(LibPath); |
1404 | if (!DL) |
1405 | return DL.takeError(); |
1406 | JD.addToLinkOrder(JD&: **DL); |
1407 | LLVM_DEBUG({ |
1408 | dbgs() << "Linking dynamic library " << LibPath << " to " << JD.getName() |
1409 | << "\n" ; |
1410 | }); |
1411 | return Error::success(); |
1412 | } |
1413 | |
1414 | Error Session::FileInfo::registerGOTEntry( |
1415 | LinkGraph &G, Symbol &Sym, GetSymbolTargetFunction GetSymbolTarget) { |
1416 | if (Sym.isSymbolZeroFill()) |
1417 | return make_error<StringError>(Args: "Unexpected zero-fill symbol in section " + |
1418 | Sym.getBlock().getSection().getName(), |
1419 | Args: inconvertibleErrorCode()); |
1420 | auto TS = GetSymbolTarget(G, Sym.getBlock()); |
1421 | if (!TS) |
1422 | return TS.takeError(); |
1423 | GOTEntryInfos[*TS->getName()] = {Sym.getSymbolContent(), |
1424 | Sym.getAddress().getValue(), |
1425 | Sym.getTargetFlags()}; |
1426 | return Error::success(); |
1427 | } |
1428 | |
1429 | Error Session::FileInfo::registerStubEntry( |
1430 | LinkGraph &G, Symbol &Sym, GetSymbolTargetFunction GetSymbolTarget) { |
1431 | if (Sym.isSymbolZeroFill()) |
1432 | return make_error<StringError>(Args: "Unexpected zero-fill symbol in section " + |
1433 | Sym.getBlock().getSection().getName(), |
1434 | Args: inconvertibleErrorCode()); |
1435 | auto TS = GetSymbolTarget(G, Sym.getBlock()); |
1436 | if (!TS) |
1437 | return TS.takeError(); |
1438 | |
1439 | SmallVectorImpl<MemoryRegionInfo> &Entry = StubInfos[*TS->getName()]; |
1440 | Entry.insert(I: Entry.begin(), |
1441 | Elt: {Sym.getSymbolContent(), Sym.getAddress().getValue(), |
1442 | Sym.getTargetFlags()}); |
1443 | return Error::success(); |
1444 | } |
1445 | |
1446 | Error Session::FileInfo::registerMultiStubEntry( |
1447 | LinkGraph &G, Symbol &Sym, GetSymbolTargetFunction GetSymbolTarget) { |
1448 | if (Sym.isSymbolZeroFill()) |
1449 | return make_error<StringError>(Args: "Unexpected zero-fill symbol in section " + |
1450 | Sym.getBlock().getSection().getName(), |
1451 | Args: inconvertibleErrorCode()); |
1452 | |
1453 | auto Target = GetSymbolTarget(G, Sym.getBlock()); |
1454 | if (!Target) |
1455 | return Target.takeError(); |
1456 | |
1457 | SmallVectorImpl<MemoryRegionInfo> &Entry = StubInfos[*Target->getName()]; |
1458 | Entry.emplace_back(Args: Sym.getSymbolContent(), Args: Sym.getAddress().getValue(), |
1459 | Args: Sym.getTargetFlags()); |
1460 | |
1461 | // Let's keep stubs ordered by ascending address. |
1462 | std::sort(first: Entry.begin(), last: Entry.end(), |
1463 | comp: [](const MemoryRegionInfo &L, const MemoryRegionInfo &R) { |
1464 | return L.getTargetAddress() < R.getTargetAddress(); |
1465 | }); |
1466 | |
1467 | return Error::success(); |
1468 | } |
1469 | |
1470 | Expected<Session::FileInfo &> Session::findFileInfo(StringRef FileName) { |
1471 | auto FileInfoItr = FileInfos.find(Key: FileName); |
1472 | if (FileInfoItr == FileInfos.end()) |
1473 | return make_error<StringError>(Args: "file \"" + FileName + "\" not recognized" , |
1474 | Args: inconvertibleErrorCode()); |
1475 | return FileInfoItr->second; |
1476 | } |
1477 | |
1478 | Expected<Session::MemoryRegionInfo &> |
1479 | Session::findSectionInfo(StringRef FileName, StringRef SectionName) { |
1480 | auto FI = findFileInfo(FileName); |
1481 | if (!FI) |
1482 | return FI.takeError(); |
1483 | auto SecInfoItr = FI->SectionInfos.find(Key: SectionName); |
1484 | if (SecInfoItr == FI->SectionInfos.end()) |
1485 | return make_error<StringError>(Args: "no section \"" + SectionName + |
1486 | "\" registered for file \"" + FileName + |
1487 | "\"" , |
1488 | Args: inconvertibleErrorCode()); |
1489 | return SecInfoItr->second; |
1490 | } |
1491 | |
1492 | class MemoryMatcher { |
1493 | public: |
1494 | MemoryMatcher(ArrayRef<char> Content) |
1495 | : Pos(Content.data()), End(Pos + Content.size()) {} |
1496 | |
1497 | template <typename MaskType> bool matchMask(MaskType Mask) { |
1498 | if (Mask == (Mask & *reinterpret_cast<const MaskType *>(Pos))) { |
1499 | Pos += sizeof(MaskType); |
1500 | return true; |
1501 | } |
1502 | return false; |
1503 | } |
1504 | |
1505 | template <typename ValueType> bool matchEqual(ValueType Value) { |
1506 | if (Value == *reinterpret_cast<const ValueType *>(Pos)) { |
1507 | Pos += sizeof(ValueType); |
1508 | return true; |
1509 | } |
1510 | return false; |
1511 | } |
1512 | |
1513 | bool done() const { return Pos == End; } |
1514 | |
1515 | private: |
1516 | const char *Pos; |
1517 | const char *End; |
1518 | }; |
1519 | |
1520 | static StringRef detectStubKind(const Session::MemoryRegionInfo &Stub) { |
1521 | using namespace support::endian; |
1522 | auto Armv7MovWTle = byte_swap<uint32_t, endianness::little>(value: 0xe300c000); |
1523 | auto Armv7BxR12le = byte_swap<uint32_t, endianness::little>(value: 0xe12fff1c); |
1524 | auto Thumbv7MovWTle = byte_swap<uint32_t, endianness::little>(value: 0x0c00f240); |
1525 | auto Thumbv7BxR12le = byte_swap<uint16_t, endianness::little>(value: 0x4760); |
1526 | |
1527 | MemoryMatcher M(Stub.getContent()); |
1528 | if (M.matchMask(Mask: Thumbv7MovWTle)) { |
1529 | if (M.matchMask(Mask: Thumbv7MovWTle)) |
1530 | if (M.matchEqual(Value: Thumbv7BxR12le)) |
1531 | if (M.done()) |
1532 | return "thumbv7_abs_le" ; |
1533 | } else if (M.matchMask(Mask: Armv7MovWTle)) { |
1534 | if (M.matchMask(Mask: Armv7MovWTle)) |
1535 | if (M.matchEqual(Value: Armv7BxR12le)) |
1536 | if (M.done()) |
1537 | return "armv7_abs_le" ; |
1538 | } |
1539 | return "" ; |
1540 | } |
1541 | |
1542 | Expected<Session::MemoryRegionInfo &> |
1543 | Session::findStubInfo(StringRef FileName, StringRef TargetName, |
1544 | StringRef KindNameFilter) { |
1545 | auto FI = findFileInfo(FileName); |
1546 | if (!FI) |
1547 | return FI.takeError(); |
1548 | auto StubInfoItr = FI->StubInfos.find(Key: TargetName); |
1549 | if (StubInfoItr == FI->StubInfos.end()) |
1550 | return make_error<StringError>(Args: "no stub for \"" + TargetName + |
1551 | "\" registered for file \"" + FileName + |
1552 | "\"" , |
1553 | Args: inconvertibleErrorCode()); |
1554 | auto &StubsForTarget = StubInfoItr->second; |
1555 | assert(!StubsForTarget.empty() && "At least 1 stub in each entry" ); |
1556 | if (KindNameFilter.empty() && StubsForTarget.size() == 1) |
1557 | return StubsForTarget[0]; // Regular single-stub match |
1558 | |
1559 | std::string KindsStr; |
1560 | SmallVector<MemoryRegionInfo *, 1> Matches; |
1561 | Regex KindNameMatcher(KindNameFilter.empty() ? ".*" : KindNameFilter); |
1562 | for (MemoryRegionInfo &Stub : StubsForTarget) { |
1563 | StringRef Kind = detectStubKind(Stub); |
1564 | if (KindNameMatcher.match(String: Kind)) |
1565 | Matches.push_back(Elt: &Stub); |
1566 | KindsStr += "\"" + (Kind.empty() ? "<unknown>" : Kind.str()) + "\", " ; |
1567 | } |
1568 | if (Matches.empty()) |
1569 | return make_error<StringError>( |
1570 | Args: "\"" + TargetName + "\" has " + Twine(StubsForTarget.size()) + |
1571 | " stubs in file \"" + FileName + |
1572 | "\", but none of them matches the stub-kind filter \"" + |
1573 | KindNameFilter + "\" (all encountered kinds are " + |
1574 | StringRef(KindsStr.data(), KindsStr.size() - 2) + ")." , |
1575 | Args: inconvertibleErrorCode()); |
1576 | if (Matches.size() > 1) |
1577 | return make_error<StringError>( |
1578 | Args: "\"" + TargetName + "\" has " + Twine(Matches.size()) + |
1579 | " candidate stubs in file \"" + FileName + |
1580 | "\". Please refine stub-kind filter \"" + KindNameFilter + |
1581 | "\" for disambiguation (encountered kinds are " + |
1582 | StringRef(KindsStr.data(), KindsStr.size() - 2) + ")." , |
1583 | Args: inconvertibleErrorCode()); |
1584 | |
1585 | return *Matches[0]; |
1586 | } |
1587 | |
1588 | Expected<Session::MemoryRegionInfo &> |
1589 | Session::findGOTEntryInfo(StringRef FileName, StringRef TargetName) { |
1590 | auto FI = findFileInfo(FileName); |
1591 | if (!FI) |
1592 | return FI.takeError(); |
1593 | auto GOTInfoItr = FI->GOTEntryInfos.find(Key: TargetName); |
1594 | if (GOTInfoItr == FI->GOTEntryInfos.end()) |
1595 | return make_error<StringError>(Args: "no GOT entry for \"" + TargetName + |
1596 | "\" registered for file \"" + FileName + |
1597 | "\"" , |
1598 | Args: inconvertibleErrorCode()); |
1599 | return GOTInfoItr->second; |
1600 | } |
1601 | |
1602 | bool Session::isSymbolRegistered(const orc::SymbolStringPtr &SymbolName) { |
1603 | return SymbolInfos.count(Val: SymbolName); |
1604 | } |
1605 | |
1606 | Expected<Session::MemoryRegionInfo &> |
1607 | Session::findSymbolInfo(const orc::SymbolStringPtr &SymbolName, |
1608 | Twine ErrorMsgStem) { |
1609 | auto SymInfoItr = SymbolInfos.find(Val: SymbolName); |
1610 | if (SymInfoItr == SymbolInfos.end()) |
1611 | return make_error<StringError>(Args: ErrorMsgStem + ": symbol " + *SymbolName + |
1612 | " not found" , |
1613 | Args: inconvertibleErrorCode()); |
1614 | return SymInfoItr->second; |
1615 | } |
1616 | |
1617 | } // end namespace llvm |
1618 | |
1619 | static std::pair<Triple, SubtargetFeatures> getFirstFileTripleAndFeatures() { |
1620 | static std::pair<Triple, SubtargetFeatures> FirstTTAndFeatures = []() { |
1621 | assert(!InputFiles.empty() && "InputFiles can not be empty" ); |
1622 | |
1623 | if (!OverrideTriple.empty()) { |
1624 | LLVM_DEBUG({ |
1625 | dbgs() << "Triple from -triple override: " << OverrideTriple << "\n" ; |
1626 | }); |
1627 | return std::make_pair(x: Triple(OverrideTriple), y: SubtargetFeatures()); |
1628 | } |
1629 | |
1630 | for (auto InputFile : InputFiles) { |
1631 | auto ObjBuffer = ExitOnErr(getFile(FileName: InputFile)); |
1632 | file_magic Magic = identify_magic(magic: ObjBuffer->getBuffer()); |
1633 | switch (Magic) { |
1634 | case file_magic::coff_object: |
1635 | case file_magic::elf_relocatable: |
1636 | case file_magic::macho_object: { |
1637 | auto Obj = ExitOnErr( |
1638 | object::ObjectFile::createObjectFile(Object: ObjBuffer->getMemBufferRef())); |
1639 | Triple TT = Obj->makeTriple(); |
1640 | if (Magic == file_magic::coff_object) { |
1641 | // TODO: Move this to makeTriple() if possible. |
1642 | TT.setObjectFormat(Triple::COFF); |
1643 | TT.setOS(Triple::OSType::Win32); |
1644 | } |
1645 | SubtargetFeatures Features; |
1646 | if (auto ObjFeatures = Obj->getFeatures()) |
1647 | Features = std::move(*ObjFeatures); |
1648 | |
1649 | LLVM_DEBUG({ |
1650 | dbgs() << "Triple from " << InputFile << ": " << TT.str() << "\n" ; |
1651 | }); |
1652 | return std::make_pair(x&: TT, y&: Features); |
1653 | } |
1654 | default: |
1655 | break; |
1656 | } |
1657 | } |
1658 | |
1659 | // If no plain object file inputs exist to pin down the triple then detect |
1660 | // the host triple and default to that. |
1661 | auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost()); |
1662 | LLVM_DEBUG({ |
1663 | dbgs() << "Triple from host-detection: " << JTMB.getTargetTriple().str() |
1664 | << "\n" ; |
1665 | }); |
1666 | return std::make_pair(x&: JTMB.getTargetTriple(), y&: JTMB.getFeatures()); |
1667 | }(); |
1668 | |
1669 | return FirstTTAndFeatures; |
1670 | } |
1671 | |
1672 | static Error sanitizeArguments(const Triple &TT, const char *ArgV0) { |
1673 | |
1674 | // -noexec and --args should not be used together. |
1675 | if (NoExec && !InputArgv.empty()) |
1676 | errs() << "Warning: --args passed to -noexec run will be ignored.\n" ; |
1677 | |
1678 | // Set the entry point name if not specified. |
1679 | if (EntryPointName.empty()) |
1680 | EntryPointName = TT.getObjectFormat() == Triple::MachO ? "_main" : "main" ; |
1681 | |
1682 | // Disable debugger support by default in noexec tests. |
1683 | if (DebuggerSupport.getNumOccurrences() == 0 && NoExec) |
1684 | DebuggerSupport = false; |
1685 | |
1686 | if (!OrcRuntime.empty() && NoProcessSymbols) |
1687 | return make_error<StringError>(Args: "-orc-runtime requires process symbols" , |
1688 | Args: inconvertibleErrorCode()); |
1689 | |
1690 | // If -slab-allocate is passed, check that we're not trying to use it in |
1691 | // -oop-executor or -oop-executor-connect mode. |
1692 | // |
1693 | // FIXME: Remove once we enable remote slab allocation. |
1694 | if (SlabAllocateSizeString != "" ) { |
1695 | if (OutOfProcessExecutor.getNumOccurrences() || |
1696 | OutOfProcessExecutorConnect.getNumOccurrences()) |
1697 | return make_error<StringError>( |
1698 | Args: "-slab-allocate cannot be used with -oop-executor or " |
1699 | "-oop-executor-connect" , |
1700 | Args: inconvertibleErrorCode()); |
1701 | } |
1702 | |
1703 | // If -slab-address is passed, require -slab-allocate and -noexec |
1704 | if (SlabAddress != ~0ULL) { |
1705 | if (SlabAllocateSizeString == "" || !NoExec) |
1706 | return make_error<StringError>( |
1707 | Args: "-slab-address requires -slab-allocate and -noexec" , |
1708 | Args: inconvertibleErrorCode()); |
1709 | |
1710 | if (SlabPageSize == 0) |
1711 | errs() << "Warning: -slab-address used without -slab-page-size.\n" ; |
1712 | } |
1713 | |
1714 | if (SlabPageSize != 0) { |
1715 | // -slab-page-size requires slab alloc. |
1716 | if (SlabAllocateSizeString == "" ) |
1717 | return make_error<StringError>(Args: "-slab-page-size requires -slab-allocate" , |
1718 | Args: inconvertibleErrorCode()); |
1719 | |
1720 | // Check -slab-page-size / -noexec interactions. |
1721 | if (!NoExec) { |
1722 | if (auto RealPageSize = sys::Process::getPageSize()) { |
1723 | if (SlabPageSize % *RealPageSize) |
1724 | return make_error<StringError>( |
1725 | Args: "-slab-page-size must be a multiple of real page size for exec " |
1726 | "tests (did you mean to use -noexec ?)\n" , |
1727 | Args: inconvertibleErrorCode()); |
1728 | } else { |
1729 | errs() << "Could not retrieve process page size:\n" ; |
1730 | logAllUnhandledErrors(E: RealPageSize.takeError(), OS&: errs(), ErrorBanner: "" ); |
1731 | errs() << "Executing with slab page size = " |
1732 | << formatv(Fmt: "{0:x}" , Vals&: SlabPageSize) << ".\n" |
1733 | << "Tool may crash if " << formatv(Fmt: "{0:x}" , Vals&: SlabPageSize) |
1734 | << " is not a multiple of the real process page size.\n" |
1735 | << "(did you mean to use -noexec ?)" ; |
1736 | } |
1737 | } |
1738 | } |
1739 | |
1740 | #if LLVM_ENABLE_THREADS |
1741 | if (MaterializationThreads == std::numeric_limits<size_t>::max()) { |
1742 | if (auto HC = std::thread::hardware_concurrency()) |
1743 | MaterializationThreads = HC; |
1744 | else { |
1745 | errs() << "Warning: std::thread::hardware_concurrency() returned 0, " |
1746 | "defaulting to -num-threads=1.\n" ; |
1747 | MaterializationThreads = 1; |
1748 | } |
1749 | } |
1750 | #else |
1751 | if (MaterializationThreads.getNumOccurrences() && |
1752 | MaterializationThreads != 0) { |
1753 | errs() << "Warning: -num-threads was set, but LLVM was built with threads " |
1754 | "disabled. Resetting to -num-threads=0\n" ; |
1755 | } |
1756 | MaterializationThreads = 0; |
1757 | #endif |
1758 | |
1759 | if (!!OutOfProcessExecutor.getNumOccurrences() || |
1760 | !!OutOfProcessExecutorConnect.getNumOccurrences()) { |
1761 | if (NoExec) |
1762 | return make_error<StringError>(Args: "-noexec cannot be used with " + |
1763 | OutOfProcessExecutor.ArgStr + " or " + |
1764 | OutOfProcessExecutorConnect.ArgStr, |
1765 | Args: inconvertibleErrorCode()); |
1766 | |
1767 | if (MaterializationThreads == 0) |
1768 | return make_error<StringError>(Args: "-threads=0 cannot be used with " + |
1769 | OutOfProcessExecutor.ArgStr + " or " + |
1770 | OutOfProcessExecutorConnect.ArgStr, |
1771 | Args: inconvertibleErrorCode()); |
1772 | } |
1773 | |
1774 | #ifndef NDEBUG |
1775 | if (DebugFlag && MaterializationThreads != 0) |
1776 | errs() << "Warning: debugging output is not thread safe. " |
1777 | "Use -num-threads=0 to stabilize output.\n" ; |
1778 | #endif // NDEBUG |
1779 | |
1780 | // Only one of -oop-executor and -oop-executor-connect can be used. |
1781 | if (!!OutOfProcessExecutor.getNumOccurrences() && |
1782 | !!OutOfProcessExecutorConnect.getNumOccurrences()) |
1783 | return make_error<StringError>( |
1784 | Args: "Only one of -" + OutOfProcessExecutor.ArgStr + " and -" + |
1785 | OutOfProcessExecutorConnect.ArgStr + " can be specified" , |
1786 | Args: inconvertibleErrorCode()); |
1787 | |
1788 | // If -oop-executor was used but no value was specified then use a sensible |
1789 | // default. |
1790 | if (!!OutOfProcessExecutor.getNumOccurrences() && |
1791 | OutOfProcessExecutor.empty()) { |
1792 | SmallString<256> OOPExecutorPath(sys::fs::getMainExecutable( |
1793 | argv0: ArgV0, MainExecAddr: reinterpret_cast<void *>(&sanitizeArguments))); |
1794 | sys::path::remove_filename(path&: OOPExecutorPath); |
1795 | sys::path::append(path&: OOPExecutorPath, a: "llvm-jitlink-executor" ); |
1796 | OutOfProcessExecutor = OOPExecutorPath.str().str(); |
1797 | } |
1798 | |
1799 | // If lazy linking is requested then check compatibility with other options. |
1800 | if (lazyLinkingRequested()) { |
1801 | if (OrcRuntime.empty()) |
1802 | return make_error<StringError>(Args: "Lazy linking requries the ORC runtime" , |
1803 | Args: inconvertibleErrorCode()); |
1804 | |
1805 | if (!TestHarnesses.empty()) |
1806 | return make_error<StringError>( |
1807 | Args: "Lazy linking cannot be used with -harness mode" , |
1808 | Args: inconvertibleErrorCode()); |
1809 | } else if (Speculate != SpeculateKind::None) { |
1810 | errs() << "Warning: -speculate ignored as there are no -lazy inputs\n" ; |
1811 | Speculate = SpeculateKind::None; |
1812 | } |
1813 | |
1814 | if (Speculate == SpeculateKind::None) { |
1815 | if (!SpeculateOrder.empty()) { |
1816 | errs() << "Warning: -speculate-order ignored because speculation is " |
1817 | "disabled\n" ; |
1818 | SpeculateOrder = "" ; |
1819 | } |
1820 | |
1821 | if (!RecordLazyExecs.empty()) { |
1822 | errs() << "Warning: -record-lazy-execs ignored because speculation is " |
1823 | "disabled\n" ; |
1824 | RecordLazyExecs = "" ; |
1825 | } |
1826 | } |
1827 | |
1828 | return Error::success(); |
1829 | } |
1830 | |
1831 | static void addPhonyExternalsGenerator(Session &S) { |
1832 | S.MainJD->addGenerator(DefGenerator: std::make_unique<PhonyExternalsGenerator>()); |
1833 | } |
1834 | |
1835 | static Error createJITDylibs(Session &S, |
1836 | std::map<unsigned, JITDylib *> &IdxToJD) { |
1837 | // First, set up JITDylibs. |
1838 | LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n" ); |
1839 | { |
1840 | // Create a "main" JITLinkDylib. |
1841 | IdxToJD[0] = S.MainJD; |
1842 | S.JDSearchOrder.push_back(x: {S.MainJD, JITDylibLookupFlags::MatchAllSymbols}); |
1843 | LLVM_DEBUG(dbgs() << " 0: " << S.MainJD->getName() << "\n" ); |
1844 | |
1845 | // Add any extra JITDylibs from the command line. |
1846 | for (auto JDItr = JITDylibs.begin(), JDEnd = JITDylibs.end(); |
1847 | JDItr != JDEnd; ++JDItr) { |
1848 | auto JD = S.ES.createJITDylib(Name: *JDItr); |
1849 | if (!JD) |
1850 | return JD.takeError(); |
1851 | unsigned JDIdx = JITDylibs.getPosition(optnum: JDItr - JITDylibs.begin()); |
1852 | IdxToJD[JDIdx] = &*JD; |
1853 | S.JDSearchOrder.push_back(x: {&*JD, JITDylibLookupFlags::MatchAllSymbols}); |
1854 | LLVM_DEBUG(dbgs() << " " << JDIdx << ": " << JD->getName() << "\n" ); |
1855 | } |
1856 | } |
1857 | |
1858 | if (S.PlatformJD) |
1859 | S.JDSearchOrder.push_back( |
1860 | x: {S.PlatformJD, JITDylibLookupFlags::MatchExportedSymbolsOnly}); |
1861 | if (S.ProcessSymsJD) |
1862 | S.JDSearchOrder.push_back( |
1863 | x: {S.ProcessSymsJD, JITDylibLookupFlags::MatchExportedSymbolsOnly}); |
1864 | |
1865 | LLVM_DEBUG({ |
1866 | dbgs() << "Dylib search order is [ " ; |
1867 | for (auto &KV : S.JDSearchOrder) |
1868 | dbgs() << KV.first->getName() << " " ; |
1869 | dbgs() << "]\n" ; |
1870 | }); |
1871 | |
1872 | return Error::success(); |
1873 | } |
1874 | |
1875 | static Error addAbsoluteSymbols(Session &S, |
1876 | const std::map<unsigned, JITDylib *> &IdxToJD) { |
1877 | // Define absolute symbols. |
1878 | LLVM_DEBUG(dbgs() << "Defining absolute symbols...\n" ); |
1879 | for (auto AbsDefItr = AbsoluteDefs.begin(), AbsDefEnd = AbsoluteDefs.end(); |
1880 | AbsDefItr != AbsDefEnd; ++AbsDefItr) { |
1881 | unsigned AbsDefArgIdx = |
1882 | AbsoluteDefs.getPosition(optnum: AbsDefItr - AbsoluteDefs.begin()); |
1883 | auto &JD = *std::prev(x: IdxToJD.lower_bound(x: AbsDefArgIdx))->second; |
1884 | |
1885 | StringRef AbsDefStmt = *AbsDefItr; |
1886 | size_t EqIdx = AbsDefStmt.find_first_of(C: '='); |
1887 | if (EqIdx == StringRef::npos) |
1888 | return make_error<StringError>(Args: "Invalid absolute define \"" + AbsDefStmt + |
1889 | "\". Syntax: <name>=<addr>" , |
1890 | Args: inconvertibleErrorCode()); |
1891 | StringRef Name = AbsDefStmt.substr(Start: 0, N: EqIdx).trim(); |
1892 | StringRef AddrStr = AbsDefStmt.substr(Start: EqIdx + 1).trim(); |
1893 | |
1894 | uint64_t Addr; |
1895 | if (AddrStr.getAsInteger(Radix: 0, Result&: Addr)) |
1896 | return make_error<StringError>(Args: "Invalid address expression \"" + AddrStr + |
1897 | "\" in absolute symbol definition \"" + |
1898 | AbsDefStmt + "\"" , |
1899 | Args: inconvertibleErrorCode()); |
1900 | ExecutorSymbolDef AbsDef(ExecutorAddr(Addr), JITSymbolFlags::Exported); |
1901 | auto InternedName = S.ES.intern(SymName: Name); |
1902 | if (auto Err = JD.define(MU: absoluteSymbols(Symbols: {{InternedName, AbsDef}}))) |
1903 | return Err; |
1904 | |
1905 | // Register the absolute symbol with the session symbol infos. |
1906 | S.SymbolInfos[std::move(InternedName)] = |
1907 | {ArrayRef<char>(), Addr, AbsDef.getFlags().getTargetFlags()}; |
1908 | } |
1909 | |
1910 | return Error::success(); |
1911 | } |
1912 | |
1913 | static Error addAliases(Session &S, |
1914 | const std::map<unsigned, JITDylib *> &IdxToJD) { |
1915 | // Define absolute symbols. |
1916 | LLVM_DEBUG(dbgs() << "Defining aliases...\n" ); |
1917 | |
1918 | DenseMap<std::pair<JITDylib *, JITDylib *>, SymbolAliasMap> Reexports; |
1919 | for (auto AliasItr = Aliases.begin(), AliasEnd = Aliases.end(); |
1920 | AliasItr != AliasEnd; ++AliasItr) { |
1921 | |
1922 | auto BadExpr = [&]() { |
1923 | return make_error<StringError>( |
1924 | Args: "Invalid alias definition \"" + *AliasItr + |
1925 | "\". Syntax: [<dst-jd>:]<alias>=[<src-jd>:]<aliasee>" , |
1926 | Args: inconvertibleErrorCode()); |
1927 | }; |
1928 | |
1929 | auto GetJD = [&](StringRef JDName) -> Expected<JITDylib *> { |
1930 | if (JDName.empty()) { |
1931 | unsigned AliasArgIdx = Aliases.getPosition(optnum: AliasItr - Aliases.begin()); |
1932 | return std::prev(x: IdxToJD.lower_bound(x: AliasArgIdx))->second; |
1933 | } |
1934 | |
1935 | auto *JD = S.ES.getJITDylibByName(Name: JDName); |
1936 | if (!JD) |
1937 | return make_error<StringError>(Args: StringRef("In alias definition \"" ) + |
1938 | *AliasItr + "\" no dylib named " + |
1939 | JDName, |
1940 | Args: inconvertibleErrorCode()); |
1941 | |
1942 | return JD; |
1943 | }; |
1944 | |
1945 | { |
1946 | // First split on '=' to get alias and aliasee. |
1947 | StringRef AliasStmt = *AliasItr; |
1948 | auto [AliasExpr, AliaseeExpr] = AliasStmt.split(Separator: '='); |
1949 | if (AliaseeExpr.empty()) |
1950 | return BadExpr(); |
1951 | |
1952 | auto [AliasJDName, Alias] = AliasExpr.split(Separator: ':'); |
1953 | if (Alias.empty()) |
1954 | std::swap(a&: AliasJDName, b&: Alias); |
1955 | |
1956 | auto AliasJD = GetJD(AliasJDName); |
1957 | if (!AliasJD) |
1958 | return AliasJD.takeError(); |
1959 | |
1960 | auto [AliaseeJDName, Aliasee] = AliaseeExpr.split(Separator: ':'); |
1961 | if (Aliasee.empty()) |
1962 | std::swap(a&: AliaseeJDName, b&: Aliasee); |
1963 | |
1964 | if (AliaseeJDName.empty() && !AliasJDName.empty()) |
1965 | AliaseeJDName = AliasJDName; |
1966 | auto AliaseeJD = GetJD(AliaseeJDName); |
1967 | if (!AliaseeJD) |
1968 | return AliaseeJD.takeError(); |
1969 | |
1970 | Reexports[{*AliasJD, *AliaseeJD}][S.ES.intern(SymName: Alias)] = { |
1971 | S.ES.intern(SymName: Aliasee), JITSymbolFlags::Exported}; |
1972 | } |
1973 | } |
1974 | |
1975 | for (auto &[JDs, AliasMap] : Reexports) { |
1976 | auto [DstJD, SrcJD] = JDs; |
1977 | if (auto Err = DstJD->define(MU: reexports(SourceJD&: *SrcJD, Aliases: std::move(AliasMap)))) |
1978 | return Err; |
1979 | } |
1980 | |
1981 | return Error::success(); |
1982 | } |
1983 | |
1984 | static Error addSectCreates(Session &S, |
1985 | const std::map<unsigned, JITDylib *> &IdxToJD) { |
1986 | for (auto SCItr = SectCreate.begin(), SCEnd = SectCreate.end(); |
1987 | SCItr != SCEnd; ++SCItr) { |
1988 | |
1989 | unsigned SCArgIdx = SectCreate.getPosition(optnum: SCItr - SectCreate.begin()); |
1990 | auto &JD = *std::prev(x: IdxToJD.lower_bound(x: SCArgIdx))->second; |
1991 | |
1992 | StringRef SCArg(*SCItr); |
1993 | |
1994 | auto [SectAndFileName, ExtraSymbolsString] = SCArg.rsplit(Separator: '@'); |
1995 | auto [SectName, FileName] = SectAndFileName.rsplit(Separator: ','); |
1996 | if (SectName.empty()) |
1997 | return make_error<StringError>(Args: "In -sectcreate=" + SCArg + |
1998 | ", filename component cannot be empty" , |
1999 | Args: inconvertibleErrorCode()); |
2000 | if (FileName.empty()) |
2001 | return make_error<StringError>(Args: "In -sectcreate=" + SCArg + |
2002 | ", filename component cannot be empty" , |
2003 | Args: inconvertibleErrorCode()); |
2004 | |
2005 | auto Content = getFile(FileName); |
2006 | if (!Content) |
2007 | return Content.takeError(); |
2008 | |
2009 | SectCreateMaterializationUnit::ExtraSymbolsMap ; |
2010 | while (!ExtraSymbolsString.empty()) { |
2011 | StringRef NextSymPair; |
2012 | std::tie(args&: NextSymPair, args&: ExtraSymbolsString) = ExtraSymbolsString.split(Separator: ','); |
2013 | |
2014 | auto [Sym, OffsetString] = NextSymPair.split(Separator: '='); |
2015 | size_t Offset; |
2016 | |
2017 | if (OffsetString.getAsInteger(Radix: 0, Result&: Offset)) |
2018 | return make_error<StringError>(Args: "In -sectcreate=" + SCArg + ", " + |
2019 | OffsetString + |
2020 | " is not a valid integer" , |
2021 | Args: inconvertibleErrorCode()); |
2022 | |
2023 | ExtraSymbols[S.ES.intern(SymName: Sym)] = {.Flags: JITSymbolFlags::Exported, .Offset: Offset}; |
2024 | } |
2025 | |
2026 | if (auto Err = JD.define(MU: std::make_unique<SectCreateMaterializationUnit>( |
2027 | args&: S.ObjLayer, args: SectName.str(), args: MemProt::Read, args: 16, args: std::move(*Content), |
2028 | args: std::move(ExtraSymbols)))) |
2029 | return Err; |
2030 | } |
2031 | |
2032 | return Error::success(); |
2033 | } |
2034 | |
2035 | static Error addTestHarnesses(Session &S) { |
2036 | LLVM_DEBUG(dbgs() << "Adding test harness objects...\n" ); |
2037 | for (auto HarnessFile : TestHarnesses) { |
2038 | LLVM_DEBUG(dbgs() << " " << HarnessFile << "\n" ); |
2039 | auto Linkable = loadLinkableFile(Path: HarnessFile, TT: S.ES.getTargetTriple(), |
2040 | LA: LoadArchives::Never); |
2041 | if (!Linkable) |
2042 | return Linkable.takeError(); |
2043 | if (auto Err = S.ObjLayer.add(JD&: *S.MainJD, O: std::move(Linkable->first))) |
2044 | return Err; |
2045 | } |
2046 | return Error::success(); |
2047 | } |
2048 | |
2049 | static Error addObjects(Session &S, |
2050 | const std::map<unsigned, JITDylib *> &IdxToJD, |
2051 | const DenseSet<unsigned> &LazyLinkIdxs) { |
2052 | |
2053 | // Load each object into the corresponding JITDylib.. |
2054 | LLVM_DEBUG(dbgs() << "Adding objects...\n" ); |
2055 | for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end(); |
2056 | InputFileItr != InputFileEnd; ++InputFileItr) { |
2057 | unsigned InputFileArgIdx = |
2058 | InputFiles.getPosition(optnum: InputFileItr - InputFiles.begin()); |
2059 | const std::string &InputFile = *InputFileItr; |
2060 | if (StringRef(InputFile).ends_with(Suffix: ".a" ) || |
2061 | StringRef(InputFile).ends_with(Suffix: ".lib" )) |
2062 | continue; |
2063 | auto &JD = *std::prev(x: IdxToJD.lower_bound(x: InputFileArgIdx))->second; |
2064 | bool AddLazy = LazyLinkIdxs.count(V: InputFileArgIdx); |
2065 | LLVM_DEBUG(dbgs() << " " << InputFileArgIdx << ": \"" << InputFile << "\" " |
2066 | << (AddLazy ? " (lazy-linked)" : "" ) << " to " |
2067 | << JD.getName() << "\n" ;); |
2068 | auto ObjBuffer = loadLinkableFile(Path: InputFile, TT: S.ES.getTargetTriple(), |
2069 | LA: LoadArchives::Never); |
2070 | if (!ObjBuffer) |
2071 | return ObjBuffer.takeError(); |
2072 | |
2073 | if (S.HarnessFiles.empty()) { |
2074 | if (auto Err = |
2075 | S.getLinkLayer(Lazy: AddLazy).add(JD, O: std::move(ObjBuffer->first))) |
2076 | return Err; |
2077 | } else { |
2078 | // We're in -harness mode. Use a custom interface for this |
2079 | // test object. |
2080 | auto ObjInterface = |
2081 | getTestObjectFileInterface(S, O: ObjBuffer->first->getMemBufferRef()); |
2082 | if (!ObjInterface) |
2083 | return ObjInterface.takeError(); |
2084 | |
2085 | if (auto Err = S.ObjLayer.add(JD, O: std::move(ObjBuffer->first), |
2086 | I: std::move(*ObjInterface))) |
2087 | return Err; |
2088 | } |
2089 | } |
2090 | |
2091 | return Error::success(); |
2092 | } |
2093 | |
2094 | static Expected<MaterializationUnit::Interface> |
2095 | getObjectFileInterfaceHidden(ExecutionSession &ES, MemoryBufferRef ObjBuffer) { |
2096 | auto I = getObjectFileInterface(ES, ObjBuffer); |
2097 | if (I) { |
2098 | for (auto &KV : I->SymbolFlags) |
2099 | KV.second &= ~JITSymbolFlags::Exported; |
2100 | } |
2101 | return I; |
2102 | } |
2103 | |
2104 | static SmallVector<StringRef, 5> getSearchPathsFromEnvVar(Session &S) { |
2105 | // FIXME: Handle EPC environment. |
2106 | SmallVector<StringRef, 5> PathVec; |
2107 | auto TT = S.ES.getTargetTriple(); |
2108 | if (TT.isOSBinFormatCOFF()) |
2109 | StringRef(getenv(name: "PATH" )).split(A&: PathVec, Separator: ";" ); |
2110 | else if (TT.isOSBinFormatELF()) |
2111 | StringRef(getenv(name: "LD_LIBRARY_PATH" )).split(A&: PathVec, Separator: ":" ); |
2112 | |
2113 | return PathVec; |
2114 | } |
2115 | |
2116 | static Expected<std::unique_ptr<DefinitionGenerator>> |
2117 | LoadLibraryWeak(Session &S, StringRef Path) { |
2118 | auto Symbols = getDylibInterface(ES&: S.ES, Path); |
2119 | if (!Symbols) |
2120 | return Symbols.takeError(); |
2121 | |
2122 | return std::make_unique<EPCDynamicLibrarySearchGenerator>( |
2123 | args&: S.ES, args: [Symbols = std::move(*Symbols)](const SymbolStringPtr &Sym) { |
2124 | return Symbols.count(V: Sym); |
2125 | }); |
2126 | } |
2127 | |
2128 | static Error addLibraries(Session &S, |
2129 | const std::map<unsigned, JITDylib *> &IdxToJD, |
2130 | const DenseSet<unsigned> &LazyLinkIdxs) { |
2131 | |
2132 | // 1. Collect search paths for each JITDylib. |
2133 | DenseMap<const JITDylib *, SmallVector<StringRef, 2>> JDSearchPaths; |
2134 | |
2135 | for (auto LSPItr = LibrarySearchPaths.begin(), |
2136 | LSPEnd = LibrarySearchPaths.end(); |
2137 | LSPItr != LSPEnd; ++LSPItr) { |
2138 | unsigned LibrarySearchPathIdx = |
2139 | LibrarySearchPaths.getPosition(optnum: LSPItr - LibrarySearchPaths.begin()); |
2140 | auto &JD = *std::prev(x: IdxToJD.lower_bound(x: LibrarySearchPathIdx))->second; |
2141 | |
2142 | StringRef LibrarySearchPath = *LSPItr; |
2143 | if (sys::fs::get_file_type(Path: LibrarySearchPath) != |
2144 | sys::fs::file_type::directory_file) |
2145 | return make_error<StringError>(Args: "While linking " + JD.getName() + ", -L" + |
2146 | LibrarySearchPath + |
2147 | " does not point to a directory" , |
2148 | Args: inconvertibleErrorCode()); |
2149 | |
2150 | JDSearchPaths[&JD].push_back(Elt: *LSPItr); |
2151 | } |
2152 | |
2153 | LLVM_DEBUG({ |
2154 | if (!JDSearchPaths.empty()) |
2155 | dbgs() << "Search paths:\n" ; |
2156 | for (auto &KV : JDSearchPaths) { |
2157 | dbgs() << " " << KV.first->getName() << ": [" ; |
2158 | for (auto &LibSearchPath : KV.second) |
2159 | dbgs() << " \"" << LibSearchPath << "\"" ; |
2160 | dbgs() << " ]\n" ; |
2161 | } |
2162 | }); |
2163 | |
2164 | // 2. Collect library loads |
2165 | struct LibraryLoad { |
2166 | std::string LibName; |
2167 | bool IsPath = false; |
2168 | unsigned Position; |
2169 | ArrayRef<StringRef> CandidateExtensions; |
2170 | enum { Standard, Hidden, Weak } Modifier; |
2171 | }; |
2172 | |
2173 | // Queue to load library as in the order as it appears in the argument list. |
2174 | std::deque<LibraryLoad> LibraryLoadQueue; |
2175 | |
2176 | // Add archive files from the inputs to LibraryLoads. |
2177 | for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end(); |
2178 | InputFileItr != InputFileEnd; ++InputFileItr) { |
2179 | StringRef InputFile = *InputFileItr; |
2180 | if (!InputFile.ends_with(Suffix: ".a" ) && !InputFile.ends_with(Suffix: ".lib" )) |
2181 | continue; |
2182 | LibraryLoad LL; |
2183 | LL.LibName = InputFile.str(); |
2184 | LL.IsPath = true; |
2185 | LL.Position = InputFiles.getPosition(optnum: InputFileItr - InputFiles.begin()); |
2186 | LL.CandidateExtensions = {}; |
2187 | LL.Modifier = LibraryLoad::Standard; |
2188 | LibraryLoadQueue.push_back(x: std::move(LL)); |
2189 | } |
2190 | |
2191 | // Add -load_hidden arguments to LibraryLoads. |
2192 | for (auto LibItr = LoadHidden.begin(), LibEnd = LoadHidden.end(); |
2193 | LibItr != LibEnd; ++LibItr) { |
2194 | LibraryLoad LL; |
2195 | LL.LibName = *LibItr; |
2196 | LL.IsPath = true; |
2197 | LL.Position = LoadHidden.getPosition(optnum: LibItr - LoadHidden.begin()); |
2198 | LL.CandidateExtensions = {}; |
2199 | LL.Modifier = LibraryLoad::Hidden; |
2200 | LibraryLoadQueue.push_back(x: std::move(LL)); |
2201 | } |
2202 | |
2203 | // Add -weak_library arguments to LibraryLoads. |
2204 | for (auto LibItr = WeakLibraries.begin(), LibEnd = WeakLibraries.end(); |
2205 | LibItr != LibEnd; ++LibItr) { |
2206 | LibraryLoad LL; |
2207 | LL.LibName = *LibItr; |
2208 | LL.IsPath = true; |
2209 | LL.Position = WeakLibraries.getPosition(optnum: LibItr - WeakLibraries.begin()); |
2210 | LL.CandidateExtensions = {}; |
2211 | LL.Modifier = LibraryLoad::Weak; |
2212 | LibraryLoadQueue.push_back(x: std::move(LL)); |
2213 | } |
2214 | |
2215 | StringRef StandardExtensions[] = {".so" , ".dylib" , ".dll" , ".a" , ".lib" }; |
2216 | StringRef DynLibExtensionsOnly[] = {".so" , ".dylib" , ".dll" }; |
2217 | StringRef ArchiveExtensionsOnly[] = {".a" , ".lib" }; |
2218 | StringRef WeakLinkExtensionsOnly[] = {".dylib" , ".tbd" }; |
2219 | |
2220 | // Add -lx arguments to LibraryLoads. |
2221 | for (auto LibItr = Libraries.begin(), LibEnd = Libraries.end(); |
2222 | LibItr != LibEnd; ++LibItr) { |
2223 | LibraryLoad LL; |
2224 | LL.LibName = *LibItr; |
2225 | LL.Position = Libraries.getPosition(optnum: LibItr - Libraries.begin()); |
2226 | LL.CandidateExtensions = StandardExtensions; |
2227 | LL.Modifier = LibraryLoad::Standard; |
2228 | LibraryLoadQueue.push_back(x: std::move(LL)); |
2229 | } |
2230 | |
2231 | // Add -hidden-lx arguments to LibraryLoads. |
2232 | for (auto LibHiddenItr = LibrariesHidden.begin(), |
2233 | LibHiddenEnd = LibrariesHidden.end(); |
2234 | LibHiddenItr != LibHiddenEnd; ++LibHiddenItr) { |
2235 | LibraryLoad LL; |
2236 | LL.LibName = *LibHiddenItr; |
2237 | LL.Position = |
2238 | LibrariesHidden.getPosition(optnum: LibHiddenItr - LibrariesHidden.begin()); |
2239 | LL.CandidateExtensions = ArchiveExtensionsOnly; |
2240 | LL.Modifier = LibraryLoad::Hidden; |
2241 | LibraryLoadQueue.push_back(x: std::move(LL)); |
2242 | } |
2243 | |
2244 | // Add -weak-lx arguments to LibraryLoads. |
2245 | for (auto LibWeakItr = LibrariesWeak.begin(), |
2246 | LibWeakEnd = LibrariesWeak.end(); |
2247 | LibWeakItr != LibWeakEnd; ++LibWeakItr) { |
2248 | LibraryLoad LL; |
2249 | LL.LibName = *LibWeakItr; |
2250 | LL.Position = LibrariesWeak.getPosition(optnum: LibWeakItr - LibrariesWeak.begin()); |
2251 | LL.CandidateExtensions = WeakLinkExtensionsOnly; |
2252 | LL.Modifier = LibraryLoad::Weak; |
2253 | LibraryLoadQueue.push_back(x: std::move(LL)); |
2254 | } |
2255 | |
2256 | // Sort library loads by position in the argument list. |
2257 | llvm::sort(C&: LibraryLoadQueue, |
2258 | Comp: [](const LibraryLoad &LHS, const LibraryLoad &RHS) { |
2259 | return LHS.Position < RHS.Position; |
2260 | }); |
2261 | |
2262 | // 3. Process library loads. |
2263 | auto AddArchive = [&](JITDylib &JD, const char *Path, const LibraryLoad &LL) |
2264 | -> Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> { |
2265 | StaticLibraryDefinitionGenerator::GetObjectFileInterface |
2266 | GetObjFileInterface; |
2267 | switch (LL.Modifier) { |
2268 | case LibraryLoad::Standard: |
2269 | GetObjFileInterface = getObjectFileInterface; |
2270 | break; |
2271 | case LibraryLoad::Hidden: |
2272 | GetObjFileInterface = getObjectFileInterfaceHidden; |
2273 | S.HiddenArchives.insert(key: Path); |
2274 | break; |
2275 | case LibraryLoad::Weak: |
2276 | llvm_unreachable("Unsupported" ); |
2277 | break; |
2278 | } |
2279 | |
2280 | auto &LinkLayer = S.getLinkLayer(Lazy: LazyLinkIdxs.count(V: LL.Position)); |
2281 | |
2282 | std::set<std::string> ImportedDynamicLibraries; |
2283 | StaticLibraryDefinitionGenerator::VisitMembersFunction VisitMembers; |
2284 | |
2285 | // COFF gets special handling due to import libraries. |
2286 | if (S.ES.getTargetTriple().isOSBinFormatCOFF()) { |
2287 | if (AllLoad) { |
2288 | VisitMembers = |
2289 | [ImportScanner = COFFImportFileScanner(ImportedDynamicLibraries), |
2290 | LoadAll = |
2291 | StaticLibraryDefinitionGenerator::loadAllObjectFileMembers( |
2292 | L&: LinkLayer, JD)](object::Archive &A, |
2293 | MemoryBufferRef MemberBuf, |
2294 | size_t Index) mutable -> Expected<bool> { |
2295 | if (!ImportScanner(A, MemberBuf, Index)) |
2296 | return false; |
2297 | return LoadAll(A, MemberBuf, Index); |
2298 | }; |
2299 | } else |
2300 | VisitMembers = COFFImportFileScanner(ImportedDynamicLibraries); |
2301 | } else if (AllLoad) |
2302 | VisitMembers = StaticLibraryDefinitionGenerator::loadAllObjectFileMembers( |
2303 | L&: LinkLayer, JD); |
2304 | else if (S.ES.getTargetTriple().isOSBinFormatMachO() && ForceLoadObjC) |
2305 | VisitMembers = ForceLoadMachOArchiveMembers(LinkLayer, JD, true); |
2306 | |
2307 | auto G = StaticLibraryDefinitionGenerator::Load( |
2308 | L&: LinkLayer, FileName: Path, VisitMembers: std::move(VisitMembers), |
2309 | GetObjFileInterface: std::move(GetObjFileInterface)); |
2310 | if (!G) |
2311 | return G.takeError(); |
2312 | |
2313 | // Push additional dynamic libraries to search. |
2314 | // Note that this mechanism only happens in COFF. |
2315 | for (auto FileName : ImportedDynamicLibraries) { |
2316 | LibraryLoad NewLL; |
2317 | auto FileNameRef = StringRef(FileName); |
2318 | if (!FileNameRef.ends_with_insensitive(Suffix: ".dll" )) |
2319 | return make_error<StringError>( |
2320 | Args: "COFF Imported library not ending with dll extension?" , |
2321 | Args: inconvertibleErrorCode()); |
2322 | NewLL.LibName = FileNameRef.drop_back(N: strlen(s: ".dll" )).str(); |
2323 | NewLL.Position = LL.Position; |
2324 | NewLL.CandidateExtensions = DynLibExtensionsOnly; |
2325 | NewLL.Modifier = LibraryLoad::Standard; |
2326 | LibraryLoadQueue.push_front(x: std::move(NewLL)); |
2327 | } |
2328 | return G; |
2329 | }; |
2330 | |
2331 | SmallVector<StringRef, 5> SystemSearchPaths; |
2332 | if (SearchSystemLibrary.getValue()) |
2333 | SystemSearchPaths = getSearchPathsFromEnvVar(S); |
2334 | while (!LibraryLoadQueue.empty()) { |
2335 | bool LibFound = false; |
2336 | auto LL = LibraryLoadQueue.front(); |
2337 | LibraryLoadQueue.pop_front(); |
2338 | auto &JD = *std::prev(x: IdxToJD.lower_bound(x: LL.Position))->second; |
2339 | |
2340 | // If this is the name of a JITDylib then link against that. |
2341 | if (auto *LJD = S.ES.getJITDylibByName(Name: LL.LibName)) { |
2342 | if (LL.Modifier == LibraryLoad::Weak) |
2343 | return make_error<StringError>( |
2344 | Args: "Can't use -weak-lx or -weak_library to load JITDylib " + |
2345 | LL.LibName, |
2346 | Args: inconvertibleErrorCode()); |
2347 | JD.addToLinkOrder(JD&: *LJD); |
2348 | continue; |
2349 | } |
2350 | |
2351 | if (LL.IsPath) { |
2352 | // Must be -weak_library. |
2353 | if (LL.Modifier == LibraryLoad::Weak) { |
2354 | if (auto G = LoadLibraryWeak(S, Path: LL.LibName)) { |
2355 | JD.addGenerator(DefGenerator: std::move(*G)); |
2356 | continue; |
2357 | } else |
2358 | return G.takeError(); |
2359 | } |
2360 | |
2361 | // Otherwise handle archive. |
2362 | auto G = AddArchive(JD, LL.LibName.c_str(), LL); |
2363 | if (!G) |
2364 | return createFileError(F: LL.LibName, E: G.takeError()); |
2365 | JD.addGenerator(DefGenerator: std::move(*G)); |
2366 | LLVM_DEBUG({ |
2367 | dbgs() << "Adding generator for static library " << LL.LibName << " to " |
2368 | << JD.getName() << "\n" ; |
2369 | }); |
2370 | continue; |
2371 | } |
2372 | |
2373 | // Otherwise look through the search paths. |
2374 | auto CurJDSearchPaths = JDSearchPaths[&JD]; |
2375 | for (StringRef SearchPath : |
2376 | concat<StringRef>(Ranges&: CurJDSearchPaths, Ranges&: SystemSearchPaths)) { |
2377 | for (auto LibExt : LL.CandidateExtensions) { |
2378 | SmallVector<char, 256> LibPath; |
2379 | LibPath.reserve(N: SearchPath.size() + strlen(s: "lib" ) + LL.LibName.size() + |
2380 | LibExt.size() + 2); // +2 for pathsep, null term. |
2381 | llvm::append_range(C&: LibPath, R&: SearchPath); |
2382 | if (LibExt != ".lib" && LibExt != ".dll" ) |
2383 | sys::path::append(path&: LibPath, a: "lib" + LL.LibName + LibExt); |
2384 | else |
2385 | sys::path::append(path&: LibPath, a: LL.LibName + LibExt); |
2386 | LibPath.push_back(Elt: '\0'); |
2387 | |
2388 | // Skip missing or non-regular paths. |
2389 | if (sys::fs::get_file_type(Path: LibPath.data()) != |
2390 | sys::fs::file_type::regular_file) { |
2391 | continue; |
2392 | } |
2393 | |
2394 | file_magic Magic; |
2395 | if (auto EC = identify_magic(path: LibPath, result&: Magic)) { |
2396 | // If there was an error loading the file then skip it. |
2397 | LLVM_DEBUG({ |
2398 | dbgs() << "Library search found \"" << LibPath |
2399 | << "\", but could not identify file type (" << EC.message() |
2400 | << "). Skipping.\n" ; |
2401 | }); |
2402 | continue; |
2403 | } |
2404 | |
2405 | // We identified the magic. Assume that we can load it -- we'll reset |
2406 | // in the default case. |
2407 | LibFound = true; |
2408 | switch (Magic) { |
2409 | case file_magic::pecoff_executable: |
2410 | case file_magic::elf_shared_object: |
2411 | case file_magic::macho_dynamically_linked_shared_lib: { |
2412 | if (LL.Modifier == LibraryLoad::Weak) { |
2413 | if (auto G = LoadLibraryWeak(S, Path: LibPath.data())) |
2414 | JD.addGenerator(DefGenerator: std::move(*G)); |
2415 | else |
2416 | return G.takeError(); |
2417 | } else { |
2418 | if (auto Err = S.loadAndLinkDynamicLibrary(JD, LibPath: LibPath.data())) |
2419 | return Err; |
2420 | } |
2421 | break; |
2422 | } |
2423 | case file_magic::archive: |
2424 | case file_magic::macho_universal_binary: { |
2425 | auto G = AddArchive(JD, LibPath.data(), LL); |
2426 | if (!G) |
2427 | return G.takeError(); |
2428 | JD.addGenerator(DefGenerator: std::move(*G)); |
2429 | LLVM_DEBUG({ |
2430 | dbgs() << "Adding generator for static library " << LibPath.data() |
2431 | << " to " << JD.getName() << "\n" ; |
2432 | }); |
2433 | break; |
2434 | } |
2435 | case file_magic::tapi_file: |
2436 | assert(LL.Modifier == LibraryLoad::Weak && |
2437 | "TextAPI file not being loaded as weak?" ); |
2438 | if (auto G = LoadLibraryWeak(S, Path: LibPath.data())) |
2439 | JD.addGenerator(DefGenerator: std::move(*G)); |
2440 | else |
2441 | return G.takeError(); |
2442 | break; |
2443 | default: |
2444 | // This file isn't a recognized library kind. |
2445 | LLVM_DEBUG({ |
2446 | dbgs() << "Library search found \"" << LibPath |
2447 | << "\", but file type is not supported. Skipping.\n" ; |
2448 | }); |
2449 | LibFound = false; |
2450 | break; |
2451 | } |
2452 | if (LibFound) |
2453 | break; |
2454 | } |
2455 | if (LibFound) |
2456 | break; |
2457 | } |
2458 | |
2459 | if (!LibFound) |
2460 | return make_error<StringError>(Args: "While linking " + JD.getName() + |
2461 | ", could not find library for -l" + |
2462 | LL.LibName, |
2463 | Args: inconvertibleErrorCode()); |
2464 | } |
2465 | |
2466 | // Add platform and process symbols if available. |
2467 | for (auto &[Idx, JD] : IdxToJD) { |
2468 | if (S.PlatformJD) |
2469 | JD->addToLinkOrder(JD&: *S.PlatformJD); |
2470 | if (S.ProcessSymsJD) |
2471 | JD->addToLinkOrder(JD&: *S.ProcessSymsJD); |
2472 | } |
2473 | |
2474 | return Error::success(); |
2475 | } |
2476 | |
2477 | static Error addSpeculationOrder(Session &S) { |
2478 | |
2479 | if (SpeculateOrder.empty()) |
2480 | return Error::success(); |
2481 | |
2482 | assert(S.LazyLinking && "SpeculateOrder set, but lazy linking not enabled" ); |
2483 | assert(S.LazyLinking->Speculator && "SpeculatoOrder set, but no speculator" ); |
2484 | |
2485 | auto SpecOrderBuffer = getFile(FileName: SpeculateOrder); |
2486 | if (!SpecOrderBuffer) |
2487 | return SpecOrderBuffer.takeError(); |
2488 | |
2489 | StringRef LineStream((*SpecOrderBuffer)->getBuffer()); |
2490 | std::vector<std::pair<std::string, SymbolStringPtr>> SpecOrder; |
2491 | |
2492 | size_t LineNumber = 0; |
2493 | while (!LineStream.empty()) { |
2494 | ++LineNumber; |
2495 | |
2496 | auto MakeSpecOrderErr = [&](StringRef Reason) { |
2497 | return make_error<StringError>(Args: "Error in speculation order file \"" + |
2498 | SpeculateOrder + "\" on line " + |
2499 | Twine(LineNumber) + ": " + Reason, |
2500 | Args: inconvertibleErrorCode()); |
2501 | }; |
2502 | |
2503 | StringRef CurLine; |
2504 | std::tie(args&: CurLine, args&: LineStream) = LineStream.split(Separator: '\n'); |
2505 | CurLine = CurLine.trim(); |
2506 | if (CurLine.empty()) |
2507 | continue; |
2508 | |
2509 | auto [JDName, FuncName] = CurLine.split(Separator: ','); |
2510 | |
2511 | if (FuncName.empty()) |
2512 | return MakeSpecOrderErr("missing ',' separator" ); |
2513 | |
2514 | JDName = JDName.trim(); |
2515 | if (JDName.empty()) |
2516 | return MakeSpecOrderErr("no value for column 1 (JIT Dylib name)" ); |
2517 | |
2518 | FuncName = FuncName.trim(); |
2519 | if (FuncName.empty()) |
2520 | return MakeSpecOrderErr("no value for column 2 (function name)" ); |
2521 | |
2522 | SpecOrder.push_back(x: {JDName.str(), S.ES.intern(SymName: FuncName)}); |
2523 | } |
2524 | |
2525 | S.LazyLinking->Speculator->addSpeculationSuggestions(NewSuggestions: std::move(SpecOrder)); |
2526 | |
2527 | return Error::success(); |
2528 | } |
2529 | |
2530 | static Error addSessionInputs(Session &S) { |
2531 | std::map<unsigned, JITDylib *> IdxToJD; |
2532 | DenseSet<unsigned> LazyLinkIdxs; |
2533 | |
2534 | for (auto LLItr = LazyLink.begin(), LLEnd = LazyLink.end(); LLItr != LLEnd; |
2535 | ++LLItr) { |
2536 | if (*LLItr) |
2537 | LazyLinkIdxs.insert(V: LazyLink.getPosition(optnum: LLItr - LazyLink.begin()) + 1); |
2538 | } |
2539 | |
2540 | if (auto Err = createJITDylibs(S, IdxToJD)) |
2541 | return Err; |
2542 | |
2543 | if (auto Err = addAbsoluteSymbols(S, IdxToJD)) |
2544 | return Err; |
2545 | |
2546 | if (auto Err = addAliases(S, IdxToJD)) |
2547 | return Err; |
2548 | |
2549 | if (auto Err = addSectCreates(S, IdxToJD)) |
2550 | return Err; |
2551 | |
2552 | if (!TestHarnesses.empty()) |
2553 | if (auto Err = addTestHarnesses(S)) |
2554 | return Err; |
2555 | |
2556 | if (auto Err = addObjects(S, IdxToJD, LazyLinkIdxs)) |
2557 | return Err; |
2558 | |
2559 | if (auto Err = addLibraries(S, IdxToJD, LazyLinkIdxs)) |
2560 | return Err; |
2561 | |
2562 | if (auto Err = addSpeculationOrder(S)) |
2563 | return Err; |
2564 | |
2565 | return Error::success(); |
2566 | } |
2567 | |
2568 | namespace { |
2569 | struct TargetInfo { |
2570 | const Target *TheTarget; |
2571 | std::unique_ptr<MCSubtargetInfo> STI; |
2572 | std::unique_ptr<MCRegisterInfo> MRI; |
2573 | std::unique_ptr<MCAsmInfo> MAI; |
2574 | std::unique_ptr<MCContext> Ctx; |
2575 | std::unique_ptr<MCDisassembler> Disassembler; |
2576 | std::unique_ptr<MCInstrInfo> MII; |
2577 | std::unique_ptr<MCInstrAnalysis> MIA; |
2578 | std::unique_ptr<MCInstPrinter> InstPrinter; |
2579 | }; |
2580 | } // anonymous namespace |
2581 | |
2582 | static TargetInfo |
2583 | getTargetInfo(const Triple &TT, |
2584 | const SubtargetFeatures &TF = SubtargetFeatures()) { |
2585 | auto TripleName = TT.str(); |
2586 | std::string ErrorStr; |
2587 | const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr: TripleName, Error&: ErrorStr); |
2588 | if (!TheTarget) |
2589 | ExitOnErr(make_error<StringError>(Args: "Error accessing target '" + TripleName + |
2590 | "': " + ErrorStr, |
2591 | Args: inconvertibleErrorCode())); |
2592 | |
2593 | std::unique_ptr<MCSubtargetInfo> STI( |
2594 | TheTarget->createMCSubtargetInfo(TheTriple: TripleName, CPU: "" , Features: TF.getString())); |
2595 | if (!STI) |
2596 | ExitOnErr( |
2597 | make_error<StringError>(Args: "Unable to create subtarget for " + TripleName, |
2598 | Args: inconvertibleErrorCode())); |
2599 | |
2600 | std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT: TripleName)); |
2601 | if (!MRI) |
2602 | ExitOnErr(make_error<StringError>(Args: "Unable to create target register info " |
2603 | "for " + |
2604 | TripleName, |
2605 | Args: inconvertibleErrorCode())); |
2606 | |
2607 | MCTargetOptions MCOptions; |
2608 | std::unique_ptr<MCAsmInfo> MAI( |
2609 | TheTarget->createMCAsmInfo(MRI: *MRI, TheTriple: TripleName, Options: MCOptions)); |
2610 | if (!MAI) |
2611 | ExitOnErr(make_error<StringError>(Args: "Unable to create target asm info " + |
2612 | TripleName, |
2613 | Args: inconvertibleErrorCode())); |
2614 | |
2615 | auto Ctx = std::make_unique<MCContext>(args: Triple(TripleName), args: MAI.get(), |
2616 | args: MRI.get(), args: STI.get()); |
2617 | |
2618 | std::unique_ptr<MCDisassembler> Disassembler( |
2619 | TheTarget->createMCDisassembler(STI: *STI, Ctx&: *Ctx)); |
2620 | if (!Disassembler) |
2621 | ExitOnErr(make_error<StringError>(Args: "Unable to create disassembler for " + |
2622 | TripleName, |
2623 | Args: inconvertibleErrorCode())); |
2624 | |
2625 | std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo()); |
2626 | if (!MII) |
2627 | ExitOnErr(make_error<StringError>(Args: "Unable to create instruction info for" + |
2628 | TripleName, |
2629 | Args: inconvertibleErrorCode())); |
2630 | |
2631 | std::unique_ptr<MCInstrAnalysis> MIA( |
2632 | TheTarget->createMCInstrAnalysis(Info: MII.get())); |
2633 | if (!MIA) |
2634 | ExitOnErr(make_error<StringError>( |
2635 | Args: "Unable to create instruction analysis for" + TripleName, |
2636 | Args: inconvertibleErrorCode())); |
2637 | |
2638 | std::unique_ptr<MCInstPrinter> InstPrinter( |
2639 | TheTarget->createMCInstPrinter(T: Triple(TripleName), SyntaxVariant: 0, MAI: *MAI, MII: *MII, MRI: *MRI)); |
2640 | if (!InstPrinter) |
2641 | ExitOnErr(make_error<StringError>( |
2642 | Args: "Unable to create instruction printer for" + TripleName, |
2643 | Args: inconvertibleErrorCode())); |
2644 | return {.TheTarget: TheTarget, .STI: std::move(STI), .MRI: std::move(MRI), |
2645 | .MAI: std::move(MAI), .Ctx: std::move(Ctx), .Disassembler: std::move(Disassembler), |
2646 | .MII: std::move(MII), .MIA: std::move(MIA), .InstPrinter: std::move(InstPrinter)}; |
2647 | } |
2648 | static Error runChecks(Session &S, Triple TT, SubtargetFeatures Features) { |
2649 | if (CheckFiles.empty()) |
2650 | return Error::success(); |
2651 | |
2652 | S.waitForFilesLinkedFromEntryPointFile(); |
2653 | |
2654 | LLVM_DEBUG(dbgs() << "Running checks...\n" ); |
2655 | |
2656 | auto IsSymbolValid = [&S](StringRef Symbol) { |
2657 | auto InternedSymbol = S.ES.getSymbolStringPool()->intern(S: Symbol); |
2658 | return S.isSymbolRegistered(SymbolName: InternedSymbol); |
2659 | }; |
2660 | |
2661 | auto GetSymbolInfo = [&S](StringRef Symbol) { |
2662 | auto InternedSymbol = S.ES.getSymbolStringPool()->intern(S: Symbol); |
2663 | return S.findSymbolInfo(SymbolName: InternedSymbol, ErrorMsgStem: "Can not get symbol info" ); |
2664 | }; |
2665 | |
2666 | auto GetSectionInfo = [&S](StringRef FileName, StringRef SectionName) { |
2667 | return S.findSectionInfo(FileName, SectionName); |
2668 | }; |
2669 | |
2670 | auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName, |
2671 | StringRef KindNameFilter) { |
2672 | return S.findStubInfo(FileName, TargetName: SectionName, KindNameFilter); |
2673 | }; |
2674 | |
2675 | auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) { |
2676 | return S.findGOTEntryInfo(FileName, TargetName: SectionName); |
2677 | }; |
2678 | |
2679 | RuntimeDyldChecker Checker( |
2680 | IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo, |
2681 | S.ES.getTargetTriple().isLittleEndian() ? llvm::endianness::little |
2682 | : llvm::endianness::big, |
2683 | TT, StringRef(), Features, dbgs()); |
2684 | |
2685 | std::string CheckLineStart = "# " + CheckName + ":" ; |
2686 | for (auto &CheckFile : CheckFiles) { |
2687 | auto CheckerFileBuf = ExitOnErr(getFile(FileName: CheckFile)); |
2688 | if (!Checker.checkAllRulesInBuffer(RulePrefix: CheckLineStart, MemBuf: &*CheckerFileBuf)) |
2689 | ExitOnErr(make_error<StringError>( |
2690 | Args: "Some checks in " + CheckFile + " failed" , Args: inconvertibleErrorCode())); |
2691 | } |
2692 | |
2693 | return Error::success(); |
2694 | } |
2695 | |
2696 | static Error addSelfRelocations(LinkGraph &G) { |
2697 | auto TI = getTargetInfo(TT: G.getTargetTriple()); |
2698 | for (auto *Sym : G.defined_symbols()) |
2699 | if (Sym->isCallable()) |
2700 | if (auto Err = addFunctionPointerRelocationsToCurrentSymbol( |
2701 | Sym&: *Sym, G, Disassembler&: *TI.Disassembler, MIA&: *TI.MIA)) |
2702 | return Err; |
2703 | return Error::success(); |
2704 | } |
2705 | |
2706 | static Expected<ExecutorSymbolDef> getMainEntryPoint(Session &S) { |
2707 | return S.ES.lookup(SearchOrder: S.JDSearchOrder, Symbol: S.ES.intern(SymName: EntryPointName)); |
2708 | } |
2709 | |
2710 | static Expected<ExecutorSymbolDef> getOrcRuntimeEntryPoint(Session &S) { |
2711 | std::string RuntimeEntryPoint = "__orc_rt_run_program_wrapper" ; |
2712 | if (S.ES.getTargetTriple().getObjectFormat() == Triple::MachO) |
2713 | RuntimeEntryPoint = '_' + RuntimeEntryPoint; |
2714 | return S.ES.lookup(SearchOrder: S.JDSearchOrder, Symbol: S.ES.intern(SymName: RuntimeEntryPoint)); |
2715 | } |
2716 | |
2717 | static Expected<ExecutorSymbolDef> getEntryPoint(Session &S) { |
2718 | ExecutorSymbolDef EntryPoint; |
2719 | |
2720 | // Find the entry-point function unconditionally, since we want to force |
2721 | // it to be materialized to collect stats. |
2722 | if (auto EP = getMainEntryPoint(S)) |
2723 | EntryPoint = *EP; |
2724 | else |
2725 | return EP.takeError(); |
2726 | LLVM_DEBUG({ |
2727 | dbgs() << "Using entry point \"" << EntryPointName |
2728 | << "\": " << formatv("{0:x16}" , EntryPoint.getAddress()) << "\n" ; |
2729 | }); |
2730 | |
2731 | // If we're running with the ORC runtime then replace the entry-point |
2732 | // with the __orc_rt_run_program symbol. |
2733 | if (!OrcRuntime.empty()) { |
2734 | if (auto EP = getOrcRuntimeEntryPoint(S)) |
2735 | EntryPoint = *EP; |
2736 | else |
2737 | return EP.takeError(); |
2738 | LLVM_DEBUG({ |
2739 | dbgs() << "(called via __orc_rt_run_program_wrapper at " |
2740 | << formatv("{0:x16}" , EntryPoint.getAddress()) << ")\n" ; |
2741 | }); |
2742 | } |
2743 | |
2744 | return EntryPoint; |
2745 | } |
2746 | |
2747 | static Expected<int> runWithRuntime(Session &S, ExecutorAddr EntryPointAddr) { |
2748 | StringRef DemangledEntryPoint = EntryPointName; |
2749 | if (S.ES.getTargetTriple().getObjectFormat() == Triple::MachO && |
2750 | DemangledEntryPoint.front() == '_') |
2751 | DemangledEntryPoint = DemangledEntryPoint.drop_front(); |
2752 | using llvm::orc::shared::SPSString; |
2753 | using SPSRunProgramSig = |
2754 | int64_t(SPSString, SPSString, shared::SPSSequence<SPSString>); |
2755 | int64_t Result; |
2756 | if (auto Err = S.ES.callSPSWrapper<SPSRunProgramSig>( |
2757 | WrapperFnAddr: EntryPointAddr, WrapperCallArgs&: Result, WrapperCallArgs: S.MainJD->getName(), WrapperCallArgs&: DemangledEntryPoint, |
2758 | WrapperCallArgs&: static_cast<std::vector<std::string> &>(InputArgv))) |
2759 | return std::move(Err); |
2760 | return Result; |
2761 | } |
2762 | |
2763 | static Expected<int> runWithoutRuntime(Session &S, |
2764 | ExecutorAddr EntryPointAddr) { |
2765 | return S.ES.getExecutorProcessControl().runAsMain(MainFnAddr: EntryPointAddr, Args: InputArgv); |
2766 | } |
2767 | |
2768 | namespace { |
2769 | struct JITLinkTimers { |
2770 | TimerGroup JITLinkTG{"llvm-jitlink timers" , "timers for llvm-jitlink phases" }; |
2771 | Timer LoadObjectsTimer{"load" , "time to load/add object files" , JITLinkTG}; |
2772 | Timer LinkTimer{"link" , "time to link object files" , JITLinkTG}; |
2773 | Timer RunTimer{"run" , "time to execute jitlink'd code" , JITLinkTG}; |
2774 | }; |
2775 | } // namespace |
2776 | |
2777 | int main(int argc, char *argv[]) { |
2778 | InitLLVM X(argc, argv); |
2779 | |
2780 | InitializeAllTargetInfos(); |
2781 | InitializeAllTargetMCs(); |
2782 | InitializeAllDisassemblers(); |
2783 | |
2784 | cl::HideUnrelatedOptions(Categories: {&JITLinkCategory, &getColorCategory()}); |
2785 | cl::ParseCommandLineOptions(argc, argv, Overview: "llvm jitlink tool" ); |
2786 | ExitOnErr.setBanner(std::string(argv[0]) + ": " ); |
2787 | |
2788 | /// If timers are enabled, create a JITLinkTimers instance. |
2789 | std::unique_ptr<JITLinkTimers> Timers = |
2790 | ShowTimes ? std::make_unique<JITLinkTimers>() : nullptr; |
2791 | |
2792 | auto [TT, Features] = getFirstFileTripleAndFeatures(); |
2793 | ExitOnErr(sanitizeArguments(TT, ArgV0: argv[0])); |
2794 | |
2795 | auto S = ExitOnErr(Session::Create(TT, Features)); |
2796 | |
2797 | enableStatistics(S&: *S, UsingOrcRuntime: !OrcRuntime.empty()); |
2798 | |
2799 | { |
2800 | TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr); |
2801 | ExitOnErr(addSessionInputs(S&: *S)); |
2802 | } |
2803 | |
2804 | if (PhonyExternals) |
2805 | addPhonyExternalsGenerator(S&: *S); |
2806 | |
2807 | if (ShowInitialExecutionSessionState) |
2808 | S->ES.dump(OS&: outs()); |
2809 | |
2810 | Expected<ExecutorSymbolDef> EntryPoint((ExecutorSymbolDef())); |
2811 | { |
2812 | ExpectedAsOutParameter<ExecutorSymbolDef> _(&EntryPoint); |
2813 | TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr); |
2814 | EntryPoint = getEntryPoint(S&: *S); |
2815 | } |
2816 | |
2817 | // Print any reports regardless of whether we succeeded or failed. |
2818 | if (ShowEntryExecutionSessionState) |
2819 | S->ES.dump(OS&: outs()); |
2820 | |
2821 | if (ShowAddrs) |
2822 | S->dumpSessionInfo(OS&: outs()); |
2823 | |
2824 | if (!EntryPoint) { |
2825 | if (Timers) |
2826 | Timers->JITLinkTG.printAll(OS&: errs()); |
2827 | reportLLVMJITLinkError(Err: EntryPoint.takeError()); |
2828 | ExitOnErr(S->ES.endSession()); |
2829 | exit(status: 1); |
2830 | } |
2831 | |
2832 | ExitOnErr(runChecks(S&: *S, TT: std::move(TT), Features: std::move(Features))); |
2833 | |
2834 | int Result = 0; |
2835 | if (!NoExec) { |
2836 | LLVM_DEBUG(dbgs() << "Running \"" << EntryPointName << "\"...\n" ); |
2837 | TimeRegion TR(Timers ? &Timers->RunTimer : nullptr); |
2838 | if (!OrcRuntime.empty()) |
2839 | Result = |
2840 | ExitOnErr(runWithRuntime(S&: *S, EntryPointAddr: ExecutorAddr(EntryPoint->getAddress()))); |
2841 | else |
2842 | Result = ExitOnErr( |
2843 | runWithoutRuntime(S&: *S, EntryPointAddr: ExecutorAddr(EntryPoint->getAddress()))); |
2844 | } |
2845 | |
2846 | // Destroy the session. |
2847 | ExitOnErr(S->ES.endSession()); |
2848 | S.reset(); |
2849 | |
2850 | if (Timers) |
2851 | Timers->JITLinkTG.printAll(OS&: errs()); |
2852 | |
2853 | // If the executing code set a test result override then use that. |
2854 | if (UseTestResultOverride) |
2855 | Result = TestResultOverride; |
2856 | |
2857 | return Result; |
2858 | } |
2859 | |