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