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