1 | //===-- llvm-rtdyld.cpp - MCJIT Testing Tool ------------------------------===// |
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 is a testing tool for use with the MC-JIT LLVM components. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/ADT/StringMap.h" |
14 | #include "llvm/DebugInfo/DIContext.h" |
15 | #include "llvm/DebugInfo/DWARF/DWARFContext.h" |
16 | #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" |
17 | #include "llvm/ExecutionEngine/RuntimeDyld.h" |
18 | #include "llvm/ExecutionEngine/RuntimeDyldChecker.h" |
19 | #include "llvm/MC/MCAsmInfo.h" |
20 | #include "llvm/MC/MCContext.h" |
21 | #include "llvm/MC/MCDisassembler/MCDisassembler.h" |
22 | #include "llvm/MC/MCInstPrinter.h" |
23 | #include "llvm/MC/MCInstrInfo.h" |
24 | #include "llvm/MC/MCRegisterInfo.h" |
25 | #include "llvm/MC/MCSubtargetInfo.h" |
26 | #include "llvm/MC/MCTargetOptions.h" |
27 | #include "llvm/MC/TargetRegistry.h" |
28 | #include "llvm/Object/SymbolSize.h" |
29 | #include "llvm/Support/CommandLine.h" |
30 | #include "llvm/Support/DynamicLibrary.h" |
31 | #include "llvm/Support/FileSystem.h" |
32 | #include "llvm/Support/InitLLVM.h" |
33 | #include "llvm/Support/MSVCErrorWorkarounds.h" |
34 | #include "llvm/Support/Memory.h" |
35 | #include "llvm/Support/MemoryBuffer.h" |
36 | #include "llvm/Support/Path.h" |
37 | #include "llvm/Support/TargetSelect.h" |
38 | #include "llvm/Support/Timer.h" |
39 | #include "llvm/Support/raw_ostream.h" |
40 | |
41 | #include <future> |
42 | #include <list> |
43 | |
44 | using namespace llvm; |
45 | using namespace llvm::object; |
46 | |
47 | static cl::OptionCategory RTDyldCategory("RTDyld Options" ); |
48 | |
49 | static cl::list<std::string> InputFileList(cl::Positional, |
50 | cl::desc("<input files>" ), |
51 | cl::cat(RTDyldCategory)); |
52 | |
53 | enum ActionType { |
54 | AC_Execute, |
55 | AC_PrintObjectLineInfo, |
56 | AC_PrintLineInfo, |
57 | AC_PrintDebugLineInfo, |
58 | AC_Verify |
59 | }; |
60 | |
61 | static cl::opt<ActionType> Action( |
62 | cl::desc("Action to perform:" ), cl::init(Val: AC_Execute), |
63 | cl::values( |
64 | clEnumValN(AC_Execute, "execute" , |
65 | "Load, link, and execute the inputs." ), |
66 | clEnumValN(AC_PrintLineInfo, "printline" , |
67 | "Load, link, and print line information for each function." ), |
68 | clEnumValN(AC_PrintDebugLineInfo, "printdebugline" , |
69 | "Load, link, and print line information for each function " |
70 | "using the debug object" ), |
71 | clEnumValN(AC_PrintObjectLineInfo, "printobjline" , |
72 | "Like -printlineinfo but does not load the object first" ), |
73 | clEnumValN(AC_Verify, "verify" , |
74 | "Load, link and verify the resulting memory image." )), |
75 | cl::cat(RTDyldCategory)); |
76 | |
77 | static cl::opt<std::string> |
78 | EntryPoint("entry" , cl::desc("Function to call as entry point." ), |
79 | cl::init(Val: "_main" ), cl::cat(RTDyldCategory)); |
80 | |
81 | static cl::list<std::string> Dylibs("dylib" , cl::desc("Add library." ), |
82 | cl::cat(RTDyldCategory)); |
83 | |
84 | static cl::list<std::string> InputArgv("args" , cl::Positional, |
85 | cl::desc("<program arguments>..." ), |
86 | cl::PositionalEatsArgs, |
87 | cl::cat(RTDyldCategory)); |
88 | |
89 | static cl::opt<std::string> |
90 | TripleName("triple" , cl::desc("Target triple for disassembler" ), |
91 | cl::cat(RTDyldCategory)); |
92 | |
93 | static cl::opt<std::string> |
94 | MCPU("mcpu" , |
95 | cl::desc("Target a specific cpu type (-mcpu=help for details)" ), |
96 | cl::value_desc("cpu-name" ), cl::init(Val: "" ), cl::cat(RTDyldCategory)); |
97 | |
98 | static cl::list<std::string> |
99 | CheckFiles("check" , |
100 | cl::desc("File containing RuntimeDyld verifier checks." ), |
101 | cl::cat(RTDyldCategory)); |
102 | |
103 | static cl::opt<uint64_t> |
104 | PreallocMemory("preallocate" , |
105 | cl::desc("Allocate memory upfront rather than on-demand" ), |
106 | cl::init(Val: 0), cl::cat(RTDyldCategory)); |
107 | |
108 | static cl::opt<uint64_t> TargetAddrStart( |
109 | "target-addr-start" , |
110 | cl::desc("For -verify only: start of phony target address " |
111 | "range." ), |
112 | cl::init(Val: 4096), // Start at "page 1" - no allocating at "null". |
113 | cl::Hidden, cl::cat(RTDyldCategory)); |
114 | |
115 | static cl::opt<uint64_t> TargetAddrEnd( |
116 | "target-addr-end" , |
117 | cl::desc("For -verify only: end of phony target address range." ), |
118 | cl::init(Val: ~0ULL), cl::Hidden, cl::cat(RTDyldCategory)); |
119 | |
120 | static cl::opt<uint64_t> TargetSectionSep( |
121 | "target-section-sep" , |
122 | cl::desc("For -verify only: Separation between sections in " |
123 | "phony target address space." ), |
124 | cl::init(Val: 0), cl::Hidden, cl::cat(RTDyldCategory)); |
125 | |
126 | static cl::list<std::string> |
127 | SpecificSectionMappings("map-section" , |
128 | cl::desc("For -verify only: Map a section to a " |
129 | "specific address." ), |
130 | cl::Hidden, cl::cat(RTDyldCategory)); |
131 | |
132 | static cl::list<std::string> DummySymbolMappings( |
133 | "dummy-extern" , |
134 | cl::desc("For -verify only: Inject a symbol into the extern " |
135 | "symbol table." ), |
136 | cl::Hidden, cl::cat(RTDyldCategory)); |
137 | |
138 | static cl::opt<bool> PrintAllocationRequests( |
139 | "print-alloc-requests" , |
140 | cl::desc("Print allocation requests made to the memory " |
141 | "manager by RuntimeDyld" ), |
142 | cl::Hidden, cl::cat(RTDyldCategory)); |
143 | |
144 | static cl::opt<bool> ShowTimes("show-times" , |
145 | cl::desc("Show times for llvm-rtdyld phases" ), |
146 | cl::init(Val: false), cl::cat(RTDyldCategory)); |
147 | |
148 | ExitOnError ExitOnErr; |
149 | |
150 | struct RTDyldTimers { |
151 | TimerGroup RTDyldTG{"llvm-rtdyld timers" , "timers for llvm-rtdyld phases" }; |
152 | Timer LoadObjectsTimer{"load" , "time to load/add object files" , RTDyldTG}; |
153 | Timer LinkTimer{"link" , "time to link object files" , RTDyldTG}; |
154 | Timer RunTimer{"run" , "time to execute jitlink'd code" , RTDyldTG}; |
155 | }; |
156 | |
157 | std::unique_ptr<RTDyldTimers> Timers; |
158 | |
159 | /* *** */ |
160 | |
161 | using SectionIDMap = StringMap<unsigned>; |
162 | using FileToSectionIDMap = StringMap<SectionIDMap>; |
163 | |
164 | void dumpFileToSectionIDMap(const FileToSectionIDMap &FileToSecIDMap) { |
165 | for (const auto &KV : FileToSecIDMap) { |
166 | llvm::dbgs() << "In " << KV.first() << "\n" ; |
167 | for (auto &KV2 : KV.second) |
168 | llvm::dbgs() << " \"" << KV2.first() << "\" -> " << KV2.second << "\n" ; |
169 | } |
170 | } |
171 | |
172 | Expected<unsigned> getSectionId(const FileToSectionIDMap &FileToSecIDMap, |
173 | StringRef FileName, StringRef SectionName) { |
174 | auto I = FileToSecIDMap.find(Key: FileName); |
175 | if (I == FileToSecIDMap.end()) |
176 | return make_error<StringError>(Args: "No file named " + FileName, |
177 | Args: inconvertibleErrorCode()); |
178 | auto &SectionIDs = I->second; |
179 | auto J = SectionIDs.find(Key: SectionName); |
180 | if (J == SectionIDs.end()) |
181 | return make_error<StringError>(Args: "No section named \"" + SectionName + |
182 | "\" in file " + FileName, |
183 | Args: inconvertibleErrorCode()); |
184 | return J->second; |
185 | } |
186 | |
187 | // A trivial memory manager that doesn't do anything fancy, just uses the |
188 | // support library allocation routines directly. |
189 | class TrivialMemoryManager : public RTDyldMemoryManager { |
190 | public: |
191 | struct SectionInfo { |
192 | SectionInfo(StringRef Name, sys::MemoryBlock MB, unsigned SectionID) |
193 | : Name(std::string(Name)), MB(std::move(MB)), SectionID(SectionID) {} |
194 | std::string Name; |
195 | sys::MemoryBlock MB; |
196 | unsigned SectionID = ~0U; |
197 | }; |
198 | |
199 | SmallVector<SectionInfo, 16> FunctionMemory; |
200 | SmallVector<SectionInfo, 16> DataMemory; |
201 | |
202 | uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, |
203 | unsigned SectionID, |
204 | StringRef SectionName) override; |
205 | uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, |
206 | unsigned SectionID, StringRef SectionName, |
207 | bool IsReadOnly) override; |
208 | TrivialMemoryManager::TLSSection |
209 | allocateTLSSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, |
210 | StringRef SectionName) override; |
211 | |
212 | /// If non null, records subsequent Name -> SectionID mappings. |
213 | void setSectionIDsMap(SectionIDMap *SecIDMap) { |
214 | this->SecIDMap = SecIDMap; |
215 | } |
216 | |
217 | void *getPointerToNamedFunction(const std::string &Name, |
218 | bool AbortOnFailure = true) override { |
219 | return nullptr; |
220 | } |
221 | |
222 | bool finalizeMemory(std::string *ErrMsg) override { return false; } |
223 | |
224 | void addDummySymbol(const std::string &Name, uint64_t Addr) { |
225 | DummyExterns[Name] = Addr; |
226 | } |
227 | |
228 | JITSymbol findSymbol(const std::string &Name) override { |
229 | auto I = DummyExterns.find(x: Name); |
230 | |
231 | if (I != DummyExterns.end()) |
232 | return JITSymbol(I->second, JITSymbolFlags::Exported); |
233 | |
234 | if (auto Sym = RTDyldMemoryManager::findSymbol(Name)) |
235 | return Sym; |
236 | else if (auto Err = Sym.takeError()) |
237 | ExitOnErr(std::move(Err)); |
238 | else |
239 | ExitOnErr(make_error<StringError>(Args: "Could not find definition for \"" + |
240 | Name + "\"" , |
241 | Args: inconvertibleErrorCode())); |
242 | llvm_unreachable("Should have returned or exited by now" ); |
243 | } |
244 | |
245 | void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, |
246 | size_t Size) override {} |
247 | void deregisterEHFrames() override {} |
248 | |
249 | void preallocateSlab(uint64_t Size) { |
250 | std::error_code EC; |
251 | sys::MemoryBlock MB = |
252 | sys::Memory::allocateMappedMemory(NumBytes: Size, NearBlock: nullptr, |
253 | Flags: sys::Memory::MF_READ | |
254 | sys::Memory::MF_WRITE, |
255 | EC); |
256 | if (!MB.base()) |
257 | report_fatal_error(reason: Twine("Can't allocate enough memory: " ) + |
258 | EC.message()); |
259 | |
260 | PreallocSlab = MB; |
261 | UsePreallocation = true; |
262 | SlabSize = Size; |
263 | } |
264 | |
265 | uint8_t *allocateFromSlab(uintptr_t Size, unsigned Alignment, bool isCode, |
266 | StringRef SectionName, unsigned SectionID) { |
267 | Size = alignTo(Value: Size, Align: Alignment); |
268 | if (CurrentSlabOffset + Size > SlabSize) |
269 | report_fatal_error(reason: "Can't allocate enough memory. Tune --preallocate" ); |
270 | |
271 | uintptr_t OldSlabOffset = CurrentSlabOffset; |
272 | sys::MemoryBlock MB((void *)OldSlabOffset, Size); |
273 | if (isCode) |
274 | FunctionMemory.push_back(Elt: SectionInfo(SectionName, MB, SectionID)); |
275 | else |
276 | DataMemory.push_back(Elt: SectionInfo(SectionName, MB, SectionID)); |
277 | CurrentSlabOffset += Size; |
278 | return (uint8_t*)OldSlabOffset; |
279 | } |
280 | |
281 | private: |
282 | std::map<std::string, uint64_t> DummyExterns; |
283 | sys::MemoryBlock PreallocSlab; |
284 | bool UsePreallocation = false; |
285 | uintptr_t SlabSize = 0; |
286 | uintptr_t CurrentSlabOffset = 0; |
287 | SectionIDMap *SecIDMap = nullptr; |
288 | #if defined(__x86_64__) && defined(__ELF__) && defined(__linux__) |
289 | unsigned UsedTLSStorage = 0; |
290 | #endif |
291 | }; |
292 | |
293 | uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, |
294 | unsigned Alignment, |
295 | unsigned SectionID, |
296 | StringRef SectionName) { |
297 | if (PrintAllocationRequests) |
298 | outs() << "allocateCodeSection(Size = " << Size << ", Alignment = " |
299 | << Alignment << ", SectionName = " << SectionName << ")\n" ; |
300 | |
301 | if (SecIDMap) |
302 | (*SecIDMap)[SectionName] = SectionID; |
303 | |
304 | if (UsePreallocation) |
305 | return allocateFromSlab(Size, Alignment, isCode: true /* isCode */, |
306 | SectionName, SectionID); |
307 | |
308 | std::error_code EC; |
309 | sys::MemoryBlock MB = |
310 | sys::Memory::allocateMappedMemory(NumBytes: Size, NearBlock: nullptr, |
311 | Flags: sys::Memory::MF_READ | |
312 | sys::Memory::MF_WRITE, |
313 | EC); |
314 | if (!MB.base()) |
315 | report_fatal_error(reason: Twine("MemoryManager allocation failed: " ) + |
316 | EC.message()); |
317 | FunctionMemory.push_back(Elt: SectionInfo(SectionName, MB, SectionID)); |
318 | return (uint8_t*)MB.base(); |
319 | } |
320 | |
321 | uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size, |
322 | unsigned Alignment, |
323 | unsigned SectionID, |
324 | StringRef SectionName, |
325 | bool IsReadOnly) { |
326 | if (PrintAllocationRequests) |
327 | outs() << "allocateDataSection(Size = " << Size << ", Alignment = " |
328 | << Alignment << ", SectionName = " << SectionName << ")\n" ; |
329 | |
330 | if (SecIDMap) |
331 | (*SecIDMap)[SectionName] = SectionID; |
332 | |
333 | if (UsePreallocation) |
334 | return allocateFromSlab(Size, Alignment, isCode: false /* isCode */, SectionName, |
335 | SectionID); |
336 | |
337 | std::error_code EC; |
338 | sys::MemoryBlock MB = |
339 | sys::Memory::allocateMappedMemory(NumBytes: Size, NearBlock: nullptr, |
340 | Flags: sys::Memory::MF_READ | |
341 | sys::Memory::MF_WRITE, |
342 | EC); |
343 | if (!MB.base()) |
344 | report_fatal_error(reason: Twine("MemoryManager allocation failed: " ) + |
345 | EC.message()); |
346 | DataMemory.push_back(Elt: SectionInfo(SectionName, MB, SectionID)); |
347 | return (uint8_t*)MB.base(); |
348 | } |
349 | |
350 | // In case the execution needs TLS storage, we define a very small TLS memory |
351 | // area here that will be used in allocateTLSSection(). |
352 | #if defined(__x86_64__) && defined(__ELF__) && defined(__linux__) |
353 | extern "C" { |
354 | alignas(16) __attribute__((visibility("hidden" ), tls_model("initial-exec" ), |
355 | used)) thread_local char LLVMRTDyldTLSSpace[16]; |
356 | } |
357 | #endif |
358 | |
359 | TrivialMemoryManager::TLSSection |
360 | TrivialMemoryManager::allocateTLSSection(uintptr_t Size, unsigned Alignment, |
361 | unsigned SectionID, |
362 | StringRef SectionName) { |
363 | #if defined(__x86_64__) && defined(__ELF__) && defined(__linux__) |
364 | if (Size + UsedTLSStorage > sizeof(LLVMRTDyldTLSSpace)) { |
365 | return {}; |
366 | } |
367 | |
368 | // Get the offset of the TLSSpace in the TLS block by using a tpoff |
369 | // relocation here. |
370 | int64_t TLSOffset; |
371 | asm("leaq LLVMRTDyldTLSSpace@tpoff, %0" : "=r" (TLSOffset)); |
372 | |
373 | TLSSection Section; |
374 | // We use the storage directly as the initialization image. This means that |
375 | // when a new thread is spawned after this allocation, it will not be |
376 | // initialized correctly. This means, llvm-rtdyld will only support TLS in a |
377 | // single thread. |
378 | Section.InitializationImage = |
379 | reinterpret_cast<uint8_t *>(LLVMRTDyldTLSSpace + UsedTLSStorage); |
380 | Section.Offset = TLSOffset + UsedTLSStorage; |
381 | |
382 | UsedTLSStorage += Size; |
383 | |
384 | return Section; |
385 | #else |
386 | return {}; |
387 | #endif |
388 | } |
389 | |
390 | static const char *ProgramName; |
391 | |
392 | static void ErrorAndExit(const Twine &Msg) { |
393 | errs() << ProgramName << ": error: " << Msg << "\n" ; |
394 | exit(status: 1); |
395 | } |
396 | |
397 | static void loadDylibs() { |
398 | for (const std::string &Dylib : Dylibs) { |
399 | if (!sys::fs::is_regular_file(Path: Dylib)) |
400 | report_fatal_error(reason: Twine("Dylib not found: '" ) + Dylib + "'." ); |
401 | std::string ErrMsg; |
402 | if (sys::DynamicLibrary::LoadLibraryPermanently(Filename: Dylib.c_str(), ErrMsg: &ErrMsg)) |
403 | report_fatal_error(reason: Twine("Error loading '" ) + Dylib + "': " + ErrMsg); |
404 | } |
405 | } |
406 | |
407 | /* *** */ |
408 | |
409 | static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { |
410 | assert(LoadObjects || !UseDebugObj); |
411 | |
412 | // Load any dylibs requested on the command line. |
413 | loadDylibs(); |
414 | |
415 | // If we don't have any input files, read from stdin. |
416 | if (!InputFileList.size()) |
417 | InputFileList.push_back(value: "-" ); |
418 | for (auto &File : InputFileList) { |
419 | // Instantiate a dynamic linker. |
420 | TrivialMemoryManager MemMgr; |
421 | RuntimeDyld Dyld(MemMgr, MemMgr); |
422 | |
423 | // Load the input memory buffer. |
424 | |
425 | ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = |
426 | MemoryBuffer::getFileOrSTDIN(Filename: File); |
427 | if (std::error_code EC = InputBuffer.getError()) |
428 | ErrorAndExit(Msg: "unable to read input: '" + EC.message() + "'" ); |
429 | |
430 | Expected<std::unique_ptr<ObjectFile>> MaybeObj( |
431 | ObjectFile::createObjectFile(Object: (*InputBuffer)->getMemBufferRef())); |
432 | |
433 | if (!MaybeObj) { |
434 | std::string Buf; |
435 | raw_string_ostream OS(Buf); |
436 | logAllUnhandledErrors(E: MaybeObj.takeError(), OS); |
437 | OS.flush(); |
438 | ErrorAndExit(Msg: "unable to create object file: '" + Buf + "'" ); |
439 | } |
440 | |
441 | ObjectFile &Obj = **MaybeObj; |
442 | |
443 | OwningBinary<ObjectFile> DebugObj; |
444 | std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo = nullptr; |
445 | ObjectFile *SymbolObj = &Obj; |
446 | if (LoadObjects) { |
447 | // Load the object file |
448 | LoadedObjInfo = |
449 | Dyld.loadObject(O: Obj); |
450 | |
451 | if (Dyld.hasError()) |
452 | ErrorAndExit(Msg: Dyld.getErrorString()); |
453 | |
454 | // Resolve all the relocations we can. |
455 | Dyld.resolveRelocations(); |
456 | |
457 | if (UseDebugObj) { |
458 | DebugObj = LoadedObjInfo->getObjectForDebug(Obj); |
459 | SymbolObj = DebugObj.getBinary(); |
460 | LoadedObjInfo.reset(); |
461 | } |
462 | } |
463 | |
464 | std::unique_ptr<DIContext> Context = DWARFContext::create( |
465 | Obj: *SymbolObj, RelocAction: DWARFContext::ProcessDebugRelocations::Process, |
466 | L: LoadedObjInfo.get()); |
467 | |
468 | std::vector<std::pair<SymbolRef, uint64_t>> SymAddr = |
469 | object::computeSymbolSizes(O: *SymbolObj); |
470 | |
471 | // Use symbol info to iterate functions in the object. |
472 | for (const auto &P : SymAddr) { |
473 | object::SymbolRef Sym = P.first; |
474 | Expected<SymbolRef::Type> TypeOrErr = Sym.getType(); |
475 | if (!TypeOrErr) { |
476 | // TODO: Actually report errors helpfully. |
477 | consumeError(Err: TypeOrErr.takeError()); |
478 | continue; |
479 | } |
480 | SymbolRef::Type Type = *TypeOrErr; |
481 | if (Type == object::SymbolRef::ST_Function) { |
482 | Expected<StringRef> Name = Sym.getName(); |
483 | if (!Name) { |
484 | // TODO: Actually report errors helpfully. |
485 | consumeError(Err: Name.takeError()); |
486 | continue; |
487 | } |
488 | Expected<uint64_t> AddrOrErr = Sym.getAddress(); |
489 | if (!AddrOrErr) { |
490 | // TODO: Actually report errors helpfully. |
491 | consumeError(Err: AddrOrErr.takeError()); |
492 | continue; |
493 | } |
494 | uint64_t Addr = *AddrOrErr; |
495 | |
496 | object::SectionedAddress Address; |
497 | |
498 | uint64_t Size = P.second; |
499 | // If we're not using the debug object, compute the address of the |
500 | // symbol in memory (rather than that in the unrelocated object file) |
501 | // and use that to query the DWARFContext. |
502 | if (!UseDebugObj && LoadObjects) { |
503 | auto SecOrErr = Sym.getSection(); |
504 | if (!SecOrErr) { |
505 | // TODO: Actually report errors helpfully. |
506 | consumeError(Err: SecOrErr.takeError()); |
507 | continue; |
508 | } |
509 | object::section_iterator Sec = *SecOrErr; |
510 | Address.SectionIndex = Sec->getIndex(); |
511 | uint64_t SectionLoadAddress = |
512 | LoadedObjInfo->getSectionLoadAddress(Sec: *Sec); |
513 | if (SectionLoadAddress != 0) |
514 | Addr += SectionLoadAddress - Sec->getAddress(); |
515 | } else if (auto SecOrErr = Sym.getSection()) |
516 | Address.SectionIndex = SecOrErr.get()->getIndex(); |
517 | |
518 | outs() << "Function: " << *Name << ", Size = " << Size |
519 | << ", Addr = " << Addr << "\n" ; |
520 | |
521 | Address.Address = Addr; |
522 | DILineInfoTable Lines = |
523 | Context->getLineInfoForAddressRange(Address, Size); |
524 | for (auto &D : Lines) { |
525 | outs() << " Line info @ " << D.first - Addr << ": " |
526 | << D.second.FileName << ", line:" << D.second.Line << "\n" ; |
527 | } |
528 | } |
529 | } |
530 | } |
531 | |
532 | return 0; |
533 | } |
534 | |
535 | static void doPreallocation(TrivialMemoryManager &MemMgr) { |
536 | // Allocate a slab of memory upfront, if required. This is used if |
537 | // we want to test small code models. |
538 | if (static_cast<intptr_t>(PreallocMemory) < 0) |
539 | report_fatal_error(reason: "Pre-allocated bytes of memory must be a positive integer." ); |
540 | |
541 | // FIXME: Limit the amount of memory that can be preallocated? |
542 | if (PreallocMemory != 0) |
543 | MemMgr.preallocateSlab(Size: PreallocMemory); |
544 | } |
545 | |
546 | static int executeInput() { |
547 | // Load any dylibs requested on the command line. |
548 | loadDylibs(); |
549 | |
550 | // Instantiate a dynamic linker. |
551 | TrivialMemoryManager MemMgr; |
552 | doPreallocation(MemMgr); |
553 | RuntimeDyld Dyld(MemMgr, MemMgr); |
554 | |
555 | // If we don't have any input files, read from stdin. |
556 | if (!InputFileList.size()) |
557 | InputFileList.push_back(value: "-" ); |
558 | { |
559 | TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr); |
560 | for (auto &File : InputFileList) { |
561 | // Load the input memory buffer. |
562 | ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = |
563 | MemoryBuffer::getFileOrSTDIN(Filename: File); |
564 | if (std::error_code EC = InputBuffer.getError()) |
565 | ErrorAndExit(Msg: "unable to read input: '" + EC.message() + "'" ); |
566 | Expected<std::unique_ptr<ObjectFile>> MaybeObj( |
567 | ObjectFile::createObjectFile(Object: (*InputBuffer)->getMemBufferRef())); |
568 | |
569 | if (!MaybeObj) { |
570 | std::string Buf; |
571 | raw_string_ostream OS(Buf); |
572 | logAllUnhandledErrors(E: MaybeObj.takeError(), OS); |
573 | OS.flush(); |
574 | ErrorAndExit(Msg: "unable to create object file: '" + Buf + "'" ); |
575 | } |
576 | |
577 | ObjectFile &Obj = **MaybeObj; |
578 | |
579 | // Load the object file |
580 | Dyld.loadObject(O: Obj); |
581 | if (Dyld.hasError()) { |
582 | ErrorAndExit(Msg: Dyld.getErrorString()); |
583 | } |
584 | } |
585 | } |
586 | |
587 | { |
588 | TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr); |
589 | // Resove all the relocations we can. |
590 | // FIXME: Error out if there are unresolved relocations. |
591 | Dyld.resolveRelocations(); |
592 | } |
593 | |
594 | // Get the address of the entry point (_main by default). |
595 | void *MainAddress = Dyld.getSymbolLocalAddress(Name: EntryPoint); |
596 | if (!MainAddress) |
597 | ErrorAndExit(Msg: "no definition for '" + EntryPoint + "'" ); |
598 | |
599 | // Invalidate the instruction cache for each loaded function. |
600 | for (auto &FM : MemMgr.FunctionMemory) { |
601 | |
602 | auto &FM_MB = FM.MB; |
603 | |
604 | // Make sure the memory is executable. |
605 | // setExecutable will call InvalidateInstructionCache. |
606 | if (auto EC = sys::Memory::protectMappedMemory(Block: FM_MB, |
607 | Flags: sys::Memory::MF_READ | |
608 | sys::Memory::MF_EXEC)) |
609 | ErrorAndExit(Msg: "unable to mark function executable: '" + EC.message() + |
610 | "'" ); |
611 | } |
612 | |
613 | // Dispatch to _main(). |
614 | errs() << "loaded '" << EntryPoint << "' at: " << (void*)MainAddress << "\n" ; |
615 | |
616 | int (*Main)(int, const char**) = |
617 | (int(*)(int,const char**)) uintptr_t(MainAddress); |
618 | std::vector<const char *> Argv; |
619 | // Use the name of the first input object module as argv[0] for the target. |
620 | Argv.push_back(x: InputFileList[0].data()); |
621 | for (auto &Arg : InputArgv) |
622 | Argv.push_back(x: Arg.data()); |
623 | Argv.push_back(x: nullptr); |
624 | int Result = 0; |
625 | { |
626 | TimeRegion TR(Timers ? &Timers->RunTimer : nullptr); |
627 | Result = Main(Argv.size() - 1, Argv.data()); |
628 | } |
629 | |
630 | return Result; |
631 | } |
632 | |
633 | static int checkAllExpressions(RuntimeDyldChecker &Checker) { |
634 | for (const auto& CheckerFileName : CheckFiles) { |
635 | ErrorOr<std::unique_ptr<MemoryBuffer>> CheckerFileBuf = |
636 | MemoryBuffer::getFileOrSTDIN(Filename: CheckerFileName); |
637 | if (std::error_code EC = CheckerFileBuf.getError()) |
638 | ErrorAndExit(Msg: "unable to read input '" + CheckerFileName + "': " + |
639 | EC.message()); |
640 | |
641 | if (!Checker.checkAllRulesInBuffer(RulePrefix: "# rtdyld-check:" , |
642 | MemBuf: CheckerFileBuf.get().get())) |
643 | ErrorAndExit(Msg: "some checks in '" + CheckerFileName + "' failed" ); |
644 | } |
645 | return 0; |
646 | } |
647 | |
648 | void applySpecificSectionMappings(RuntimeDyld &Dyld, |
649 | const FileToSectionIDMap &FileToSecIDMap) { |
650 | |
651 | for (StringRef Mapping : SpecificSectionMappings) { |
652 | size_t EqualsIdx = Mapping.find_first_of(C: '='); |
653 | std::string SectionIDStr = std::string(Mapping.substr(Start: 0, N: EqualsIdx)); |
654 | size_t ComaIdx = Mapping.find_first_of(C: ','); |
655 | |
656 | if (ComaIdx == StringRef::npos) |
657 | report_fatal_error(reason: "Invalid section specification '" + Mapping + |
658 | "'. Should be '<file name>,<section name>=<addr>'" ); |
659 | |
660 | std::string FileName = SectionIDStr.substr(pos: 0, n: ComaIdx); |
661 | std::string SectionName = SectionIDStr.substr(pos: ComaIdx + 1); |
662 | unsigned SectionID = |
663 | ExitOnErr(getSectionId(FileToSecIDMap, FileName, SectionName)); |
664 | |
665 | auto* OldAddr = Dyld.getSectionContent(SectionID).data(); |
666 | std::string NewAddrStr = std::string(Mapping.substr(Start: EqualsIdx + 1)); |
667 | uint64_t NewAddr; |
668 | |
669 | if (StringRef(NewAddrStr).getAsInteger(Radix: 0, Result&: NewAddr)) |
670 | report_fatal_error(reason: "Invalid section address in mapping '" + Mapping + |
671 | "'." ); |
672 | |
673 | Dyld.mapSectionAddress(LocalAddress: OldAddr, TargetAddress: NewAddr); |
674 | } |
675 | } |
676 | |
677 | // Scatter sections in all directions! |
678 | // Remaps section addresses for -verify mode. The following command line options |
679 | // can be used to customize the layout of the memory within the phony target's |
680 | // address space: |
681 | // -target-addr-start <s> -- Specify where the phony target address range starts. |
682 | // -target-addr-end <e> -- Specify where the phony target address range ends. |
683 | // -target-section-sep <d> -- Specify how big a gap should be left between the |
684 | // end of one section and the start of the next. |
685 | // Defaults to zero. Set to something big |
686 | // (e.g. 1 << 32) to stress-test stubs, GOTs, etc. |
687 | // |
688 | static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple, |
689 | RuntimeDyld &Dyld, |
690 | TrivialMemoryManager &MemMgr) { |
691 | |
692 | // Set up a work list (section addr/size pairs). |
693 | typedef std::list<const TrivialMemoryManager::SectionInfo*> WorklistT; |
694 | WorklistT Worklist; |
695 | |
696 | for (const auto& CodeSection : MemMgr.FunctionMemory) |
697 | Worklist.push_back(x: &CodeSection); |
698 | for (const auto& DataSection : MemMgr.DataMemory) |
699 | Worklist.push_back(x: &DataSection); |
700 | |
701 | // Keep an "already allocated" mapping of section target addresses to sizes. |
702 | // Sections whose address mappings aren't specified on the command line will |
703 | // allocated around the explicitly mapped sections while maintaining the |
704 | // minimum separation. |
705 | std::map<uint64_t, uint64_t> AlreadyAllocated; |
706 | |
707 | // Move the previously applied mappings (whether explicitly specified on the |
708 | // command line, or implicitly set by RuntimeDyld) into the already-allocated |
709 | // map. |
710 | for (WorklistT::iterator I = Worklist.begin(), E = Worklist.end(); |
711 | I != E;) { |
712 | WorklistT::iterator Tmp = I; |
713 | ++I; |
714 | |
715 | auto LoadAddr = Dyld.getSectionLoadAddress(SectionID: (*Tmp)->SectionID); |
716 | |
717 | if (LoadAddr != static_cast<uint64_t>( |
718 | reinterpret_cast<uintptr_t>((*Tmp)->MB.base()))) { |
719 | // A section will have a LoadAddr of 0 if it wasn't loaded for whatever |
720 | // reason (e.g. zero byte COFF sections). Don't include those sections in |
721 | // the allocation map. |
722 | if (LoadAddr != 0) |
723 | AlreadyAllocated[LoadAddr] = (*Tmp)->MB.allocatedSize(); |
724 | Worklist.erase(position: Tmp); |
725 | } |
726 | } |
727 | |
728 | // If the -target-addr-end option wasn't explicitly passed, then set it to a |
729 | // sensible default based on the target triple. |
730 | if (TargetAddrEnd.getNumOccurrences() == 0) { |
731 | if (TargetTriple.isArch16Bit()) |
732 | TargetAddrEnd = (1ULL << 16) - 1; |
733 | else if (TargetTriple.isArch32Bit()) |
734 | TargetAddrEnd = (1ULL << 32) - 1; |
735 | // TargetAddrEnd already has a sensible default for 64-bit systems, so |
736 | // there's nothing to do in the 64-bit case. |
737 | } |
738 | |
739 | // Process any elements remaining in the worklist. |
740 | while (!Worklist.empty()) { |
741 | auto *CurEntry = Worklist.front(); |
742 | Worklist.pop_front(); |
743 | |
744 | uint64_t NextSectionAddr = TargetAddrStart; |
745 | |
746 | for (const auto &Alloc : AlreadyAllocated) |
747 | if (NextSectionAddr + CurEntry->MB.allocatedSize() + TargetSectionSep <= |
748 | Alloc.first) |
749 | break; |
750 | else |
751 | NextSectionAddr = Alloc.first + Alloc.second + TargetSectionSep; |
752 | |
753 | Dyld.mapSectionAddress(LocalAddress: CurEntry->MB.base(), TargetAddress: NextSectionAddr); |
754 | AlreadyAllocated[NextSectionAddr] = CurEntry->MB.allocatedSize(); |
755 | } |
756 | |
757 | // Add dummy symbols to the memory manager. |
758 | for (const auto &Mapping : DummySymbolMappings) { |
759 | size_t EqualsIdx = Mapping.find_first_of(c: '='); |
760 | |
761 | if (EqualsIdx == StringRef::npos) |
762 | report_fatal_error(reason: Twine("Invalid dummy symbol specification '" ) + |
763 | Mapping + "'. Should be '<symbol name>=<addr>'" ); |
764 | |
765 | std::string Symbol = Mapping.substr(pos: 0, n: EqualsIdx); |
766 | std::string AddrStr = Mapping.substr(pos: EqualsIdx + 1); |
767 | |
768 | uint64_t Addr; |
769 | if (StringRef(AddrStr).getAsInteger(Radix: 0, Result&: Addr)) |
770 | report_fatal_error(reason: Twine("Invalid symbol mapping '" ) + Mapping + "'." ); |
771 | |
772 | MemMgr.addDummySymbol(Name: Symbol, Addr); |
773 | } |
774 | } |
775 | |
776 | // Load and link the objects specified on the command line, but do not execute |
777 | // anything. Instead, attach a RuntimeDyldChecker instance and call it to |
778 | // verify the correctness of the linked memory. |
779 | static int linkAndVerify() { |
780 | |
781 | // Check for missing triple. |
782 | if (TripleName == "" ) |
783 | ErrorAndExit(Msg: "-triple required when running in -verify mode." ); |
784 | |
785 | // Look up the target and build the disassembler. |
786 | Triple TheTriple(Triple::normalize(Str: TripleName)); |
787 | std::string ErrorStr; |
788 | const Target *TheTarget = |
789 | TargetRegistry::lookupTarget(ArchName: "" , TheTriple, Error&: ErrorStr); |
790 | if (!TheTarget) |
791 | ErrorAndExit(Msg: "Error accessing target '" + TripleName + "': " + ErrorStr); |
792 | |
793 | TripleName = TheTriple.getTriple(); |
794 | |
795 | std::unique_ptr<MCSubtargetInfo> STI( |
796 | TheTarget->createMCSubtargetInfo(TheTriple: TripleName, CPU: MCPU, Features: "" )); |
797 | if (!STI) |
798 | ErrorAndExit(Msg: "Unable to create subtarget info!" ); |
799 | |
800 | std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT: TripleName)); |
801 | if (!MRI) |
802 | ErrorAndExit(Msg: "Unable to create target register info!" ); |
803 | |
804 | MCTargetOptions MCOptions; |
805 | std::unique_ptr<MCAsmInfo> MAI( |
806 | TheTarget->createMCAsmInfo(MRI: *MRI, TheTriple: TripleName, Options: MCOptions)); |
807 | if (!MAI) |
808 | ErrorAndExit(Msg: "Unable to create target asm info!" ); |
809 | |
810 | MCContext Ctx(Triple(TripleName), MAI.get(), MRI.get(), STI.get()); |
811 | |
812 | std::unique_ptr<MCDisassembler> Disassembler( |
813 | TheTarget->createMCDisassembler(STI: *STI, Ctx)); |
814 | if (!Disassembler) |
815 | ErrorAndExit(Msg: "Unable to create disassembler!" ); |
816 | |
817 | std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo()); |
818 | if (!MII) |
819 | ErrorAndExit(Msg: "Unable to create target instruction info!" ); |
820 | |
821 | std::unique_ptr<MCInstPrinter> InstPrinter( |
822 | TheTarget->createMCInstPrinter(T: Triple(TripleName), SyntaxVariant: 0, MAI: *MAI, MII: *MII, MRI: *MRI)); |
823 | |
824 | // Load any dylibs requested on the command line. |
825 | loadDylibs(); |
826 | |
827 | // Instantiate a dynamic linker. |
828 | TrivialMemoryManager MemMgr; |
829 | doPreallocation(MemMgr); |
830 | |
831 | struct StubID { |
832 | unsigned SectionID; |
833 | uint32_t Offset; |
834 | }; |
835 | using StubInfos = StringMap<StubID>; |
836 | using StubContainers = StringMap<StubInfos>; |
837 | |
838 | StubContainers StubMap; |
839 | RuntimeDyld Dyld(MemMgr, MemMgr); |
840 | Dyld.setProcessAllSections(true); |
841 | |
842 | Dyld.setNotifyStubEmitted([&StubMap](StringRef FilePath, |
843 | StringRef SectionName, |
844 | StringRef SymbolName, unsigned SectionID, |
845 | uint32_t StubOffset) { |
846 | std::string ContainerName = |
847 | (sys::path::filename(path: FilePath) + "/" + SectionName).str(); |
848 | StubMap[ContainerName][SymbolName] = {.SectionID: SectionID, .Offset: StubOffset}; |
849 | }); |
850 | |
851 | auto GetSymbolInfo = |
852 | [&Dyld, &MemMgr]( |
853 | StringRef Symbol) -> Expected<RuntimeDyldChecker::MemoryRegionInfo> { |
854 | RuntimeDyldChecker::MemoryRegionInfo SymInfo; |
855 | |
856 | // First get the target address. |
857 | if (auto InternalSymbol = Dyld.getSymbol(Name: Symbol)) |
858 | SymInfo.setTargetAddress(InternalSymbol.getAddress()); |
859 | else { |
860 | // Symbol not found in RuntimeDyld. Fall back to external lookup. |
861 | #ifdef _MSC_VER |
862 | using ExpectedLookupResult = |
863 | MSVCPExpected<JITSymbolResolver::LookupResult>; |
864 | #else |
865 | using ExpectedLookupResult = Expected<JITSymbolResolver::LookupResult>; |
866 | #endif |
867 | |
868 | auto ResultP = std::make_shared<std::promise<ExpectedLookupResult>>(); |
869 | auto ResultF = ResultP->get_future(); |
870 | |
871 | MemMgr.lookup(Symbols: JITSymbolResolver::LookupSet({Symbol}), |
872 | OnResolved: [=](Expected<JITSymbolResolver::LookupResult> Result) { |
873 | ResultP->set_value(std::move(Result)); |
874 | }); |
875 | |
876 | auto Result = ResultF.get(); |
877 | if (!Result) |
878 | return Result.takeError(); |
879 | |
880 | auto I = Result->find(x: Symbol); |
881 | assert(I != Result->end() && |
882 | "Expected symbol address if no error occurred" ); |
883 | SymInfo.setTargetAddress(I->second.getAddress()); |
884 | } |
885 | |
886 | // Now find the symbol content if possible (otherwise leave content as a |
887 | // default-constructed StringRef). |
888 | if (auto *SymAddr = Dyld.getSymbolLocalAddress(Name: Symbol)) { |
889 | unsigned SectionID = Dyld.getSymbolSectionID(Name: Symbol); |
890 | if (SectionID != ~0U) { |
891 | char *CSymAddr = static_cast<char *>(SymAddr); |
892 | StringRef SecContent = Dyld.getSectionContent(SectionID); |
893 | uint64_t SymSize = SecContent.size() - (CSymAddr - SecContent.data()); |
894 | SymInfo.setContent(ArrayRef<char>(CSymAddr, SymSize)); |
895 | SymInfo.setTargetFlags( |
896 | Dyld.getSymbol(Name: Symbol).getFlags().getTargetFlags()); |
897 | } |
898 | } |
899 | return SymInfo; |
900 | }; |
901 | |
902 | auto IsSymbolValid = [&Dyld, GetSymbolInfo](StringRef Symbol) { |
903 | if (Dyld.getSymbol(Name: Symbol)) |
904 | return true; |
905 | auto SymInfo = GetSymbolInfo(Symbol); |
906 | if (!SymInfo) { |
907 | logAllUnhandledErrors(E: SymInfo.takeError(), OS&: errs(), ErrorBanner: "RTDyldChecker: " ); |
908 | return false; |
909 | } |
910 | return SymInfo->getTargetAddress() != 0; |
911 | }; |
912 | |
913 | FileToSectionIDMap FileToSecIDMap; |
914 | |
915 | auto GetSectionInfo = [&Dyld, &FileToSecIDMap](StringRef FileName, |
916 | StringRef SectionName) |
917 | -> Expected<RuntimeDyldChecker::MemoryRegionInfo> { |
918 | auto SectionID = getSectionId(FileToSecIDMap, FileName, SectionName); |
919 | if (!SectionID) |
920 | return SectionID.takeError(); |
921 | RuntimeDyldChecker::MemoryRegionInfo SecInfo; |
922 | SecInfo.setTargetAddress(Dyld.getSectionLoadAddress(SectionID: *SectionID)); |
923 | StringRef SecContent = Dyld.getSectionContent(SectionID: *SectionID); |
924 | SecInfo.setContent(ArrayRef<char>(SecContent.data(), SecContent.size())); |
925 | return SecInfo; |
926 | }; |
927 | |
928 | auto GetStubInfo = [&Dyld, &StubMap](StringRef StubContainer, |
929 | StringRef SymbolName, |
930 | StringRef KindNameFilter) |
931 | -> Expected<RuntimeDyldChecker::MemoryRegionInfo> { |
932 | if (!StubMap.count(Key: StubContainer)) |
933 | return make_error<StringError>(Args: "Stub container not found: " + |
934 | StubContainer, |
935 | Args: inconvertibleErrorCode()); |
936 | if (!StubMap[StubContainer].count(Key: SymbolName)) |
937 | return make_error<StringError>(Args: "Symbol name " + SymbolName + |
938 | " in stub container " + StubContainer, |
939 | Args: inconvertibleErrorCode()); |
940 | auto &SI = StubMap[StubContainer][SymbolName]; |
941 | RuntimeDyldChecker::MemoryRegionInfo StubMemInfo; |
942 | StubMemInfo.setTargetAddress(Dyld.getSectionLoadAddress(SectionID: SI.SectionID) + |
943 | SI.Offset); |
944 | StringRef SecContent = |
945 | Dyld.getSectionContent(SectionID: SI.SectionID).substr(Start: SI.Offset); |
946 | StubMemInfo.setContent( |
947 | ArrayRef<char>(SecContent.data(), SecContent.size())); |
948 | return StubMemInfo; |
949 | }; |
950 | |
951 | auto GetGOTInfo = [&GetStubInfo](StringRef StubContainer, |
952 | StringRef SymbolName) { |
953 | return GetStubInfo(StubContainer, SymbolName, "" ); |
954 | }; |
955 | |
956 | // We will initialize this below once we have the first object file and can |
957 | // know the endianness. |
958 | std::unique_ptr<RuntimeDyldChecker> Checker; |
959 | |
960 | // If we don't have any input files, read from stdin. |
961 | if (!InputFileList.size()) |
962 | InputFileList.push_back(value: "-" ); |
963 | for (auto &InputFile : InputFileList) { |
964 | // Load the input memory buffer. |
965 | ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = |
966 | MemoryBuffer::getFileOrSTDIN(Filename: InputFile); |
967 | |
968 | if (std::error_code EC = InputBuffer.getError()) |
969 | ErrorAndExit(Msg: "unable to read input: '" + EC.message() + "'" ); |
970 | |
971 | Expected<std::unique_ptr<ObjectFile>> MaybeObj( |
972 | ObjectFile::createObjectFile(Object: (*InputBuffer)->getMemBufferRef())); |
973 | |
974 | if (!MaybeObj) { |
975 | std::string Buf; |
976 | raw_string_ostream OS(Buf); |
977 | logAllUnhandledErrors(E: MaybeObj.takeError(), OS); |
978 | OS.flush(); |
979 | ErrorAndExit(Msg: "unable to create object file: '" + Buf + "'" ); |
980 | } |
981 | |
982 | ObjectFile &Obj = **MaybeObj; |
983 | |
984 | if (!Checker) |
985 | Checker = std::make_unique<RuntimeDyldChecker>( |
986 | args&: IsSymbolValid, args&: GetSymbolInfo, args&: GetSectionInfo, args&: GetStubInfo, args&: GetGOTInfo, |
987 | args: Obj.isLittleEndian() ? llvm::endianness::little |
988 | : llvm::endianness::big, |
989 | args&: TheTriple, args&: MCPU, args: SubtargetFeatures(), args&: dbgs()); |
990 | |
991 | auto FileName = sys::path::filename(path: InputFile); |
992 | MemMgr.setSectionIDsMap(&FileToSecIDMap[FileName]); |
993 | |
994 | // Load the object file |
995 | Dyld.loadObject(O: Obj); |
996 | if (Dyld.hasError()) { |
997 | ErrorAndExit(Msg: Dyld.getErrorString()); |
998 | } |
999 | } |
1000 | |
1001 | // Re-map the section addresses into the phony target address space and add |
1002 | // dummy symbols. |
1003 | applySpecificSectionMappings(Dyld, FileToSecIDMap); |
1004 | remapSectionsAndSymbols(TargetTriple: TheTriple, Dyld, MemMgr); |
1005 | |
1006 | // Resolve all the relocations we can. |
1007 | Dyld.resolveRelocations(); |
1008 | |
1009 | // Register EH frames. |
1010 | Dyld.registerEHFrames(); |
1011 | |
1012 | int ErrorCode = checkAllExpressions(Checker&: *Checker); |
1013 | if (Dyld.hasError()) |
1014 | ErrorAndExit(Msg: "RTDyld reported an error applying relocations:\n " + |
1015 | Dyld.getErrorString()); |
1016 | |
1017 | return ErrorCode; |
1018 | } |
1019 | |
1020 | int main(int argc, char **argv) { |
1021 | InitLLVM X(argc, argv); |
1022 | ProgramName = argv[0]; |
1023 | |
1024 | llvm::InitializeAllTargetInfos(); |
1025 | llvm::InitializeAllTargetMCs(); |
1026 | llvm::InitializeAllDisassemblers(); |
1027 | |
1028 | cl::HideUnrelatedOptions(Categories: {&RTDyldCategory, &getColorCategory()}); |
1029 | cl::ParseCommandLineOptions(argc, argv, Overview: "llvm MC-JIT tool\n" ); |
1030 | |
1031 | ExitOnErr.setBanner(std::string(argv[0]) + ": " ); |
1032 | |
1033 | Timers = ShowTimes ? std::make_unique<RTDyldTimers>() : nullptr; |
1034 | |
1035 | int Result = 0; |
1036 | switch (Action) { |
1037 | case AC_Execute: |
1038 | Result = executeInput(); |
1039 | break; |
1040 | case AC_PrintDebugLineInfo: |
1041 | Result = |
1042 | printLineInfoForInput(/* LoadObjects */ true, /* UseDebugObj */ true); |
1043 | break; |
1044 | case AC_PrintLineInfo: |
1045 | Result = |
1046 | printLineInfoForInput(/* LoadObjects */ true, /* UseDebugObj */ false); |
1047 | break; |
1048 | case AC_PrintObjectLineInfo: |
1049 | Result = |
1050 | printLineInfoForInput(/* LoadObjects */ false, /* UseDebugObj */ false); |
1051 | break; |
1052 | case AC_Verify: |
1053 | Result = linkAndVerify(); |
1054 | break; |
1055 | } |
1056 | return Result; |
1057 | } |
1058 | |