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