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