blob: 5ecf66ae9e41fb1893d2997020d74c372350a29f [file] [log] [blame]
Lang Hames11c8dfa52019-04-20 17:10:34 +00001//===- 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
17#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
18#include "llvm/MC/MCAsmInfo.h"
19#include "llvm/MC/MCContext.h"
20#include "llvm/MC/MCDisassembler/MCDisassembler.h"
21#include "llvm/MC/MCInstPrinter.h"
22#include "llvm/MC/MCInstrInfo.h"
23#include "llvm/MC/MCRegisterInfo.h"
24#include "llvm/MC/MCSubtargetInfo.h"
25#include "llvm/Object/COFF.h"
26#include "llvm/Object/MachO.h"
27#include "llvm/Object/ObjectFile.h"
28#include "llvm/Support/CommandLine.h"
29#include "llvm/Support/Debug.h"
30#include "llvm/Support/DynamicLibrary.h"
31#include "llvm/Support/InitLLVM.h"
32#include "llvm/Support/MemoryBuffer.h"
33#include "llvm/Support/TargetRegistry.h"
34#include "llvm/Support/TargetSelect.h"
35
36#include <list>
37#include <string>
38
Lang Hames11c8dfa52019-04-20 17:10:34 +000039#define DEBUG_TYPE "llvm-jitlink"
40
41using namespace llvm;
42using namespace llvm::jitlink;
43using namespace llvm::orc;
44
45static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore,
46 cl::desc("input files"));
47
48static cl::opt<bool> NoExec("noexec", cl::desc("Do not execute loaded code"),
49 cl::init(false));
50
51static cl::list<std::string>
52 CheckFiles("check", cl::desc("File containing verifier checks"),
53 cl::ZeroOrMore);
54
55static cl::opt<std::string>
56 EntryPointName("entry", cl::desc("Symbol to call as main entry point"),
57 cl::init(""));
58
59static cl::list<std::string> JITLinkDylibs(
60 "jld", cl::desc("Specifies the JITDylib to be used for any subsequent "
61 "input file arguments"));
62
63static cl::list<std::string>
64 Dylibs("dlopen", cl::desc("Dynamic libraries to load before linking"),
65 cl::ZeroOrMore);
66
Lang Hamesd959a602019-04-24 17:23:05 +000067static cl::list<std::string> InputArgv("args", cl::Positional,
68 cl::desc("<program arguments>..."),
69 cl::ZeroOrMore, cl::PositionalEatsArgs);
70
Lang Hames11c8dfa52019-04-20 17:10:34 +000071static cl::opt<bool>
72 NoProcessSymbols("no-process-syms",
73 cl::desc("Do not resolve to llvm-jitlink process symbols"),
74 cl::init(false));
75
Nico Weber405e62b2019-04-21 23:50:24 +000076static cl::list<std::string> AbsoluteDefs(
77 "define-abs",
78 cl::desc("Inject absolute symbol definitions (syntax: <name>=<addr>)"),
79 cl::ZeroOrMore);
Lang Hames11c8dfa52019-04-20 17:10:34 +000080
81static cl::opt<bool> ShowAddrs(
82 "show-addrs",
83 cl::desc("Print registered symbol, section, got and stub addresses"),
84 cl::init(false));
85
86static cl::opt<bool> ShowAtomGraph(
87 "show-graph",
88 cl::desc("Print the atom graph after fixups have been applied"),
89 cl::init(false));
90
91static cl::opt<bool> ShowSizes(
Lang Hamesbc76bbc2019-04-21 20:34:19 +000092 "show-sizes",
93 cl::desc("Show sizes pre- and post-dead stripping, and allocations"),
94 cl::init(false));
95
96static cl::opt<bool> ShowRelocatedSectionContents(
97 "show-relocated-section-contents",
98 cl::desc("show section contents after fixups have been applied"),
99 cl::init(false));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000100
101ExitOnError ExitOnErr;
102
103namespace llvm {
104
105static raw_ostream &
106operator<<(raw_ostream &OS, const Session::MemoryRegionInfo &MRI) {
107 return OS << "target addr = " << format("0x%016" PRIx64, MRI.TargetAddress)
108 << ", content: " << (const void *)MRI.Content.data() << " -- "
109 << (const void *)(MRI.Content.data() + MRI.Content.size()) << " ("
110 << MRI.Content.size() << " bytes)";
111}
112
113static raw_ostream &
114operator<<(raw_ostream &OS, const Session::SymbolInfoMap &SIM) {
115 OS << "Symbols:\n";
116 for (auto &SKV : SIM)
117 OS << " \"" << SKV.first() << "\" " << SKV.second << "\n";
118 return OS;
119}
120
121static raw_ostream &
122operator<<(raw_ostream &OS, const Session::FileInfo &FI) {
123 for (auto &SIKV : FI.SectionInfos)
124 OS << " Section \"" << SIKV.first() << "\": " << SIKV.second << "\n";
125 for (auto &GOTKV : FI.GOTEntryInfos)
126 OS << " GOT \"" << GOTKV.first() << "\": " << GOTKV.second << "\n";
127 for (auto &StubKV : FI.StubInfos)
128 OS << " Stub \"" << StubKV.first() << "\": " << StubKV.second << "\n";
129 return OS;
130}
131
132static raw_ostream &
133operator<<(raw_ostream &OS, const Session::FileInfoMap &FIM) {
134 for (auto &FIKV : FIM)
135 OS << "File \"" << FIKV.first() << "\":\n" << FIKV.second;
136 return OS;
137}
138
139static uint64_t computeTotalAtomSizes(AtomGraph &G) {
140 uint64_t TotalSize = 0;
141 for (auto *DA : G.defined_atoms())
142 if (DA->isZeroFill())
143 TotalSize += DA->getZeroFillSize();
144 else
145 TotalSize += DA->getContent().size();
146 return TotalSize;
147}
148
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000149static void dumpSectionContents(raw_ostream &OS, AtomGraph &G) {
150 constexpr JITTargetAddress DumpWidth = 16;
151 static_assert(isPowerOf2_64(DumpWidth), "DumpWidth must be a power of two");
152
153 // Put sections in address order.
154 std::vector<Section *> Sections;
155 for (auto &S : G.sections())
156 Sections.push_back(&S);
157
158 std::sort(Sections.begin(), Sections.end(),
159 [](const Section *LHS, const Section *RHS) {
160 if (LHS->atoms_empty() && RHS->atoms_empty())
161 return false;
162 if (LHS->atoms_empty())
163 return false;
164 if (RHS->atoms_empty())
165 return true;
166 return (*LHS->atoms().begin())->getAddress() <
167 (*RHS->atoms().begin())->getAddress();
168 });
169
170 for (auto *S : Sections) {
171 OS << S->getName() << " content:";
172 if (S->atoms_empty()) {
173 OS << "\n section empty\n";
174 continue;
175 }
176
177 // Sort atoms into order, then render.
178 std::vector<DefinedAtom *> Atoms(S->atoms().begin(), S->atoms().end());
179 std::sort(Atoms.begin(), Atoms.end(),
180 [](const DefinedAtom *LHS, const DefinedAtom *RHS) {
181 return LHS->getAddress() < RHS->getAddress();
182 });
183
184 JITTargetAddress NextAddr = Atoms.front()->getAddress() & ~(DumpWidth - 1);
185 for (auto *DA : Atoms) {
186 bool IsZeroFill = DA->isZeroFill();
187 JITTargetAddress AtomStart = DA->getAddress();
188 JITTargetAddress AtomSize =
189 IsZeroFill ? DA->getZeroFillSize() : DA->getContent().size();
190 JITTargetAddress AtomEnd = AtomStart + AtomSize;
191 const uint8_t *AtomData =
192 IsZeroFill ? nullptr : DA->getContent().bytes_begin();
193
194 // Pad any space before the atom starts.
195 while (NextAddr != AtomStart) {
196 if (NextAddr % DumpWidth == 0)
197 OS << formatv("\n{0:x16}:", NextAddr);
198 OS << " ";
199 ++NextAddr;
200 }
201
202 // Render the atom content.
203 while (NextAddr != AtomEnd) {
204 if (NextAddr % DumpWidth == 0)
205 OS << formatv("\n{0:x16}:", NextAddr);
206 if (IsZeroFill)
207 OS << " 00";
208 else
209 OS << formatv(" {0:x-2}", AtomData[NextAddr - AtomStart]);
210 ++NextAddr;
211 }
212 }
213 OS << "\n";
214 }
215}
216
Lang Hamesa9fdf372019-04-26 22:58:39 +0000217Session::Session(Triple TT) : ObjLayer(ES, MemMgr), TT(std::move(TT)) {
218
219 /// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the
220 /// Session.
221 class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin {
222 public:
223 JITLinkSessionPlugin(Session &S) : S(S) {}
224 void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
225 PassConfiguration &PassConfig) {
226 S.modifyPassConfig(TT, PassConfig);
227 }
228
229 private:
230 Session &S;
231 };
232
233 if (!NoExec && !TT.isOSWindows())
234 ObjLayer.addPlugin(llvm::make_unique<LocalEHFrameRegistrationPlugin>());
235
236 ObjLayer.addPlugin(llvm::make_unique<JITLinkSessionPlugin>(*this));
237}
Lang Hames11c8dfa52019-04-20 17:10:34 +0000238
239void Session::dumpSessionInfo(raw_ostream &OS) {
240 OS << "Registered addresses:\n" << SymbolInfos << FileInfos;
241}
242
243void Session::modifyPassConfig(const Triple &FTT,
244 PassConfiguration &PassConfig) {
245 if (!CheckFiles.empty())
246 PassConfig.PostFixupPasses.push_back([this](AtomGraph &G) {
247 if (TT.getObjectFormat() == Triple::MachO)
248 return registerMachOStubsAndGOT(*this, G);
249 return make_error<StringError>("Unsupported object format for GOT/stub "
250 "registration",
251 inconvertibleErrorCode());
252 });
253
254 if (ShowAtomGraph)
255 PassConfig.PostFixupPasses.push_back([](AtomGraph &G) -> Error {
256 outs() << "Atom graph post-fixup:\n";
257 G.dump(outs());
258 return Error::success();
259 });
260
261
262 if (ShowSizes) {
263 PassConfig.PrePrunePasses.push_back([this](AtomGraph &G) -> Error {
264 SizeBeforePruning += computeTotalAtomSizes(G);
265 return Error::success();
266 });
267 PassConfig.PostFixupPasses.push_back([this](AtomGraph &G) -> Error {
268 SizeAfterFixups += computeTotalAtomSizes(G);
269 return Error::success();
270 });
271 }
272
Lang Hamesbc76bbc2019-04-21 20:34:19 +0000273 if (ShowRelocatedSectionContents)
274 PassConfig.PostFixupPasses.push_back([](AtomGraph &G) -> Error {
275 outs() << "Relocated section contents for " << G.getName() << ":\n";
276 dumpSectionContents(outs(), G);
277 return Error::success();
278 });
Lang Hames11c8dfa52019-04-20 17:10:34 +0000279}
280
281Expected<Session::FileInfo &> Session::findFileInfo(StringRef FileName) {
282 auto FileInfoItr = FileInfos.find(FileName);
283 if (FileInfoItr == FileInfos.end())
284 return make_error<StringError>("file \"" + FileName + "\" not recognized",
285 inconvertibleErrorCode());
286 return FileInfoItr->second;
287}
288
289Expected<Session::MemoryRegionInfo &>
290Session::findSectionInfo(StringRef FileName, StringRef SectionName) {
291 auto FI = findFileInfo(FileName);
292 if (!FI)
293 return FI.takeError();
294 auto SecInfoItr = FI->SectionInfos.find(SectionName);
295 if (SecInfoItr == FI->SectionInfos.end())
296 return make_error<StringError>("no section \"" + SectionName +
297 "\" registered for file \"" + FileName +
298 "\"",
299 inconvertibleErrorCode());
300 return SecInfoItr->second;
301}
302
303Expected<Session::MemoryRegionInfo &>
304Session::findStubInfo(StringRef FileName, StringRef TargetName) {
305 auto FI = findFileInfo(FileName);
306 if (!FI)
307 return FI.takeError();
308 auto StubInfoItr = FI->StubInfos.find(TargetName);
309 if (StubInfoItr == FI->StubInfos.end())
310 return make_error<StringError>("no stub for \"" + TargetName +
311 "\" registered for file \"" + FileName +
312 "\"",
313 inconvertibleErrorCode());
314 return StubInfoItr->second;
315}
316
317Expected<Session::MemoryRegionInfo &>
318Session::findGOTEntryInfo(StringRef FileName, StringRef TargetName) {
319 auto FI = findFileInfo(FileName);
320 if (!FI)
321 return FI.takeError();
322 auto GOTInfoItr = FI->GOTEntryInfos.find(TargetName);
323 if (GOTInfoItr == FI->GOTEntryInfos.end())
324 return make_error<StringError>("no GOT entry for \"" + TargetName +
325 "\" registered for file \"" + FileName +
326 "\"",
327 inconvertibleErrorCode());
328 return GOTInfoItr->second;
329}
330
331bool Session::isSymbolRegistered(StringRef SymbolName) {
332 return SymbolInfos.count(SymbolName);
333}
334
335Expected<Session::MemoryRegionInfo &>
336Session::findSymbolInfo(StringRef SymbolName, Twine ErrorMsgStem) {
337 auto SymInfoItr = SymbolInfos.find(SymbolName);
338 if (SymInfoItr == SymbolInfos.end())
339 return make_error<StringError>(ErrorMsgStem + ": symbol " + SymbolName +
340 " not found",
341 inconvertibleErrorCode());
342 return SymInfoItr->second;
343}
344
345} // end namespace llvm
346
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000347Triple getFirstFileTriple() {
348 assert(!InputFiles.empty() && "InputFiles can not be empty");
349 auto ObjBuffer =
350 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front())));
351 auto Obj = ExitOnErr(
352 object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
353 return Obj->makeTriple();
354}
355
Lang Hamesd959a602019-04-24 17:23:05 +0000356Error sanitizeArguments(const Session &S) {
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000357 if (EntryPointName.empty()) {
358 if (S.TT.getObjectFormat() == Triple::MachO)
359 EntryPointName = "_main";
360 else
361 EntryPointName = "main";
362 }
Lang Hamesd959a602019-04-24 17:23:05 +0000363
364 if (NoExec && !InputArgv.empty())
365 outs() << "Warning: --args passed to -noexec run will be ignored.\n";
366
367 return Error::success();
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000368}
369
Lang Hames11c8dfa52019-04-20 17:10:34 +0000370Error loadProcessSymbols(Session &S) {
371 std::string ErrMsg;
372 if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &ErrMsg))
373 return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
374
375 char GlobalPrefix = S.TT.getObjectFormat() == Triple::MachO ? '_' : '\0';
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000376 auto InternedEntryPointName = S.ES.intern(EntryPointName);
377 auto FilterMainEntryPoint = [InternedEntryPointName](SymbolStringPtr Name) {
378 return Name != InternedEntryPointName;
379 };
380 S.ES.getMainJITDylib().setGenerator(
381 ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
382 GlobalPrefix, FilterMainEntryPoint)));
Lang Hames11c8dfa52019-04-20 17:10:34 +0000383
384 return Error::success();
385}
386
387Error loadDylibs() {
388 // FIXME: This should all be handled inside DynamicLibrary.
389 for (const auto &Dylib : Dylibs) {
390 if (!sys::fs::is_regular_file(Dylib))
391 return make_error<StringError>("\"" + Dylib + "\" is not a regular file",
392 inconvertibleErrorCode());
393 std::string ErrMsg;
394 if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))
395 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
396 }
397
398 return Error::success();
399}
400
Lang Hames11c8dfa52019-04-20 17:10:34 +0000401Error loadObjects(Session &S) {
402
403 std::map<unsigned, JITDylib *> IdxToJLD;
404
405 // First, set up JITDylibs.
406 LLVM_DEBUG(dbgs() << "Creating JITDylibs...\n");
407 {
408 // Create a "main" JITLinkDylib.
409 auto &MainJD = S.ES.getMainJITDylib();
410 IdxToJLD[0] = &MainJD;
411 S.JDSearchOrder.push_back(&MainJD);
412 LLVM_DEBUG(dbgs() << " 0: " << MainJD.getName() << "\n");
413
414 // Add any extra JITLinkDylibs from the command line.
415 std::string JDNamePrefix("lib");
416 for (auto JLDItr = JITLinkDylibs.begin(), JLDEnd = JITLinkDylibs.end();
417 JLDItr != JLDEnd; ++JLDItr) {
418 auto &JD = S.ES.createJITDylib(JDNamePrefix + *JLDItr);
419 unsigned JDIdx =
420 JITLinkDylibs.getPosition(JLDItr - JITLinkDylibs.begin());
421 IdxToJLD[JDIdx] = &JD;
422 S.JDSearchOrder.push_back(&JD);
423 LLVM_DEBUG(dbgs() << " " << JDIdx << ": " << JD.getName() << "\n");
424 }
425
426 // Set every dylib to link against every other, in command line order.
427 for (auto *JD : S.JDSearchOrder) {
428 JITDylibSearchList O;
429 for (auto *JD2 : S.JDSearchOrder) {
430 if (JD2 == JD)
431 continue;
432 O.push_back(std::make_pair(JD2, false));
433 }
434 JD->setSearchOrder(std::move(O));
435 }
436 }
437
438 // Load each object into the corresponding JITDylib..
439 LLVM_DEBUG(dbgs() << "Adding objects...\n");
440 for (auto InputFileItr = InputFiles.begin(), InputFileEnd = InputFiles.end();
441 InputFileItr != InputFileEnd; ++InputFileItr) {
442 unsigned InputFileArgIdx =
443 InputFiles.getPosition(InputFileItr - InputFiles.begin());
444 StringRef InputFile = *InputFileItr;
445 auto &JD = *std::prev(IdxToJLD.lower_bound(InputFileArgIdx))->second;
446 LLVM_DEBUG(dbgs() << " " << InputFileArgIdx << ": \"" << InputFile
447 << "\" to " << JD.getName() << "\n";);
448 auto ObjBuffer =
449 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFile)));
450 ExitOnErr(S.ObjLayer.add(JD, std::move(ObjBuffer)));
451 }
452
453 // Define absolute symbols.
454 LLVM_DEBUG(dbgs() << "Defining absolute symbols...\n");
455 for (auto AbsDefItr = AbsoluteDefs.begin(), AbsDefEnd = AbsoluteDefs.end();
456 AbsDefItr != AbsDefEnd; ++AbsDefItr) {
457 unsigned AbsDefArgIdx =
458 AbsoluteDefs.getPosition(AbsDefItr - AbsoluteDefs.begin());
459 auto &JD = *std::prev(IdxToJLD.lower_bound(AbsDefArgIdx))->second;
460
461 StringRef AbsDefStmt = *AbsDefItr;
462 size_t EqIdx = AbsDefStmt.find_first_of('=');
463 if (EqIdx == StringRef::npos)
464 return make_error<StringError>("Invalid absolute define \"" + AbsDefStmt +
465 "\". Syntax: <name>=<addr>",
466 inconvertibleErrorCode());
467 StringRef Name = AbsDefStmt.substr(0, EqIdx).trim();
468 StringRef AddrStr = AbsDefStmt.substr(EqIdx + 1).trim();
469
470 uint64_t Addr;
471 if (AddrStr.getAsInteger(0, Addr))
472 return make_error<StringError>("Invalid address expression \"" + AddrStr +
473 "\" in absolute define \"" + AbsDefStmt +
474 "\"",
475 inconvertibleErrorCode());
476 JITEvaluatedSymbol AbsDef(Addr, JITSymbolFlags::Exported);
477 if (auto Err = JD.define(absoluteSymbols({{S.ES.intern(Name), AbsDef}})))
478 return Err;
479
480 // Register the absolute symbol with the session symbol infos.
481 S.SymbolInfos[Name] = { StringRef(), Addr };
482 }
483
484 LLVM_DEBUG({
485 dbgs() << "Dylib search order is [ ";
486 for (auto *JD : S.JDSearchOrder)
487 dbgs() << JD->getName() << " ";
488 dbgs() << "]\n";
489 });
490
491 return Error::success();
492}
493
494Error runChecks(Session &S) {
495
496 auto TripleName = S.TT.str();
497 std::string ErrorStr;
498 const Target *TheTarget = TargetRegistry::lookupTarget("", S.TT, ErrorStr);
499 if (!TheTarget)
500 ExitOnErr(make_error<StringError>("Error accessing target '" + TripleName +
501 "': " + ErrorStr,
502 inconvertibleErrorCode()));
503
504 std::unique_ptr<MCSubtargetInfo> STI(
505 TheTarget->createMCSubtargetInfo(TripleName, "", ""));
506 if (!STI)
507 ExitOnErr(
508 make_error<StringError>("Unable to create subtarget for " + TripleName,
509 inconvertibleErrorCode()));
510
511 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
512 if (!MRI)
513 ExitOnErr(make_error<StringError>("Unable to create target register info "
514 "for " +
515 TripleName,
516 inconvertibleErrorCode()));
517
518 std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName));
519 if (!MAI)
520 ExitOnErr(make_error<StringError>("Unable to create target asm info " +
521 TripleName,
522 inconvertibleErrorCode()));
523
524 MCContext Ctx(MAI.get(), MRI.get(), nullptr);
525
526 std::unique_ptr<MCDisassembler> Disassembler(
527 TheTarget->createMCDisassembler(*STI, Ctx));
528 if (!Disassembler)
529 ExitOnErr(make_error<StringError>("Unable to create disassembler for " +
530 TripleName,
531 inconvertibleErrorCode()));
532
533 std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
534
535 std::unique_ptr<MCInstPrinter> InstPrinter(
536 TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI));
537
538 auto IsSymbolValid = [&S](StringRef Symbol) {
539 return S.isSymbolRegistered(Symbol);
540 };
541
542 auto GetSymbolInfo = [&S](StringRef Symbol) {
543 return S.findSymbolInfo(Symbol, "Can not get symbol info");
544 };
545
546 auto GetSectionInfo = [&S](StringRef FileName, StringRef SectionName) {
547 return S.findSectionInfo(FileName, SectionName);
548 };
549
550 auto GetStubInfo = [&S](StringRef FileName, StringRef SectionName) {
551 return S.findStubInfo(FileName, SectionName);
552 };
553
554 auto GetGOTInfo = [&S](StringRef FileName, StringRef SectionName) {
555 return S.findGOTEntryInfo(FileName, SectionName);
556 };
557
558 RuntimeDyldChecker Checker(
559 IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,
560 S.TT.isLittleEndian() ? support::little : support::big,
561 Disassembler.get(), InstPrinter.get(), dbgs());
562
563 for (auto &CheckFile : CheckFiles) {
564 auto CheckerFileBuf =
565 ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(CheckFile)));
566 if (!Checker.checkAllRulesInBuffer("# jitlink-check:", &*CheckerFileBuf))
567 ExitOnErr(make_error<StringError>(
568 "Some checks in " + CheckFile + " failed", inconvertibleErrorCode()));
569 }
570
571 return Error::success();
572}
573
574static void dumpSessionStats(Session &S) {
575 if (ShowSizes)
576 outs() << "Total size of all atoms before pruning: " << S.SizeBeforePruning
577 << "\nTotal size of all atoms after fixups: " << S.SizeAfterFixups
578 << "\n";
579}
580
581static Expected<JITEvaluatedSymbol> getMainEntryPoint(Session &S) {
Lang Hames11c8dfa52019-04-20 17:10:34 +0000582 return S.ES.lookup(S.JDSearchOrder, EntryPointName);
583}
584
585Expected<int> runEntryPoint(Session &S, JITEvaluatedSymbol EntryPoint) {
586 assert(EntryPoint.getAddress() && "Entry point address should not be null");
587
588 constexpr const char *JITProgramName = "<llvm-jitlink jit'd code>";
589 auto PNStorage = llvm::make_unique<char[]>(strlen(JITProgramName) + 1);
590 strcpy(PNStorage.get(), JITProgramName);
591
592 std::vector<const char *> EntryPointArgs;
593 EntryPointArgs.push_back(PNStorage.get());
Lang Hamesd959a602019-04-24 17:23:05 +0000594 for (auto &InputArg : InputArgv)
595 EntryPointArgs.push_back(InputArg.data());
Lang Hames11c8dfa52019-04-20 17:10:34 +0000596 EntryPointArgs.push_back(nullptr);
597
598 using MainTy = int (*)(int, const char *[]);
599 MainTy EntryPointPtr = reinterpret_cast<MainTy>(EntryPoint.getAddress());
600
601 return EntryPointPtr(EntryPointArgs.size() - 1, EntryPointArgs.data());
602}
603
604int main(int argc, char *argv[]) {
605 InitLLVM X(argc, argv);
606
607 InitializeAllTargetInfos();
608 InitializeAllTargetMCs();
609 InitializeAllDisassemblers();
610
611 cl::ParseCommandLineOptions(argc, argv, "llvm jitlink tool");
612 ExitOnErr.setBanner(std::string(argv[0]) + ": ");
613
614 Session S(getFirstFileTriple());
615
Lang Hamesd959a602019-04-24 17:23:05 +0000616 ExitOnErr(sanitizeArguments(S));
Lang Hamesb1ba4d82019-04-24 15:15:55 +0000617
Lang Hames11c8dfa52019-04-20 17:10:34 +0000618 if (!NoProcessSymbols)
619 ExitOnErr(loadProcessSymbols(S));
620 ExitOnErr(loadDylibs());
621
622 ExitOnErr(loadObjects(S));
623
624 auto EntryPoint = ExitOnErr(getMainEntryPoint(S));
625
626 if (ShowAddrs)
627 S.dumpSessionInfo(outs());
628
629 ExitOnErr(runChecks(S));
630
631 dumpSessionStats(S);
632
633 if (NoExec)
634 return 0;
635
636 return ExitOnErr(runEntryPoint(S, EntryPoint));
637}