xref: /llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp (revision dd647e3e608ed0b2bac7c588d5859b80ef4a5976)
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     std::string SortKeysString = A->getValue();
280     for (StringRef KeyStr : llvm::split(A->getValue(), ",")) {
281       SortSymbolKeyTy KeyType = StringSwitch<SortSymbolKeyTy>(KeyStr)
282                                     .Case("name", SortSymbolKeyTy::NAME)
283                                     .Case("type", SortSymbolKeyTy::TYPE)
284                                     .Default(SortSymbolKeyTy::UNKNOWN);
285       if (KeyType == SortSymbolKeyTy::UNKNOWN)
286         error("--sort-symbols value should be 'name' or 'type', but was '" +
287               Twine(KeyStr) + "'");
288       opts::SortKeys.push_back(KeyType);
289     }
290   }
291   opts::VersionInfo = Args.hasArg(OPT_version_info);
292 
293   // Mach-O specific options.
294   opts::MachODataInCode = Args.hasArg(OPT_macho_data_in_code);
295   opts::MachODysymtab = Args.hasArg(OPT_macho_dysymtab);
296   opts::MachOIndirectSymbols = Args.hasArg(OPT_macho_indirect_symbols);
297   opts::MachOLinkerOptions = Args.hasArg(OPT_macho_linker_options);
298   opts::MachOSegment = Args.hasArg(OPT_macho_segment);
299   opts::MachOVersionMin = Args.hasArg(OPT_macho_version_min);
300 
301   // PE/COFF specific options.
302   opts::CodeView = Args.hasArg(OPT_codeview);
303   opts::CodeViewEnableGHash = Args.hasArg(OPT_codeview_ghash);
304   opts::CodeViewMergedTypes = Args.hasArg(OPT_codeview_merged_types);
305   opts::CodeViewSubsectionBytes = Args.hasArg(OPT_codeview_subsection_bytes);
306   opts::COFFBaseRelocs = Args.hasArg(OPT_coff_basereloc);
307   opts::COFFDebugDirectory = Args.hasArg(OPT_coff_debug_directory);
308   opts::COFFDirectives = Args.hasArg(OPT_coff_directives);
309   opts::COFFExports = Args.hasArg(OPT_coff_exports);
310   opts::COFFImports = Args.hasArg(OPT_coff_imports);
311   opts::COFFLoadConfig = Args.hasArg(OPT_coff_load_config);
312   opts::COFFResources = Args.hasArg(OPT_coff_resources);
313   opts::COFFTLSDirectory = Args.hasArg(OPT_coff_tls_directory);
314 
315   // XCOFF specific options.
316   opts::XCOFFAuxiliaryHeader = Args.hasArg(OPT_auxiliary_header);
317   opts::XCOFFLoaderSectionHeader = Args.hasArg(OPT_loader_section_header);
318   opts::XCOFFLoaderSectionSymbol = Args.hasArg(OPT_loader_section_symbols);
319   opts::XCOFFLoaderSectionRelocation =
320       Args.hasArg(OPT_loader_section_relocations);
321   opts::XCOFFExceptionSection = Args.hasArg(OPT_exception_section);
322 
323   opts::InputFilenames = Args.getAllArgValues(OPT_INPUT);
324 }
325 
326 namespace {
327 struct ReadObjTypeTableBuilder {
328   ReadObjTypeTableBuilder()
329       : IDTable(Allocator), TypeTable(Allocator), GlobalIDTable(Allocator),
330         GlobalTypeTable(Allocator) {}
331 
332   llvm::BumpPtrAllocator Allocator;
333   llvm::codeview::MergingTypeTableBuilder IDTable;
334   llvm::codeview::MergingTypeTableBuilder TypeTable;
335   llvm::codeview::GlobalTypeTableBuilder GlobalIDTable;
336   llvm::codeview::GlobalTypeTableBuilder GlobalTypeTable;
337   std::vector<OwningBinary<Binary>> Binaries;
338 };
339 } // namespace
340 static ReadObjTypeTableBuilder CVTypes;
341 
342 /// Creates an format-specific object file dumper.
343 static Expected<std::unique_ptr<ObjDumper>>
344 createDumper(const ObjectFile &Obj, ScopedPrinter &Writer) {
345   if (const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(&Obj))
346     return createCOFFDumper(*COFFObj, Writer);
347 
348   if (const ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj))
349     return createELFDumper(*ELFObj, Writer);
350 
351   if (const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(&Obj))
352     return createMachODumper(*MachOObj, Writer);
353 
354   if (const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(&Obj))
355     return createWasmDumper(*WasmObj, Writer);
356 
357   if (const XCOFFObjectFile *XObj = dyn_cast<XCOFFObjectFile>(&Obj))
358     return createXCOFFDumper(*XObj, Writer);
359 
360   return createStringError(errc::invalid_argument,
361                            "unsupported object file format");
362 }
363 
364 /// Dumps the specified object file.
365 static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
366                        const Archive *A = nullptr) {
367   std::string FileStr =
368       A ? Twine(A->getFileName() + "(" + Obj.getFileName() + ")").str()
369         : Obj.getFileName().str();
370 
371   std::string ContentErrString;
372   if (Error ContentErr = Obj.initContent())
373     ContentErrString = "unable to continue dumping, the file is corrupt: " +
374                        toString(std::move(ContentErr));
375 
376   ObjDumper *Dumper;
377   std::optional<SymbolComparator> SymComp;
378   Expected<std::unique_ptr<ObjDumper>> DumperOrErr = createDumper(Obj, Writer);
379   if (!DumperOrErr)
380     reportError(DumperOrErr.takeError(), FileStr);
381   Dumper = (*DumperOrErr).get();
382 
383   if (!opts::SortKeys.empty()) {
384     if (Dumper->canCompareSymbols()) {
385       SymComp = SymbolComparator();
386       for (SortSymbolKeyTy Key : opts::SortKeys) {
387         switch (Key) {
388         case NAME:
389           SymComp->addPredicate([Dumper](SymbolRef LHS, SymbolRef RHS) {
390             return Dumper->compareSymbolsByName(LHS, RHS);
391           });
392           break;
393         case TYPE:
394           SymComp->addPredicate([Dumper](SymbolRef LHS, SymbolRef RHS) {
395             return Dumper->compareSymbolsByType(LHS, RHS);
396           });
397           break;
398         case UNKNOWN:
399           llvm_unreachable("Unsupported sort key");
400         }
401       }
402 
403     } else {
404       reportWarning(createStringError(
405                         errc::invalid_argument,
406                         "--sort-symbols is not supported yet for this format"),
407                     FileStr);
408     }
409   }
410   Dumper->printFileSummary(FileStr, Obj, opts::InputFilenames, A);
411 
412   if (opts::FileHeaders)
413     Dumper->printFileHeaders();
414 
415   // Auxiliary header in XOCFF is right after the file header, so print the data
416   // here.
417   if (Obj.isXCOFF() && opts::XCOFFAuxiliaryHeader)
418     Dumper->printAuxiliaryHeader();
419 
420   // This is only used for ELF currently. In some cases, when an object is
421   // corrupt (e.g. truncated), we can't dump anything except the file header.
422   if (!ContentErrString.empty())
423     reportError(createError(ContentErrString), FileStr);
424 
425   if (opts::SectionDetails || opts::SectionHeaders) {
426     if (opts::Output == opts::GNU && opts::SectionDetails)
427       Dumper->printSectionDetails();
428     else
429       Dumper->printSectionHeaders();
430   }
431 
432   if (opts::HashSymbols)
433     Dumper->printHashSymbols();
434   if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE)
435     Dumper->printProgramHeaders(opts::ProgramHeaders, opts::SectionMapping);
436   if (opts::DynamicTable)
437     Dumper->printDynamicTable();
438   if (opts::NeededLibraries)
439     Dumper->printNeededLibraries();
440   if (opts::Relocations)
441     Dumper->printRelocations();
442   if (opts::DynRelocs)
443     Dumper->printDynamicRelocations();
444   if (opts::UnwindInfo)
445     Dumper->printUnwindInfo();
446   if (opts::Symbols || opts::DynamicSymbols)
447     Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols,
448                          opts::ExtraSymInfo, SymComp);
449   if (!opts::StringDump.empty())
450     Dumper->printSectionsAsString(Obj, opts::StringDump, opts::Decompress);
451   if (!opts::HexDump.empty())
452     Dumper->printSectionsAsHex(Obj, opts::HexDump, opts::Decompress);
453   if (opts::HashTable)
454     Dumper->printHashTable();
455   if (opts::GnuHashTable)
456     Dumper->printGnuHashTable();
457   if (opts::VersionInfo)
458     Dumper->printVersionInfo();
459   if (opts::StringTable)
460     Dumper->printStringTable();
461   if (Obj.isELF()) {
462     if (opts::DependentLibraries)
463       Dumper->printDependentLibs();
464     if (opts::ELFLinkerOptions)
465       Dumper->printELFLinkerOptions();
466     if (opts::ArchSpecificInfo)
467       Dumper->printArchSpecificInfo();
468     if (opts::SectionGroups)
469       Dumper->printGroupSections();
470     if (opts::HashHistogram)
471       Dumper->printHashHistograms();
472     if (opts::CGProfile)
473       Dumper->printCGProfile();
474     if (opts::BBAddrMap)
475       Dumper->printBBAddrMaps(opts::PrettyPGOAnalysisMap);
476     if (opts::Addrsig)
477       Dumper->printAddrsig();
478     if (opts::Notes)
479       Dumper->printNotes();
480     if (opts::Memtag)
481       Dumper->printMemtag();
482   }
483   if (Obj.isCOFF()) {
484     if (opts::COFFImports)
485       Dumper->printCOFFImports();
486     if (opts::COFFExports)
487       Dumper->printCOFFExports();
488     if (opts::COFFDirectives)
489       Dumper->printCOFFDirectives();
490     if (opts::COFFBaseRelocs)
491       Dumper->printCOFFBaseReloc();
492     if (opts::COFFDebugDirectory)
493       Dumper->printCOFFDebugDirectory();
494     if (opts::COFFTLSDirectory)
495       Dumper->printCOFFTLSDirectory();
496     if (opts::COFFResources)
497       Dumper->printCOFFResources();
498     if (opts::COFFLoadConfig)
499       Dumper->printCOFFLoadConfig();
500     if (opts::CGProfile)
501       Dumper->printCGProfile();
502     if (opts::Addrsig)
503       Dumper->printAddrsig();
504     if (opts::CodeView)
505       Dumper->printCodeViewDebugInfo();
506     if (opts::CodeViewMergedTypes)
507       Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable,
508                                  CVTypes.GlobalIDTable, CVTypes.GlobalTypeTable,
509                                  opts::CodeViewEnableGHash);
510   }
511   if (Obj.isMachO()) {
512     if (opts::MachODataInCode)
513       Dumper->printMachODataInCode();
514     if (opts::MachOIndirectSymbols)
515       Dumper->printMachOIndirectSymbols();
516     if (opts::MachOLinkerOptions)
517       Dumper->printMachOLinkerOptions();
518     if (opts::MachOSegment)
519       Dumper->printMachOSegment();
520     if (opts::MachOVersionMin)
521       Dumper->printMachOVersionMin();
522     if (opts::MachODysymtab)
523       Dumper->printMachODysymtab();
524     if (opts::CGProfile)
525       Dumper->printCGProfile();
526   }
527 
528   if (Obj.isXCOFF()) {
529     if (opts::XCOFFLoaderSectionHeader || opts::XCOFFLoaderSectionSymbol ||
530         opts::XCOFFLoaderSectionRelocation)
531       Dumper->printLoaderSection(opts::XCOFFLoaderSectionHeader,
532                                  opts::XCOFFLoaderSectionSymbol,
533                                  opts::XCOFFLoaderSectionRelocation);
534 
535     if (opts::XCOFFExceptionSection)
536       Dumper->printExceptionSection();
537   }
538 
539   if (opts::PrintStackMap)
540     Dumper->printStackMap();
541   if (opts::PrintStackSizes)
542     Dumper->printStackSizes();
543 }
544 
545 /// Dumps each object file in \a Arc;
546 static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) {
547   Error Err = Error::success();
548   for (auto &Child : Arc->children(Err)) {
549     Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
550     if (!ChildOrErr) {
551       if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
552         reportError(std::move(E), Arc->getFileName());
553       continue;
554     }
555 
556     Binary *Bin = ChildOrErr->get();
557     if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin))
558       dumpObject(*Obj, Writer, Arc);
559     else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(Bin))
560       dumpCOFFImportFile(Imp, Writer);
561     else
562       reportWarning(createStringError(errc::invalid_argument,
563                                       Bin->getFileName() +
564                                           " has an unsupported file type"),
565                     Arc->getFileName());
566   }
567   if (Err)
568     reportError(std::move(Err), Arc->getFileName());
569 }
570 
571 /// Dumps each object file in \a MachO Universal Binary;
572 static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary,
573                                      ScopedPrinter &Writer) {
574   for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) {
575     Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile();
576     if (ObjOrErr)
577       dumpObject(*ObjOrErr.get(), Writer);
578     else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError()))
579       reportError(ObjOrErr.takeError(), UBinary->getFileName());
580     else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive())
581       dumpArchive(&*AOrErr.get(), Writer);
582   }
583 }
584 
585 /// Dumps \a COFF file;
586 static void dumpCOFFObject(COFFObjectFile *Obj, ScopedPrinter &Writer) {
587   dumpObject(*Obj, Writer);
588 
589   // Dump a hybrid object when available.
590   std::unique_ptr<MemoryBuffer> HybridView = Obj->getHybridObjectView();
591   if (!HybridView)
592     return;
593   Expected<std::unique_ptr<COFFObjectFile>> HybridObjOrErr =
594       COFFObjectFile::create(*HybridView);
595   if (!HybridObjOrErr)
596     reportError(HybridObjOrErr.takeError(), Obj->getFileName().str());
597   DictScope D(Writer, "HybridObject");
598   dumpObject(**HybridObjOrErr, Writer);
599 }
600 
601 /// Dumps \a WinRes, Windows Resource (.res) file;
602 static void dumpWindowsResourceFile(WindowsResource *WinRes,
603                                     ScopedPrinter &Printer) {
604   WindowsRes::Dumper Dumper(WinRes, Printer);
605   if (auto Err = Dumper.printData())
606     reportError(std::move(Err), WinRes->getFileName());
607 }
608 
609 
610 /// Opens \a File and dumps it.
611 static void dumpInput(StringRef File, ScopedPrinter &Writer) {
612   ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
613       MemoryBuffer::getFileOrSTDIN(File, /*IsText=*/false,
614                                    /*RequiresNullTerminator=*/false);
615   if (std::error_code EC = FileOrErr.getError())
616     return reportError(errorCodeToError(EC), File);
617 
618   std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get();
619   file_magic Type = identify_magic(Buffer->getBuffer());
620   if (Type == file_magic::bitcode) {
621     reportWarning(createStringError(errc::invalid_argument,
622                                     "bitcode files are not supported"),
623                   File);
624     return;
625   }
626 
627   Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(
628       Buffer->getMemBufferRef(), /*Context=*/nullptr, /*InitContent=*/false);
629   if (!BinaryOrErr)
630     reportError(BinaryOrErr.takeError(), File);
631 
632   std::unique_ptr<Binary> Bin = std::move(*BinaryOrErr);
633   if (Archive *Arc = dyn_cast<Archive>(Bin.get()))
634     dumpArchive(Arc, Writer);
635   else if (MachOUniversalBinary *UBinary =
636                dyn_cast<MachOUniversalBinary>(Bin.get()))
637     dumpMachOUniversalBinary(UBinary, Writer);
638   else if (COFFObjectFile *Obj = dyn_cast<COFFObjectFile>(Bin.get()))
639     dumpCOFFObject(Obj, Writer);
640   else if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin.get()))
641     dumpObject(*Obj, Writer);
642   else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(Bin.get()))
643     dumpCOFFImportFile(Import, Writer);
644   else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(Bin.get()))
645     dumpWindowsResourceFile(WinRes, Writer);
646   else
647     llvm_unreachable("unrecognized file type");
648 
649   CVTypes.Binaries.push_back(
650       OwningBinary<Binary>(std::move(Bin), std::move(Buffer)));
651 }
652 
653 std::unique_ptr<ScopedPrinter> createWriter() {
654   if (opts::Output == opts::JSON)
655     return std::make_unique<JSONScopedPrinter>(
656         fouts(), opts::PrettyPrint ? 2 : 0, std::make_unique<ListScope>());
657   return std::make_unique<ScopedPrinter>(fouts());
658 }
659 
660 int llvm_readobj_main(int argc, char **argv, const llvm::ToolContext &) {
661   BumpPtrAllocator A;
662   StringSaver Saver(A);
663   ReadobjOptTable Tbl;
664   ToolName = argv[0];
665   opt::InputArgList Args =
666       Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
667         error(Msg);
668         exit(1);
669       });
670   if (Args.hasArg(OPT_help)) {
671     Tbl.printHelp(
672         outs(),
673         (Twine(ToolName) + " [options] <input object files>").str().c_str(),
674         "LLVM Object Reader");
675     // TODO Replace this with OptTable API once it adds extrahelp support.
676     outs() << "\nPass @FILE as argument to read options from FILE.\n";
677     return 0;
678   }
679   if (Args.hasArg(OPT_version)) {
680     cl::PrintVersionMessage();
681     return 0;
682   }
683 
684   if (sys::path::stem(argv[0]).contains("readelf"))
685     opts::Output = opts::GNU;
686   parseOptions(Args);
687 
688   // Default to print error if no filename is specified.
689   if (opts::InputFilenames.empty()) {
690     error("no input files specified");
691   }
692 
693   if (opts::All) {
694     opts::FileHeaders = true;
695     opts::XCOFFAuxiliaryHeader = true;
696     opts::ProgramHeaders = true;
697     opts::SectionHeaders = true;
698     opts::Symbols = true;
699     opts::Relocations = true;
700     opts::DynamicTable = true;
701     opts::Notes = true;
702     opts::VersionInfo = true;
703     opts::UnwindInfo = true;
704     opts::SectionGroups = true;
705     opts::HashHistogram = true;
706     if (opts::Output == opts::LLVM) {
707       opts::Addrsig = true;
708       opts::PrintStackSizes = true;
709     }
710     opts::Memtag = true;
711   }
712 
713   if (opts::Headers) {
714     opts::FileHeaders = true;
715     opts::XCOFFAuxiliaryHeader = true;
716     opts::ProgramHeaders = true;
717     opts::SectionHeaders = true;
718   }
719 
720   std::unique_ptr<ScopedPrinter> Writer = createWriter();
721 
722   for (const std::string &I : opts::InputFilenames)
723     dumpInput(I, *Writer);
724 
725   if (opts::CodeViewMergedTypes) {
726     if (opts::CodeViewEnableGHash)
727       dumpCodeViewMergedTypes(*Writer, CVTypes.GlobalIDTable.records(),
728                               CVTypes.GlobalTypeTable.records());
729     else
730       dumpCodeViewMergedTypes(*Writer, CVTypes.IDTable.records(),
731                               CVTypes.TypeTable.records());
732   }
733 
734   return 0;
735 }
736