xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp (revision a2fda816eb054d5873be223ef2461741dfcc253c)
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/LLVMDriver.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(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
58  #include "Opts.inc"
59  #undef OPTION
60  };
61  
62  #define PREFIX(NAME, VALUE)                                                    \
63    static constexpr StringLiteral NAME##_init[] = VALUE;                        \
64    static constexpr ArrayRef<StringLiteral> NAME(NAME##_init,                   \
65                                                  std::size(NAME##_init) - 1);
66  #include "Opts.inc"
67  #undef PREFIX
68  
69  static constexpr opt::OptTable::Info InfoTable[] = {
70  #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
71  #include "Opts.inc"
72  #undef OPTION
73  };
74  
75  class ReadobjOptTable : public opt::GenericOptTable {
76  public:
77    ReadobjOptTable() : opt::GenericOptTable(InfoTable) {
78      setGroupedShortOptions(true);
79    }
80  };
81  
82  enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };
83  
84  enum SortSymbolKeyTy {
85    NAME = 0,
86    TYPE = 1,
87    UNKNOWN = 100,
88    // TODO: add ADDRESS, SIZE as needed.
89  };
90  
91  } // namespace
92  
93  namespace opts {
94  static bool Addrsig;
95  static bool All;
96  static bool ArchSpecificInfo;
97  static bool BBAddrMap;
98  bool ExpandRelocs;
99  static bool CGProfile;
100  static bool Decompress;
101  bool Demangle;
102  static bool DependentLibraries;
103  static bool DynRelocs;
104  static bool DynamicSymbols;
105  static bool ExtraSymInfo;
106  static bool FileHeaders;
107  static bool Headers;
108  static std::vector<std::string> HexDump;
109  static bool PrettyPrint;
110  static bool PrintStackMap;
111  static bool PrintStackSizes;
112  static bool Relocations;
113  bool SectionData;
114  static bool SectionDetails;
115  static bool SectionHeaders;
116  bool SectionRelocations;
117  bool SectionSymbols;
118  static std::vector<std::string> StringDump;
119  static bool StringTable;
120  static bool Symbols;
121  static bool UnwindInfo;
122  static cl::boolOrDefault SectionMapping;
123  static SmallVector<SortSymbolKeyTy> SortKeys;
124  
125  // ELF specific options.
126  static bool DynamicTable;
127  static bool ELFLinkerOptions;
128  static bool GnuHashTable;
129  static bool HashSymbols;
130  static bool HashTable;
131  static bool HashHistogram;
132  static bool Memtag;
133  static bool NeededLibraries;
134  static bool Notes;
135  static bool ProgramHeaders;
136  bool RawRelr;
137  static bool SectionGroups;
138  static bool VersionInfo;
139  
140  // Mach-O specific options.
141  static bool MachODataInCode;
142  static bool MachODysymtab;
143  static bool MachOIndirectSymbols;
144  static bool MachOLinkerOptions;
145  static bool MachOSegment;
146  static bool MachOVersionMin;
147  
148  // PE/COFF specific options.
149  static bool CodeView;
150  static bool CodeViewEnableGHash;
151  static bool CodeViewMergedTypes;
152  bool CodeViewSubsectionBytes;
153  static bool COFFBaseRelocs;
154  static bool COFFDebugDirectory;
155  static bool COFFDirectives;
156  static bool COFFExports;
157  static bool COFFImports;
158  static bool COFFLoadConfig;
159  static bool COFFResources;
160  static bool COFFTLSDirectory;
161  
162  // XCOFF specific options.
163  static bool XCOFFAuxiliaryHeader;
164  static bool XCOFFLoaderSectionHeader;
165  static bool XCOFFLoaderSectionSymbol;
166  static bool XCOFFLoaderSectionRelocation;
167  static bool XCOFFExceptionSection;
168  
169  OutputStyleTy Output = OutputStyleTy::LLVM;
170  static std::vector<std::string> InputFilenames;
171  } // namespace opts
172  
173  static StringRef ToolName;
174  
175  namespace llvm {
176  
177  [[noreturn]] static void error(Twine Msg) {
178    // Flush the standard output to print the error at a
179    // proper place.
180    fouts().flush();
181    WithColor::error(errs(), ToolName) << Msg << "\n";
182    exit(1);
183  }
184  
185  [[noreturn]] void reportError(Error Err, StringRef Input) {
186    assert(Err);
187    if (Input == "-")
188      Input = "<stdin>";
189    handleAllErrors(createFileError(Input, std::move(Err)),
190                    [&](const ErrorInfoBase &EI) { error(EI.message()); });
191    llvm_unreachable("error() call should never return");
192  }
193  
194  void reportWarning(Error Err, StringRef Input) {
195    assert(Err);
196    if (Input == "-")
197      Input = "<stdin>";
198  
199    // Flush the standard output to print the warning at a
200    // proper place.
201    fouts().flush();
202    handleAllErrors(
203        createFileError(Input, std::move(Err)), [&](const ErrorInfoBase &EI) {
204          WithColor::warning(errs(), ToolName) << EI.message() << "\n";
205        });
206  }
207  
208  } // namespace llvm
209  
210  static void parseOptions(const opt::InputArgList &Args) {
211    opts::Addrsig = Args.hasArg(OPT_addrsig);
212    opts::All = Args.hasArg(OPT_all);
213    opts::ArchSpecificInfo = Args.hasArg(OPT_arch_specific);
214    opts::BBAddrMap = Args.hasArg(OPT_bb_addr_map);
215    opts::CGProfile = Args.hasArg(OPT_cg_profile);
216    opts::Decompress = Args.hasArg(OPT_decompress);
217    opts::Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, false);
218    opts::DependentLibraries = Args.hasArg(OPT_dependent_libraries);
219    opts::DynRelocs = Args.hasArg(OPT_dyn_relocations);
220    opts::DynamicSymbols = Args.hasArg(OPT_dyn_syms);
221    opts::ExpandRelocs = Args.hasArg(OPT_expand_relocs);
222    opts::ExtraSymInfo = Args.hasArg(OPT_extra_sym_info);
223    opts::FileHeaders = Args.hasArg(OPT_file_header);
224    opts::Headers = Args.hasArg(OPT_headers);
225    opts::HexDump = Args.getAllArgValues(OPT_hex_dump_EQ);
226    opts::Relocations = Args.hasArg(OPT_relocs);
227    opts::SectionData = Args.hasArg(OPT_section_data);
228    opts::SectionDetails = Args.hasArg(OPT_section_details);
229    opts::SectionHeaders = Args.hasArg(OPT_section_headers);
230    opts::SectionRelocations = Args.hasArg(OPT_section_relocations);
231    opts::SectionSymbols = Args.hasArg(OPT_section_symbols);
232    if (Args.hasArg(OPT_section_mapping))
233      opts::SectionMapping = cl::BOU_TRUE;
234    else if (Args.hasArg(OPT_section_mapping_EQ_false))
235      opts::SectionMapping = cl::BOU_FALSE;
236    else
237      opts::SectionMapping = cl::BOU_UNSET;
238    opts::PrintStackSizes = Args.hasArg(OPT_stack_sizes);
239    opts::PrintStackMap = Args.hasArg(OPT_stackmap);
240    opts::StringDump = Args.getAllArgValues(OPT_string_dump_EQ);
241    opts::StringTable = Args.hasArg(OPT_string_table);
242    opts::Symbols = Args.hasArg(OPT_symbols);
243    opts::UnwindInfo = Args.hasArg(OPT_unwind);
244  
245    // ELF specific options.
246    opts::DynamicTable = Args.hasArg(OPT_dynamic_table);
247    opts::ELFLinkerOptions = Args.hasArg(OPT_elf_linker_options);
248    if (Arg *A = Args.getLastArg(OPT_elf_output_style_EQ)) {
249      std::string OutputStyleChoice = A->getValue();
250      opts::Output = StringSwitch<opts::OutputStyleTy>(OutputStyleChoice)
251                         .Case("LLVM", opts::OutputStyleTy::LLVM)
252                         .Case("GNU", opts::OutputStyleTy::GNU)
253                         .Case("JSON", opts::OutputStyleTy::JSON)
254                         .Default(opts::OutputStyleTy::UNKNOWN);
255      if (opts::Output == opts::OutputStyleTy::UNKNOWN) {
256        error("--elf-output-style value should be either 'LLVM', 'GNU', or "
257              "'JSON', but was '" +
258              OutputStyleChoice + "'");
259      }
260    }
261    opts::GnuHashTable = Args.hasArg(OPT_gnu_hash_table);
262    opts::HashSymbols = Args.hasArg(OPT_hash_symbols);
263    opts::HashTable = Args.hasArg(OPT_hash_table);
264    opts::HashHistogram = Args.hasArg(OPT_histogram);
265    opts::Memtag = Args.hasArg(OPT_memtag);
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,
442                           opts::ExtraSymInfo, SymComp);
443    if (!opts::StringDump.empty())
444      Dumper->printSectionsAsString(Obj, opts::StringDump, opts::Decompress);
445    if (!opts::HexDump.empty())
446      Dumper->printSectionsAsHex(Obj, opts::HexDump, opts::Decompress);
447    if (opts::HashTable)
448      Dumper->printHashTable();
449    if (opts::GnuHashTable)
450      Dumper->printGnuHashTable();
451    if (opts::VersionInfo)
452      Dumper->printVersionInfo();
453    if (opts::StringTable)
454      Dumper->printStringTable();
455    if (Obj.isELF()) {
456      if (opts::DependentLibraries)
457        Dumper->printDependentLibs();
458      if (opts::ELFLinkerOptions)
459        Dumper->printELFLinkerOptions();
460      if (opts::ArchSpecificInfo)
461        Dumper->printArchSpecificInfo();
462      if (opts::SectionGroups)
463        Dumper->printGroupSections();
464      if (opts::HashHistogram)
465        Dumper->printHashHistograms();
466      if (opts::CGProfile)
467        Dumper->printCGProfile();
468      if (opts::BBAddrMap)
469        Dumper->printBBAddrMaps();
470      if (opts::Addrsig)
471        Dumper->printAddrsig();
472      if (opts::Notes)
473        Dumper->printNotes();
474      if (opts::Memtag)
475        Dumper->printMemtag();
476    }
477    if (Obj.isCOFF()) {
478      if (opts::COFFImports)
479        Dumper->printCOFFImports();
480      if (opts::COFFExports)
481        Dumper->printCOFFExports();
482      if (opts::COFFDirectives)
483        Dumper->printCOFFDirectives();
484      if (opts::COFFBaseRelocs)
485        Dumper->printCOFFBaseReloc();
486      if (opts::COFFDebugDirectory)
487        Dumper->printCOFFDebugDirectory();
488      if (opts::COFFTLSDirectory)
489        Dumper->printCOFFTLSDirectory();
490      if (opts::COFFResources)
491        Dumper->printCOFFResources();
492      if (opts::COFFLoadConfig)
493        Dumper->printCOFFLoadConfig();
494      if (opts::CGProfile)
495        Dumper->printCGProfile();
496      if (opts::Addrsig)
497        Dumper->printAddrsig();
498      if (opts::CodeView)
499        Dumper->printCodeViewDebugInfo();
500      if (opts::CodeViewMergedTypes)
501        Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable,
502                                   CVTypes.GlobalIDTable, CVTypes.GlobalTypeTable,
503                                   opts::CodeViewEnableGHash);
504    }
505    if (Obj.isMachO()) {
506      if (opts::MachODataInCode)
507        Dumper->printMachODataInCode();
508      if (opts::MachOIndirectSymbols)
509        Dumper->printMachOIndirectSymbols();
510      if (opts::MachOLinkerOptions)
511        Dumper->printMachOLinkerOptions();
512      if (opts::MachOSegment)
513        Dumper->printMachOSegment();
514      if (opts::MachOVersionMin)
515        Dumper->printMachOVersionMin();
516      if (opts::MachODysymtab)
517        Dumper->printMachODysymtab();
518      if (opts::CGProfile)
519        Dumper->printCGProfile();
520    }
521  
522    if (Obj.isXCOFF()) {
523      if (opts::XCOFFLoaderSectionHeader || opts::XCOFFLoaderSectionSymbol ||
524          opts::XCOFFLoaderSectionRelocation)
525        Dumper->printLoaderSection(opts::XCOFFLoaderSectionHeader,
526                                   opts::XCOFFLoaderSectionSymbol,
527                                   opts::XCOFFLoaderSectionRelocation);
528  
529      if (opts::XCOFFExceptionSection)
530        Dumper->printExceptionSection();
531    }
532  
533    if (opts::PrintStackMap)
534      Dumper->printStackMap();
535    if (opts::PrintStackSizes)
536      Dumper->printStackSizes();
537  }
538  
539  /// Dumps each object file in \a Arc;
540  static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) {
541    Error Err = Error::success();
542    for (auto &Child : Arc->children(Err)) {
543      Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
544      if (!ChildOrErr) {
545        if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
546          reportError(std::move(E), Arc->getFileName());
547        continue;
548      }
549  
550      Binary *Bin = ChildOrErr->get();
551      if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin))
552        dumpObject(*Obj, Writer, Arc);
553      else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(Bin))
554        dumpCOFFImportFile(Imp, Writer);
555      else
556        reportWarning(createStringError(errc::invalid_argument,
557                                        Bin->getFileName() +
558                                            " has an unsupported file type"),
559                      Arc->getFileName());
560    }
561    if (Err)
562      reportError(std::move(Err), Arc->getFileName());
563  }
564  
565  /// Dumps each object file in \a MachO Universal Binary;
566  static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary,
567                                       ScopedPrinter &Writer) {
568    for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) {
569      Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile();
570      if (ObjOrErr)
571        dumpObject(*ObjOrErr.get(), Writer);
572      else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError()))
573        reportError(ObjOrErr.takeError(), UBinary->getFileName());
574      else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive())
575        dumpArchive(&*AOrErr.get(), Writer);
576    }
577  }
578  
579  /// Dumps \a WinRes, Windows Resource (.res) file;
580  static void dumpWindowsResourceFile(WindowsResource *WinRes,
581                                      ScopedPrinter &Printer) {
582    WindowsRes::Dumper Dumper(WinRes, Printer);
583    if (auto Err = Dumper.printData())
584      reportError(std::move(Err), WinRes->getFileName());
585  }
586  
587  
588  /// Opens \a File and dumps it.
589  static void dumpInput(StringRef File, ScopedPrinter &Writer) {
590    ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
591        MemoryBuffer::getFileOrSTDIN(File, /*IsText=*/false,
592                                     /*RequiresNullTerminator=*/false);
593    if (std::error_code EC = FileOrErr.getError())
594      return reportError(errorCodeToError(EC), File);
595  
596    std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get();
597    file_magic Type = identify_magic(Buffer->getBuffer());
598    if (Type == file_magic::bitcode) {
599      reportWarning(createStringError(errc::invalid_argument,
600                                      "bitcode files are not supported"),
601                    File);
602      return;
603    }
604  
605    Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(
606        Buffer->getMemBufferRef(), /*Context=*/nullptr, /*InitContent=*/false);
607    if (!BinaryOrErr)
608      reportError(BinaryOrErr.takeError(), File);
609  
610    std::unique_ptr<Binary> Bin = std::move(*BinaryOrErr);
611    if (Archive *Arc = dyn_cast<Archive>(Bin.get()))
612      dumpArchive(Arc, Writer);
613    else if (MachOUniversalBinary *UBinary =
614                 dyn_cast<MachOUniversalBinary>(Bin.get()))
615      dumpMachOUniversalBinary(UBinary, Writer);
616    else if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin.get()))
617      dumpObject(*Obj, Writer);
618    else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(Bin.get()))
619      dumpCOFFImportFile(Import, Writer);
620    else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(Bin.get()))
621      dumpWindowsResourceFile(WinRes, Writer);
622    else
623      llvm_unreachable("unrecognized file type");
624  
625    CVTypes.Binaries.push_back(
626        OwningBinary<Binary>(std::move(Bin), std::move(Buffer)));
627  }
628  
629  std::unique_ptr<ScopedPrinter> createWriter() {
630    if (opts::Output == opts::JSON)
631      return std::make_unique<JSONScopedPrinter>(
632          fouts(), opts::PrettyPrint ? 2 : 0, std::make_unique<ListScope>());
633    return std::make_unique<ScopedPrinter>(fouts());
634  }
635  
636  int llvm_readobj_main(int argc, char **argv, const llvm::ToolContext &) {
637    BumpPtrAllocator A;
638    StringSaver Saver(A);
639    ReadobjOptTable Tbl;
640    ToolName = argv[0];
641    opt::InputArgList Args =
642        Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
643          error(Msg);
644          exit(1);
645        });
646    if (Args.hasArg(OPT_help)) {
647      Tbl.printHelp(
648          outs(),
649          (Twine(ToolName) + " [options] <input object files>").str().c_str(),
650          "LLVM Object Reader");
651      // TODO Replace this with OptTable API once it adds extrahelp support.
652      outs() << "\nPass @FILE as argument to read options from FILE.\n";
653      return 0;
654    }
655    if (Args.hasArg(OPT_version)) {
656      cl::PrintVersionMessage();
657      return 0;
658    }
659  
660    if (sys::path::stem(argv[0]).contains("readelf"))
661      opts::Output = opts::GNU;
662    parseOptions(Args);
663  
664    // Default to print error if no filename is specified.
665    if (opts::InputFilenames.empty()) {
666      error("no input files specified");
667    }
668  
669    if (opts::All) {
670      opts::FileHeaders = true;
671      opts::XCOFFAuxiliaryHeader = true;
672      opts::ProgramHeaders = true;
673      opts::SectionHeaders = true;
674      opts::Symbols = true;
675      opts::Relocations = true;
676      opts::DynamicTable = true;
677      opts::Notes = true;
678      opts::VersionInfo = true;
679      opts::UnwindInfo = true;
680      opts::SectionGroups = true;
681      opts::HashHistogram = true;
682      if (opts::Output == opts::LLVM) {
683        opts::Addrsig = true;
684        opts::PrintStackSizes = true;
685      }
686      opts::Memtag = true;
687    }
688  
689    if (opts::Headers) {
690      opts::FileHeaders = true;
691      opts::XCOFFAuxiliaryHeader = true;
692      opts::ProgramHeaders = true;
693      opts::SectionHeaders = true;
694    }
695  
696    std::unique_ptr<ScopedPrinter> Writer = createWriter();
697  
698    for (const std::string &I : opts::InputFilenames)
699      dumpInput(I, *Writer.get());
700  
701    if (opts::CodeViewMergedTypes) {
702      if (opts::CodeViewEnableGHash)
703        dumpCodeViewMergedTypes(*Writer.get(), CVTypes.GlobalIDTable.records(),
704                                CVTypes.GlobalTypeTable.records());
705      else
706        dumpCodeViewMergedTypes(*Writer.get(), CVTypes.IDTable.records(),
707                                CVTypes.TypeTable.records());
708    }
709  
710    return 0;
711  }
712