1 //===- llvm-readobj.cpp - Dump contents of an Object File -----------------===//
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 tool similar to readelf, except it works on multiple object file
10 // formats. The main purpose of this tool is to provide detailed output suitable
11 // for FileCheck.
12 //
13 // Flags should be similar to readelf where supported, but the output format
14 // does not need to be identical. The point is to not make users learn yet
15 // another set of flags.
16 //
17 // Output should be specialized for each format where appropriate.
18 //
19 //===----------------------------------------------------------------------===//
20
21 #include "llvm-readobj.h"
22 #include "ObjDumper.h"
23 #include "WindowsResourceDumper.h"
24 #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
25 #include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
26 #include "llvm/Object/Archive.h"
27 #include "llvm/Object/COFFImportFile.h"
28 #include "llvm/Object/ELFObjectFile.h"
29 #include "llvm/Object/MachOUniversal.h"
30 #include "llvm/Object/ObjectFile.h"
31 #include "llvm/Object/Wasm.h"
32 #include "llvm/Object/WindowsResource.h"
33 #include "llvm/Object/XCOFFObjectFile.h"
34 #include "llvm/Option/Arg.h"
35 #include "llvm/Option/ArgList.h"
36 #include "llvm/Option/Option.h"
37 #include "llvm/Support/Casting.h"
38 #include "llvm/Support/CommandLine.h"
39 #include "llvm/Support/DataTypes.h"
40 #include "llvm/Support/Debug.h"
41 #include "llvm/Support/Errc.h"
42 #include "llvm/Support/FileSystem.h"
43 #include "llvm/Support/FormatVariadic.h"
44 #include "llvm/Support/InitLLVM.h"
45 #include "llvm/Support/Path.h"
46 #include "llvm/Support/ScopedPrinter.h"
47 #include "llvm/Support/TargetRegistry.h"
48 #include "llvm/Support/WithColor.h"
49
50 using namespace llvm;
51 using namespace llvm::object;
52
53 namespace {
54 using namespace llvm::opt; // for HelpHidden in Opts.inc
55 enum ID {
56 OPT_INVALID = 0, // This is not an option ID.
57 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
58 HELPTEXT, METAVAR, VALUES) \
59 OPT_##ID,
60 #include "Opts.inc"
61 #undef OPTION
62 };
63
64 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
65 #include "Opts.inc"
66 #undef PREFIX
67
68 static const opt::OptTable::Info InfoTable[] = {
69 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
70 HELPTEXT, METAVAR, VALUES) \
71 { \
72 PREFIX, NAME, HELPTEXT, \
73 METAVAR, OPT_##ID, opt::Option::KIND##Class, \
74 PARAM, FLAGS, OPT_##GROUP, \
75 OPT_##ALIAS, ALIASARGS, VALUES},
76 #include "Opts.inc"
77 #undef OPTION
78 };
79
80 class ReadobjOptTable : public opt::OptTable {
81 public:
ReadobjOptTable()82 ReadobjOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
83 };
84
85 enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };
86 } // namespace
87
88 namespace opts {
89 static bool Addrsig;
90 static bool All;
91 static bool ArchSpecificInfo;
92 static bool BBAddrMap;
93 bool ExpandRelocs;
94 static bool CGProfile;
95 bool Demangle;
96 static bool DependentLibraries;
97 static bool DynRelocs;
98 static bool DynamicSymbols;
99 static bool FileHeaders;
100 static bool Headers;
101 static std::vector<std::string> HexDump;
102 static bool PrintStackMap;
103 static bool PrintStackSizes;
104 static bool Relocations;
105 bool SectionData;
106 static bool SectionDetails;
107 static bool SectionHeaders;
108 bool SectionRelocations;
109 bool SectionSymbols;
110 static std::vector<std::string> StringDump;
111 static bool StringTable;
112 static bool Symbols;
113 static bool UnwindInfo;
114 static cl::boolOrDefault SectionMapping;
115
116 // ELF specific options.
117 static bool DynamicTable;
118 static bool ELFLinkerOptions;
119 static bool GnuHashTable;
120 static bool HashSymbols;
121 static bool HashTable;
122 static bool HashHistogram;
123 static bool NeededLibraries;
124 static bool Notes;
125 static bool ProgramHeaders;
126 bool RawRelr;
127 static bool SectionGroups;
128 static bool VersionInfo;
129
130 // Mach-O specific options.
131 static bool MachODataInCode;
132 static bool MachODysymtab;
133 static bool MachOIndirectSymbols;
134 static bool MachOLinkerOptions;
135 static bool MachOSegment;
136 static bool MachOVersionMin;
137
138 // PE/COFF specific options.
139 static bool CodeView;
140 static bool CodeViewEnableGHash;
141 static bool CodeViewMergedTypes;
142 bool CodeViewSubsectionBytes;
143 static bool COFFBaseRelocs;
144 static bool COFFDebugDirectory;
145 static bool COFFDirectives;
146 static bool COFFExports;
147 static bool COFFImports;
148 static bool COFFLoadConfig;
149 static bool COFFResources;
150 static bool COFFTLSDirectory;
151
152 OutputStyleTy Output = OutputStyleTy::LLVM;
153 static std::vector<std::string> InputFilenames;
154 } // namespace opts
155
156 static StringRef ToolName;
157
158 namespace llvm {
159
error(Twine Msg)160 LLVM_ATTRIBUTE_NORETURN static void error(Twine Msg) {
161 // Flush the standard output to print the error at a
162 // proper place.
163 fouts().flush();
164 WithColor::error(errs(), ToolName) << Msg << "\n";
165 exit(1);
166 }
167
reportError(Error Err,StringRef Input)168 LLVM_ATTRIBUTE_NORETURN void reportError(Error Err, StringRef Input) {
169 assert(Err);
170 if (Input == "-")
171 Input = "<stdin>";
172 handleAllErrors(createFileError(Input, std::move(Err)),
173 [&](const ErrorInfoBase &EI) { error(EI.message()); });
174 llvm_unreachable("error() call should never return");
175 }
176
reportWarning(Error Err,StringRef Input)177 void reportWarning(Error Err, StringRef Input) {
178 assert(Err);
179 if (Input == "-")
180 Input = "<stdin>";
181
182 // Flush the standard output to print the warning at a
183 // proper place.
184 fouts().flush();
185 handleAllErrors(
186 createFileError(Input, std::move(Err)), [&](const ErrorInfoBase &EI) {
187 WithColor::warning(errs(), ToolName) << EI.message() << "\n";
188 });
189 }
190
191 } // namespace llvm
192
parseOptions(const opt::InputArgList & Args)193 static void parseOptions(const opt::InputArgList &Args) {
194 opts::Addrsig = Args.hasArg(OPT_addrsig);
195 opts::All = Args.hasArg(OPT_all);
196 opts::ArchSpecificInfo = Args.hasArg(OPT_arch_specific);
197 opts::BBAddrMap = Args.hasArg(OPT_bb_addr_map);
198 opts::CGProfile = Args.hasArg(OPT_cg_profile);
199 opts::Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, false);
200 opts::DependentLibraries = Args.hasArg(OPT_dependent_libraries);
201 opts::DynRelocs = Args.hasArg(OPT_dyn_relocations);
202 opts::DynamicSymbols = Args.hasArg(OPT_dyn_syms);
203 opts::ExpandRelocs = Args.hasArg(OPT_expand_relocs);
204 opts::FileHeaders = Args.hasArg(OPT_file_header);
205 opts::Headers = Args.hasArg(OPT_headers);
206 opts::HexDump = Args.getAllArgValues(OPT_hex_dump_EQ);
207 opts::Relocations = Args.hasArg(OPT_relocs);
208 opts::SectionData = Args.hasArg(OPT_section_data);
209 opts::SectionDetails = Args.hasArg(OPT_section_details);
210 opts::SectionHeaders = Args.hasArg(OPT_section_headers);
211 opts::SectionRelocations = Args.hasArg(OPT_section_relocations);
212 opts::SectionSymbols = Args.hasArg(OPT_section_symbols);
213 if (Args.hasArg(OPT_section_mapping))
214 opts::SectionMapping = cl::BOU_TRUE;
215 else if (Args.hasArg(OPT_section_mapping_EQ_false))
216 opts::SectionMapping = cl::BOU_FALSE;
217 else
218 opts::SectionMapping = cl::BOU_UNSET;
219 opts::PrintStackSizes = Args.hasArg(OPT_stack_sizes);
220 opts::PrintStackMap = Args.hasArg(OPT_stackmap);
221 opts::StringDump = Args.getAllArgValues(OPT_string_dump_EQ);
222 opts::StringTable = Args.hasArg(OPT_string_table);
223 opts::Symbols = Args.hasArg(OPT_symbols);
224 opts::UnwindInfo = Args.hasArg(OPT_unwind);
225
226 // ELF specific options.
227 opts::DynamicTable = Args.hasArg(OPT_dynamic_table);
228 opts::ELFLinkerOptions = Args.hasArg(OPT_elf_linker_options);
229 if (Arg *A = Args.getLastArg(OPT_elf_output_style_EQ)) {
230 StringRef V(A->getValue());
231 if (V == "LLVM")
232 opts::Output = opts::OutputStyleTy::LLVM;
233 else if (V == "GNU")
234 opts::Output = opts::OutputStyleTy::GNU;
235 else
236 error("--elf-output-style value should be either 'LLVM' or 'GNU'");
237 }
238 opts::GnuHashTable = Args.hasArg(OPT_gnu_hash_table);
239 opts::HashSymbols = Args.hasArg(OPT_hash_symbols);
240 opts::HashTable = Args.hasArg(OPT_hash_table);
241 opts::HashHistogram = Args.hasArg(OPT_histogram);
242 opts::NeededLibraries = Args.hasArg(OPT_needed_libs);
243 opts::Notes = Args.hasArg(OPT_notes);
244 opts::ProgramHeaders = Args.hasArg(OPT_program_headers);
245 opts::RawRelr = Args.hasArg(OPT_raw_relr);
246 opts::SectionGroups = Args.hasArg(OPT_section_groups);
247 opts::VersionInfo = Args.hasArg(OPT_version_info);
248
249 // Mach-O specific options.
250 opts::MachODataInCode = Args.hasArg(OPT_macho_data_in_code);
251 opts::MachODysymtab = Args.hasArg(OPT_macho_dysymtab);
252 opts::MachOIndirectSymbols = Args.hasArg(OPT_macho_indirect_symbols);
253 opts::MachOLinkerOptions = Args.hasArg(OPT_macho_linker_options);
254 opts::MachOSegment = Args.hasArg(OPT_macho_segment);
255 opts::MachOVersionMin = Args.hasArg(OPT_macho_version_min);
256
257 // PE/COFF specific options.
258 opts::CodeView = Args.hasArg(OPT_codeview);
259 opts::CodeViewEnableGHash = Args.hasArg(OPT_codeview_ghash);
260 opts::CodeViewMergedTypes = Args.hasArg(OPT_codeview_merged_types);
261 opts::CodeViewSubsectionBytes = Args.hasArg(OPT_codeview_subsection_bytes);
262 opts::COFFBaseRelocs = Args.hasArg(OPT_coff_basereloc);
263 opts::COFFDebugDirectory = Args.hasArg(OPT_coff_debug_directory);
264 opts::COFFDirectives = Args.hasArg(OPT_coff_directives);
265 opts::COFFExports = Args.hasArg(OPT_coff_exports);
266 opts::COFFImports = Args.hasArg(OPT_coff_imports);
267 opts::COFFLoadConfig = Args.hasArg(OPT_coff_load_config);
268 opts::COFFResources = Args.hasArg(OPT_coff_resources);
269 opts::COFFTLSDirectory = Args.hasArg(OPT_coff_tls_directory);
270
271 opts::InputFilenames = Args.getAllArgValues(OPT_INPUT);
272 }
273
274 namespace {
275 struct ReadObjTypeTableBuilder {
ReadObjTypeTableBuilder__anonb5039f0b0411::ReadObjTypeTableBuilder276 ReadObjTypeTableBuilder()
277 : Allocator(), IDTable(Allocator), TypeTable(Allocator),
278 GlobalIDTable(Allocator), GlobalTypeTable(Allocator) {}
279
280 llvm::BumpPtrAllocator Allocator;
281 llvm::codeview::MergingTypeTableBuilder IDTable;
282 llvm::codeview::MergingTypeTableBuilder TypeTable;
283 llvm::codeview::GlobalTypeTableBuilder GlobalIDTable;
284 llvm::codeview::GlobalTypeTableBuilder GlobalTypeTable;
285 std::vector<OwningBinary<Binary>> Binaries;
286 };
287 } // namespace
288 static ReadObjTypeTableBuilder CVTypes;
289
290 /// Creates an format-specific object file dumper.
291 static Expected<std::unique_ptr<ObjDumper>>
createDumper(const ObjectFile & Obj,ScopedPrinter & Writer)292 createDumper(const ObjectFile &Obj, ScopedPrinter &Writer) {
293 if (const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(&Obj))
294 return createCOFFDumper(*COFFObj, Writer);
295
296 if (const ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj))
297 return createELFDumper(*ELFObj, Writer);
298
299 if (const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(&Obj))
300 return createMachODumper(*MachOObj, Writer);
301
302 if (const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(&Obj))
303 return createWasmDumper(*WasmObj, Writer);
304
305 if (const XCOFFObjectFile *XObj = dyn_cast<XCOFFObjectFile>(&Obj))
306 return createXCOFFDumper(*XObj, Writer);
307
308 return createStringError(errc::invalid_argument,
309 "unsupported object file format");
310 }
311
312 /// Dumps the specified object file.
dumpObject(ObjectFile & Obj,ScopedPrinter & Writer,const Archive * A=nullptr)313 static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
314 const Archive *A = nullptr) {
315 std::string FileStr =
316 A ? Twine(A->getFileName() + "(" + Obj.getFileName() + ")").str()
317 : Obj.getFileName().str();
318
319 std::string ContentErrString;
320 if (Error ContentErr = Obj.initContent())
321 ContentErrString = "unable to continue dumping, the file is corrupt: " +
322 toString(std::move(ContentErr));
323
324 ObjDumper *Dumper;
325 Expected<std::unique_ptr<ObjDumper>> DumperOrErr = createDumper(Obj, Writer);
326 if (!DumperOrErr)
327 reportError(DumperOrErr.takeError(), FileStr);
328 Dumper = (*DumperOrErr).get();
329
330 if (opts::Output == opts::LLVM || opts::InputFilenames.size() > 1 || A) {
331 Writer.startLine() << "\n";
332 Writer.printString("File", FileStr);
333 }
334 if (opts::Output == opts::LLVM) {
335 Writer.printString("Format", Obj.getFileFormatName());
336 Writer.printString("Arch", Triple::getArchTypeName(Obj.getArch()));
337 Writer.printString(
338 "AddressSize",
339 std::string(formatv("{0}bit", 8 * Obj.getBytesInAddress())));
340 Dumper->printLoadName();
341 }
342
343 if (opts::FileHeaders)
344 Dumper->printFileHeaders();
345
346 // This is only used for ELF currently. In some cases, when an object is
347 // corrupt (e.g. truncated), we can't dump anything except the file header.
348 if (!ContentErrString.empty())
349 reportError(createError(ContentErrString), FileStr);
350
351 if (opts::SectionDetails || opts::SectionHeaders) {
352 if (opts::Output == opts::GNU && opts::SectionDetails)
353 Dumper->printSectionDetails();
354 else
355 Dumper->printSectionHeaders();
356 }
357
358 if (opts::HashSymbols)
359 Dumper->printHashSymbols();
360 if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE)
361 Dumper->printProgramHeaders(opts::ProgramHeaders, opts::SectionMapping);
362 if (opts::DynamicTable)
363 Dumper->printDynamicTable();
364 if (opts::NeededLibraries)
365 Dumper->printNeededLibraries();
366 if (opts::Relocations)
367 Dumper->printRelocations();
368 if (opts::DynRelocs)
369 Dumper->printDynamicRelocations();
370 if (opts::UnwindInfo)
371 Dumper->printUnwindInfo();
372 if (opts::Symbols || opts::DynamicSymbols)
373 Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols);
374 if (!opts::StringDump.empty())
375 Dumper->printSectionsAsString(Obj, opts::StringDump);
376 if (!opts::HexDump.empty())
377 Dumper->printSectionsAsHex(Obj, opts::HexDump);
378 if (opts::HashTable)
379 Dumper->printHashTable();
380 if (opts::GnuHashTable)
381 Dumper->printGnuHashTable();
382 if (opts::VersionInfo)
383 Dumper->printVersionInfo();
384 if (opts::StringTable)
385 Dumper->printStringTable();
386 if (Obj.isELF()) {
387 if (opts::DependentLibraries)
388 Dumper->printDependentLibs();
389 if (opts::ELFLinkerOptions)
390 Dumper->printELFLinkerOptions();
391 if (opts::ArchSpecificInfo)
392 Dumper->printArchSpecificInfo();
393 if (opts::SectionGroups)
394 Dumper->printGroupSections();
395 if (opts::HashHistogram)
396 Dumper->printHashHistograms();
397 if (opts::CGProfile)
398 Dumper->printCGProfile();
399 if (opts::BBAddrMap)
400 Dumper->printBBAddrMaps();
401 if (opts::Addrsig)
402 Dumper->printAddrsig();
403 if (opts::Notes)
404 Dumper->printNotes();
405 }
406 if (Obj.isCOFF()) {
407 if (opts::COFFImports)
408 Dumper->printCOFFImports();
409 if (opts::COFFExports)
410 Dumper->printCOFFExports();
411 if (opts::COFFDirectives)
412 Dumper->printCOFFDirectives();
413 if (opts::COFFBaseRelocs)
414 Dumper->printCOFFBaseReloc();
415 if (opts::COFFDebugDirectory)
416 Dumper->printCOFFDebugDirectory();
417 if (opts::COFFTLSDirectory)
418 Dumper->printCOFFTLSDirectory();
419 if (opts::COFFResources)
420 Dumper->printCOFFResources();
421 if (opts::COFFLoadConfig)
422 Dumper->printCOFFLoadConfig();
423 if (opts::CGProfile)
424 Dumper->printCGProfile();
425 if (opts::Addrsig)
426 Dumper->printAddrsig();
427 if (opts::CodeView)
428 Dumper->printCodeViewDebugInfo();
429 if (opts::CodeViewMergedTypes)
430 Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable,
431 CVTypes.GlobalIDTable, CVTypes.GlobalTypeTable,
432 opts::CodeViewEnableGHash);
433 }
434 if (Obj.isMachO()) {
435 if (opts::MachODataInCode)
436 Dumper->printMachODataInCode();
437 if (opts::MachOIndirectSymbols)
438 Dumper->printMachOIndirectSymbols();
439 if (opts::MachOLinkerOptions)
440 Dumper->printMachOLinkerOptions();
441 if (opts::MachOSegment)
442 Dumper->printMachOSegment();
443 if (opts::MachOVersionMin)
444 Dumper->printMachOVersionMin();
445 if (opts::MachODysymtab)
446 Dumper->printMachODysymtab();
447 }
448 if (opts::PrintStackMap)
449 Dumper->printStackMap();
450 if (opts::PrintStackSizes)
451 Dumper->printStackSizes();
452 }
453
454 /// Dumps each object file in \a Arc;
dumpArchive(const Archive * Arc,ScopedPrinter & Writer)455 static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) {
456 Error Err = Error::success();
457 for (auto &Child : Arc->children(Err)) {
458 Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
459 if (!ChildOrErr) {
460 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
461 reportError(std::move(E), Arc->getFileName());
462 continue;
463 }
464
465 Binary *Bin = ChildOrErr->get();
466 if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin))
467 dumpObject(*Obj, Writer, Arc);
468 else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(Bin))
469 dumpCOFFImportFile(Imp, Writer);
470 else
471 reportWarning(createStringError(errc::invalid_argument,
472 Bin->getFileName() +
473 " has an unsupported file type"),
474 Arc->getFileName());
475 }
476 if (Err)
477 reportError(std::move(Err), Arc->getFileName());
478 }
479
480 /// Dumps each object file in \a MachO Universal Binary;
dumpMachOUniversalBinary(const MachOUniversalBinary * UBinary,ScopedPrinter & Writer)481 static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary,
482 ScopedPrinter &Writer) {
483 for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) {
484 Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile();
485 if (ObjOrErr)
486 dumpObject(*ObjOrErr.get(), Writer);
487 else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError()))
488 reportError(ObjOrErr.takeError(), UBinary->getFileName());
489 else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive())
490 dumpArchive(&*AOrErr.get(), Writer);
491 }
492 }
493
494 /// Dumps \a WinRes, Windows Resource (.res) file;
dumpWindowsResourceFile(WindowsResource * WinRes,ScopedPrinter & Printer)495 static void dumpWindowsResourceFile(WindowsResource *WinRes,
496 ScopedPrinter &Printer) {
497 WindowsRes::Dumper Dumper(WinRes, Printer);
498 if (auto Err = Dumper.printData())
499 reportError(std::move(Err), WinRes->getFileName());
500 }
501
502
503 /// Opens \a File and dumps it.
dumpInput(StringRef File,ScopedPrinter & Writer)504 static void dumpInput(StringRef File, ScopedPrinter &Writer) {
505 ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
506 MemoryBuffer::getFileOrSTDIN(File, /*IsText=*/false,
507 /*RequiresNullTerminator=*/false);
508 if (std::error_code EC = FileOrErr.getError())
509 return reportError(errorCodeToError(EC), File);
510
511 std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get();
512 file_magic Type = identify_magic(Buffer->getBuffer());
513 if (Type == file_magic::bitcode) {
514 reportWarning(createStringError(errc::invalid_argument,
515 "bitcode files are not supported"),
516 File);
517 return;
518 }
519
520 Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(
521 Buffer->getMemBufferRef(), /*Context=*/nullptr, /*InitContent=*/false);
522 if (!BinaryOrErr)
523 reportError(BinaryOrErr.takeError(), File);
524
525 std::unique_ptr<Binary> Bin = std::move(*BinaryOrErr);
526 if (Archive *Arc = dyn_cast<Archive>(Bin.get()))
527 dumpArchive(Arc, Writer);
528 else if (MachOUniversalBinary *UBinary =
529 dyn_cast<MachOUniversalBinary>(Bin.get()))
530 dumpMachOUniversalBinary(UBinary, Writer);
531 else if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin.get()))
532 dumpObject(*Obj, Writer);
533 else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(Bin.get()))
534 dumpCOFFImportFile(Import, Writer);
535 else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(Bin.get()))
536 dumpWindowsResourceFile(WinRes, Writer);
537 else
538 llvm_unreachable("unrecognized file type");
539
540 CVTypes.Binaries.push_back(
541 OwningBinary<Binary>(std::move(Bin), std::move(Buffer)));
542 }
543
main(int argc,char * argv[])544 int main(int argc, char *argv[]) {
545 InitLLVM X(argc, argv);
546 BumpPtrAllocator A;
547 StringSaver Saver(A);
548 ReadobjOptTable Tbl;
549 ToolName = argv[0];
550 opt::InputArgList Args =
551 Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
552 error(Msg);
553 exit(1);
554 });
555 if (Args.hasArg(OPT_help)) {
556 Tbl.printHelp(
557 outs(),
558 (Twine(ToolName) + " [options] <input object files>").str().c_str(),
559 "LLVM Object Reader");
560 // TODO Replace this with OptTable API once it adds extrahelp support.
561 outs() << "\nPass @FILE as argument to read options from FILE.\n";
562 return 0;
563 }
564 if (Args.hasArg(OPT_version)) {
565 cl::PrintVersionMessage();
566 return 0;
567 }
568
569 if (sys::path::stem(argv[0]).contains("readelf"))
570 opts::Output = opts::GNU;
571 parseOptions(Args);
572
573 // Default to print error if no filename is specified.
574 if (opts::InputFilenames.empty()) {
575 error("no input files specified");
576 }
577
578 if (opts::All) {
579 opts::FileHeaders = true;
580 opts::ProgramHeaders = true;
581 opts::SectionHeaders = true;
582 opts::Symbols = true;
583 opts::Relocations = true;
584 opts::DynamicTable = true;
585 opts::Notes = true;
586 opts::VersionInfo = true;
587 opts::UnwindInfo = true;
588 opts::SectionGroups = true;
589 opts::HashHistogram = true;
590 if (opts::Output == opts::LLVM) {
591 opts::Addrsig = true;
592 opts::PrintStackSizes = true;
593 }
594 }
595
596 if (opts::Headers) {
597 opts::FileHeaders = true;
598 opts::ProgramHeaders = true;
599 opts::SectionHeaders = true;
600 }
601
602 ScopedPrinter Writer(fouts());
603 for (const std::string &I : opts::InputFilenames)
604 dumpInput(I, Writer);
605
606 if (opts::CodeViewMergedTypes) {
607 if (opts::CodeViewEnableGHash)
608 dumpCodeViewMergedTypes(Writer, CVTypes.GlobalIDTable.records(),
609 CVTypes.GlobalTypeTable.records());
610 else
611 dumpCodeViewMergedTypes(Writer, CVTypes.IDTable.records(),
612 CVTypes.TypeTable.records());
613 }
614
615 return 0;
616 }
617