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