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 "Error.h"
23 #include "ObjDumper.h"
24 #include "WindowsResourceDumper.h"
25 #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
26 #include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
27 #include "llvm/Object/Archive.h"
28 #include "llvm/Object/COFFImportFile.h"
29 #include "llvm/Object/MachOUniversal.h"
30 #include "llvm/Object/ObjectFile.h"
31 #include "llvm/Object/WindowsResource.h"
32 #include "llvm/Support/Casting.h"
33 #include "llvm/Support/CommandLine.h"
34 #include "llvm/Support/DataTypes.h"
35 #include "llvm/Support/Debug.h"
36 #include "llvm/Support/FileSystem.h"
37 #include "llvm/Support/FormatVariadic.h"
38 #include "llvm/Support/InitLLVM.h"
39 #include "llvm/Support/Path.h"
40 #include "llvm/Support/ScopedPrinter.h"
41 #include "llvm/Support/TargetRegistry.h"
42 #include "llvm/Support/WithColor.h"
43 
44 using namespace llvm;
45 using namespace llvm::object;
46 
47 namespace opts {
48   cl::list<std::string> InputFilenames(cl::Positional,
49     cl::desc("<input object files>"),
50     cl::ZeroOrMore);
51 
52   // --all, -a
53   cl::opt<bool>
54       All("all",
55           cl::desc("Equivalent to setting: --file-headers, --program-headers, "
56                    "--section-headers, --symbols, --relocations, "
57                    "--dynamic-table, --notes, --version-info, --unwind, "
58                    "--section-groups and --elf-hash-histogram."));
59   cl::alias AllShort("a", cl::desc("Alias for --all"), cl::aliasopt(All));
60 
61   // --dependent-libraries
62   cl::opt<bool>
63       DependentLibraries("dependent-libraries",
64                          cl::desc("Display the dependent libraries section"));
65 
66   // --headers -e
67   cl::opt<bool>
68       Headers("headers",
69           cl::desc("Equivalent to setting: --file-headers, --program-headers, "
70                    "--section-headers"));
71   cl::alias HeadersShort("e", cl::desc("Alias for --headers"),
72      cl::aliasopt(Headers));
73 
74   // --wide, -W
75   cl::opt<bool>
76       WideOutput("wide", cl::desc("Ignored for compatibility with GNU readelf"),
77                  cl::Hidden);
78   cl::alias WideOutputShort("W",
79     cl::desc("Alias for --wide"),
80     cl::aliasopt(WideOutput));
81 
82   // --file-headers, --file-header, -h
83   cl::opt<bool> FileHeaders("file-headers",
84     cl::desc("Display file headers "));
85   cl::alias FileHeadersShort("h", cl::desc("Alias for --file-headers"),
86                              cl::aliasopt(FileHeaders), cl::NotHidden);
87   cl::alias FileHeadersSingular("file-header",
88                                 cl::desc("Alias for --file-headers"),
89                                 cl::aliasopt(FileHeaders));
90 
91   // --section-headers, --sections, -S
92   // Also -s in llvm-readobj mode.
93   cl::opt<bool> SectionHeaders("section-headers",
94                                cl::desc("Display all section headers."));
95   cl::alias SectionsShortUpper("S", cl::desc("Alias for --section-headers"),
96                                cl::aliasopt(SectionHeaders), cl::NotHidden);
97   cl::alias SectionHeadersAlias("sections",
98                                 cl::desc("Alias for --section-headers"),
99                                 cl::aliasopt(SectionHeaders), cl::NotHidden);
100 
101   // --section-relocations
102   // Also --sr in llvm-readobj mode.
103   cl::opt<bool> SectionRelocations("section-relocations",
104     cl::desc("Display relocations for each section shown."));
105 
106   // --section-symbols
107   // Also --st in llvm-readobj mode.
108   cl::opt<bool> SectionSymbols("section-symbols",
109     cl::desc("Display symbols for each section shown."));
110 
111   // --section-data
112   // Also --sd in llvm-readobj mode.
113   cl::opt<bool> SectionData("section-data",
114     cl::desc("Display section data for each section shown."));
115 
116   // --section-mapping
117   cl::opt<cl::boolOrDefault>
118       SectionMapping("section-mapping",
119                      cl::desc("Display the section to segment mapping."));
120 
121   // --relocations, --relocs, -r
122   cl::opt<bool> Relocations("relocations",
123     cl::desc("Display the relocation entries in the file"));
124   cl::alias RelocationsShort("r", cl::desc("Alias for --relocations"),
125                              cl::aliasopt(Relocations), cl::NotHidden);
126   cl::alias RelocationsGNU("relocs", cl::desc("Alias for --relocations"),
127                            cl::aliasopt(Relocations));
128 
129   // --notes, -n
130   cl::opt<bool> Notes("notes", cl::desc("Display the ELF notes in the file"));
131   cl::alias NotesShort("n", cl::desc("Alias for --notes"), cl::aliasopt(Notes));
132 
133   // --dyn-relocations
134   cl::opt<bool> DynRelocs("dyn-relocations",
135     cl::desc("Display the dynamic relocation entries in the file"));
136 
137   // --symbols
138   // Also -s in llvm-readelf mode, or -t in llvm-readobj mode.
139   cl::opt<bool>
140       Symbols("symbols",
141               cl::desc("Display the symbol table. Also display the dynamic "
142                        "symbol table when using GNU output style for ELF"));
143   cl::alias SymbolsGNU("syms", cl::desc("Alias for --symbols"),
144                        cl::aliasopt(Symbols));
145 
146   // --dyn-symbols, --dyn-syms
147   // Also --dt in llvm-readobj mode.
148   cl::opt<bool> DynamicSymbols("dyn-symbols",
149     cl::desc("Display the dynamic symbol table"));
150   cl::alias DynSymsGNU("dyn-syms", cl::desc("Alias for --dyn-symbols"),
151                        cl::aliasopt(DynamicSymbols));
152 
153   // --hash-symbols
154   cl::opt<bool> HashSymbols(
155       "hash-symbols",
156       cl::desc("Display the dynamic symbols derived from the hash section"));
157 
158   // --unwind, -u
159   cl::opt<bool> UnwindInfo("unwind",
160     cl::desc("Display unwind information"));
161   cl::alias UnwindInfoShort("u",
162     cl::desc("Alias for --unwind"),
163     cl::aliasopt(UnwindInfo));
164 
165   // --dynamic-table, --dynamic, -d
166   cl::opt<bool> DynamicTable("dynamic-table",
167     cl::desc("Display the ELF .dynamic section table"));
168   cl::alias DynamicTableShort("d", cl::desc("Alias for --dynamic-table"),
169                               cl::aliasopt(DynamicTable), cl::NotHidden);
170   cl::alias DynamicTableAlias("dynamic", cl::desc("Alias for --dynamic-table"),
171                               cl::aliasopt(DynamicTable));
172 
173   // --needed-libs
174   cl::opt<bool> NeededLibraries("needed-libs",
175     cl::desc("Display the needed libraries"));
176 
177   // --program-headers, --segments, -l
178   cl::opt<bool> ProgramHeaders("program-headers",
179     cl::desc("Display ELF program headers"));
180   cl::alias ProgramHeadersShort("l", cl::desc("Alias for --program-headers"),
181                                 cl::aliasopt(ProgramHeaders), cl::NotHidden);
182   cl::alias SegmentsAlias("segments", cl::desc("Alias for --program-headers"),
183                           cl::aliasopt(ProgramHeaders));
184 
185   // --string-dump, -p
186   cl::list<std::string> StringDump(
187       "string-dump", cl::value_desc("number|name"),
188       cl::desc("Display the specified section(s) as a list of strings"),
189       cl::ZeroOrMore);
190   cl::alias StringDumpShort("p", cl::desc("Alias for --string-dump"),
191                             cl::aliasopt(StringDump), cl::Prefix);
192 
193   // --hex-dump, -x
194   cl::list<std::string>
195       HexDump("hex-dump", cl::value_desc("number|name"),
196               cl::desc("Display the specified section(s) as hexadecimal bytes"),
197               cl::ZeroOrMore);
198   cl::alias HexDumpShort("x", cl::desc("Alias for --hex-dump"),
199                          cl::aliasopt(HexDump), cl::Prefix);
200 
201   // --demangle, -C
202   cl::opt<bool> Demangle("demangle",
203                          cl::desc("Demangle symbol names in output"));
204   cl::alias DemangleShort("C", cl::desc("Alias for --demangle"),
205                           cl::aliasopt(Demangle), cl::NotHidden);
206 
207   // --hash-table
208   cl::opt<bool> HashTable("hash-table",
209     cl::desc("Display ELF hash table"));
210 
211   // --gnu-hash-table
212   cl::opt<bool> GnuHashTable("gnu-hash-table",
213     cl::desc("Display ELF .gnu.hash section"));
214 
215   // --expand-relocs
216   cl::opt<bool> ExpandRelocs("expand-relocs",
217     cl::desc("Expand each shown relocation to multiple lines"));
218 
219   // --raw-relr
220   cl::opt<bool> RawRelr("raw-relr",
221     cl::desc("Do not decode relocations in SHT_RELR section, display raw contents"));
222 
223   // --codeview
224   cl::opt<bool> CodeView("codeview",
225                          cl::desc("Display CodeView debug information"));
226 
227   // --codeview-merged-types
228   cl::opt<bool>
229       CodeViewMergedTypes("codeview-merged-types",
230                           cl::desc("Display the merged CodeView type stream"));
231 
232   // --codeview-ghash
233   cl::opt<bool> CodeViewEnableGHash(
234       "codeview-ghash",
235       cl::desc(
236           "Enable global hashing for CodeView type stream de-duplication"));
237 
238   // --codeview-subsection-bytes
239   cl::opt<bool> CodeViewSubsectionBytes(
240       "codeview-subsection-bytes",
241       cl::desc("Dump raw contents of codeview debug sections and records"));
242 
243   // --arch-specific
244   cl::opt<bool> ArchSpecificInfo("arch-specific",
245                               cl::desc("Displays architecture-specific information, if there is any."));
246   cl::alias ArchSpecifcInfoShort("A", cl::desc("Alias for --arch-specific"),
247                                  cl::aliasopt(ArchSpecificInfo), cl::NotHidden);
248 
249   // --coff-imports
250   cl::opt<bool>
251   COFFImports("coff-imports", cl::desc("Display the PE/COFF import table"));
252 
253   // --coff-exports
254   cl::opt<bool>
255   COFFExports("coff-exports", cl::desc("Display the PE/COFF export table"));
256 
257   // --coff-directives
258   cl::opt<bool>
259   COFFDirectives("coff-directives",
260                  cl::desc("Display the PE/COFF .drectve section"));
261 
262   // --coff-basereloc
263   cl::opt<bool>
264   COFFBaseRelocs("coff-basereloc",
265                  cl::desc("Display the PE/COFF .reloc section"));
266 
267   // --coff-debug-directory
268   cl::opt<bool>
269   COFFDebugDirectory("coff-debug-directory",
270                      cl::desc("Display the PE/COFF debug directory"));
271 
272   // --coff-resources
273   cl::opt<bool> COFFResources("coff-resources",
274                               cl::desc("Display the PE/COFF .rsrc section"));
275 
276   // --coff-load-config
277   cl::opt<bool>
278   COFFLoadConfig("coff-load-config",
279                  cl::desc("Display the PE/COFF load config"));
280 
281   // --elf-linker-options
282   cl::opt<bool>
283   ELFLinkerOptions("elf-linker-options",
284                    cl::desc("Display the ELF .linker-options section"));
285 
286   // --macho-data-in-code
287   cl::opt<bool>
288   MachODataInCode("macho-data-in-code",
289                   cl::desc("Display MachO Data in Code command"));
290 
291   // --macho-indirect-symbols
292   cl::opt<bool>
293   MachOIndirectSymbols("macho-indirect-symbols",
294                   cl::desc("Display MachO indirect symbols"));
295 
296   // --macho-linker-options
297   cl::opt<bool>
298   MachOLinkerOptions("macho-linker-options",
299                   cl::desc("Display MachO linker options"));
300 
301   // --macho-segment
302   cl::opt<bool>
303   MachOSegment("macho-segment",
304                   cl::desc("Display MachO Segment command"));
305 
306   // --macho-version-min
307   cl::opt<bool>
308   MachOVersionMin("macho-version-min",
309                   cl::desc("Display MachO version min command"));
310 
311   // --macho-dysymtab
312   cl::opt<bool>
313   MachODysymtab("macho-dysymtab",
314                   cl::desc("Display MachO Dysymtab command"));
315 
316   // --stackmap
317   cl::opt<bool>
318   PrintStackMap("stackmap",
319                 cl::desc("Display contents of stackmap section"));
320 
321   // --stack-sizes
322   cl::opt<bool>
323       PrintStackSizes("stack-sizes",
324                       cl::desc("Display contents of all stack sizes sections"));
325 
326   // --version-info, -V
327   cl::opt<bool>
328       VersionInfo("version-info",
329                   cl::desc("Display ELF version sections (if present)"));
330   cl::alias VersionInfoShort("V", cl::desc("Alias for -version-info"),
331                              cl::aliasopt(VersionInfo));
332 
333   // --elf-section-groups, --section-groups, -g
334   cl::opt<bool> SectionGroups("elf-section-groups",
335                               cl::desc("Display ELF section group contents"));
336   cl::alias SectionGroupsAlias("section-groups",
337                                cl::desc("Alias for -elf-sections-groups"),
338                                cl::aliasopt(SectionGroups));
339   cl::alias SectionGroupsShort("g", cl::desc("Alias for -elf-sections-groups"),
340                                cl::aliasopt(SectionGroups));
341 
342   // --elf-hash-histogram, --histogram, -I
343   cl::opt<bool> HashHistogram(
344       "elf-hash-histogram",
345       cl::desc("Display bucket list histogram for hash sections"));
346   cl::alias HashHistogramShort("I", cl::desc("Alias for -elf-hash-histogram"),
347                                cl::aliasopt(HashHistogram));
348   cl::alias HistogramAlias("histogram",
349                            cl::desc("Alias for --elf-hash-histogram"),
350                            cl::aliasopt(HashHistogram));
351 
352   // --cg-profile
353   cl::opt<bool> CGProfile("cg-profile",
354                           cl::desc("Display callgraph profile section"));
355   cl::alias ELFCGProfile("elf-cg-profile", cl::desc("Alias for --cg-profile"),
356                          cl::aliasopt(CGProfile));
357 
358   // -addrsig
359   cl::opt<bool> Addrsig("addrsig",
360                         cl::desc("Display address-significance table"));
361 
362   // -elf-output-style
363   cl::opt<OutputStyleTy>
364       Output("elf-output-style", cl::desc("Specify ELF dump style"),
365              cl::values(clEnumVal(LLVM, "LLVM default style"),
366                         clEnumVal(GNU, "GNU readelf style")),
367              cl::init(LLVM));
368 
369   cl::extrahelp
370       HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
371 } // namespace opts
372 
373 static StringRef ToolName;
374 
375 namespace llvm {
376 
377 LLVM_ATTRIBUTE_NORETURN static void error(Twine Msg) {
378   // Flush the standard output to print the error at a
379   // proper place.
380   fouts().flush();
381   WithColor::error(errs(), ToolName) << Msg << "\n";
382   exit(1);
383 }
384 
385 LLVM_ATTRIBUTE_NORETURN void reportError(Error Err, StringRef Input) {
386   assert(Err);
387   if (Input == "-")
388     Input = "<stdin>";
389   handleAllErrors(createFileError(Input, std::move(Err)),
390                   [&](const ErrorInfoBase &EI) { error(EI.message()); });
391   llvm_unreachable("error() call should never return");
392 }
393 
394 void reportWarning(Error Err, StringRef Input) {
395   assert(Err);
396   if (Input == "-")
397     Input = "<stdin>";
398 
399   // Flush the standard output to print the warning at a
400   // proper place.
401   fouts().flush();
402   handleAllErrors(
403       createFileError(Input, std::move(Err)), [&](const ErrorInfoBase &EI) {
404         WithColor::warning(errs(), ToolName) << EI.message() << "\n";
405       });
406 }
407 
408 } // namespace llvm
409 
410 namespace {
411 struct ReadObjTypeTableBuilder {
412   ReadObjTypeTableBuilder()
413       : Allocator(), IDTable(Allocator), TypeTable(Allocator),
414         GlobalIDTable(Allocator), GlobalTypeTable(Allocator) {}
415 
416   llvm::BumpPtrAllocator Allocator;
417   llvm::codeview::MergingTypeTableBuilder IDTable;
418   llvm::codeview::MergingTypeTableBuilder TypeTable;
419   llvm::codeview::GlobalTypeTableBuilder GlobalIDTable;
420   llvm::codeview::GlobalTypeTableBuilder GlobalTypeTable;
421   std::vector<OwningBinary<Binary>> Binaries;
422 };
423 } // namespace
424 static ReadObjTypeTableBuilder CVTypes;
425 
426 /// Creates an format-specific object file dumper.
427 static std::error_code createDumper(const ObjectFile *Obj,
428                                     ScopedPrinter &Writer,
429                                     std::unique_ptr<ObjDumper> &Result) {
430   if (!Obj)
431     return readobj_error::unsupported_file_format;
432 
433   if (Obj->isCOFF())
434     return createCOFFDumper(Obj, Writer, Result);
435   if (Obj->isELF())
436     return createELFDumper(Obj, Writer, Result);
437   if (Obj->isMachO())
438     return createMachODumper(Obj, Writer, Result);
439   if (Obj->isWasm())
440     return createWasmDumper(Obj, Writer, Result);
441   if (Obj->isXCOFF())
442     return createXCOFFDumper(Obj, Writer, Result);
443 
444   return readobj_error::unsupported_obj_file_format;
445 }
446 
447 /// Dumps the specified object file.
448 static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
449                        const Archive *A = nullptr) {
450   std::string FileStr =
451           A ? Twine(A->getFileName() + "(" + Obj->getFileName() + ")").str()
452             : Obj->getFileName().str();
453 
454   std::unique_ptr<ObjDumper> Dumper;
455   if (std::error_code EC = createDumper(Obj, Writer, Dumper))
456     reportError(errorCodeToError(EC), FileStr);
457 
458   if (opts::Output == opts::LLVM || opts::InputFilenames.size() > 1 || A) {
459     Writer.startLine() << "\n";
460     Writer.printString("File", FileStr);
461   }
462   if (opts::Output == opts::LLVM) {
463     Writer.printString("Format", Obj->getFileFormatName());
464     Writer.printString("Arch", Triple::getArchTypeName(
465                                    (llvm::Triple::ArchType)Obj->getArch()));
466     Writer.printString(
467         "AddressSize",
468         std::string(formatv("{0}bit", 8 * Obj->getBytesInAddress())));
469     Dumper->printLoadName();
470   }
471 
472   if (opts::FileHeaders)
473     Dumper->printFileHeaders();
474   if (opts::SectionHeaders)
475     Dumper->printSectionHeaders();
476   if (opts::HashSymbols)
477     Dumper->printHashSymbols();
478   if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE)
479     Dumper->printProgramHeaders(opts::ProgramHeaders, opts::SectionMapping);
480   if (opts::DynamicTable)
481     Dumper->printDynamicTable();
482   if (opts::NeededLibraries)
483     Dumper->printNeededLibraries();
484   if (opts::Relocations)
485     Dumper->printRelocations();
486   if (opts::DynRelocs)
487     Dumper->printDynamicRelocations();
488   if (opts::UnwindInfo)
489     Dumper->printUnwindInfo();
490   if (opts::Symbols || opts::DynamicSymbols)
491     Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols);
492   if (!opts::StringDump.empty())
493     Dumper->printSectionsAsString(Obj, opts::StringDump);
494   if (!opts::HexDump.empty())
495     Dumper->printSectionsAsHex(Obj, opts::HexDump);
496   if (opts::HashTable)
497     Dumper->printHashTable();
498   if (opts::GnuHashTable)
499     Dumper->printGnuHashTable(Obj);
500   if (opts::VersionInfo)
501     Dumper->printVersionInfo();
502   if (Obj->isELF()) {
503     if (opts::DependentLibraries)
504       Dumper->printDependentLibs();
505     if (opts::ELFLinkerOptions)
506       Dumper->printELFLinkerOptions();
507     if (opts::ArchSpecificInfo)
508       Dumper->printArchSpecificInfo();
509     if (opts::SectionGroups)
510       Dumper->printGroupSections();
511     if (opts::HashHistogram)
512       Dumper->printHashHistograms();
513     if (opts::CGProfile)
514       Dumper->printCGProfile();
515     if (opts::Addrsig)
516       Dumper->printAddrsig();
517     if (opts::Notes)
518       Dumper->printNotes();
519   }
520   if (Obj->isCOFF()) {
521     if (opts::COFFImports)
522       Dumper->printCOFFImports();
523     if (opts::COFFExports)
524       Dumper->printCOFFExports();
525     if (opts::COFFDirectives)
526       Dumper->printCOFFDirectives();
527     if (opts::COFFBaseRelocs)
528       Dumper->printCOFFBaseReloc();
529     if (opts::COFFDebugDirectory)
530       Dumper->printCOFFDebugDirectory();
531     if (opts::COFFResources)
532       Dumper->printCOFFResources();
533     if (opts::COFFLoadConfig)
534       Dumper->printCOFFLoadConfig();
535     if (opts::CGProfile)
536       Dumper->printCGProfile();
537     if (opts::Addrsig)
538       Dumper->printAddrsig();
539     if (opts::CodeView)
540       Dumper->printCodeViewDebugInfo();
541     if (opts::CodeViewMergedTypes)
542       Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable,
543                                  CVTypes.GlobalIDTable, CVTypes.GlobalTypeTable,
544                                  opts::CodeViewEnableGHash);
545   }
546   if (Obj->isMachO()) {
547     if (opts::MachODataInCode)
548       Dumper->printMachODataInCode();
549     if (opts::MachOIndirectSymbols)
550       Dumper->printMachOIndirectSymbols();
551     if (opts::MachOLinkerOptions)
552       Dumper->printMachOLinkerOptions();
553     if (opts::MachOSegment)
554       Dumper->printMachOSegment();
555     if (opts::MachOVersionMin)
556       Dumper->printMachOVersionMin();
557     if (opts::MachODysymtab)
558       Dumper->printMachODysymtab();
559   }
560   if (opts::PrintStackMap)
561     Dumper->printStackMap();
562   if (opts::PrintStackSizes)
563     Dumper->printStackSizes();
564 }
565 
566 /// Dumps each object file in \a Arc;
567 static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) {
568   Error Err = Error::success();
569   for (auto &Child : Arc->children(Err)) {
570     Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
571     if (!ChildOrErr) {
572       if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
573         reportError(std::move(E), Arc->getFileName());
574       continue;
575     }
576     if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
577       dumpObject(Obj, Writer, Arc);
578     else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(&*ChildOrErr.get()))
579       dumpCOFFImportFile(Imp, Writer);
580     else
581       reportError(errorCodeToError(readobj_error::unrecognized_file_format),
582                   Arc->getFileName());
583   }
584   if (Err)
585     reportError(std::move(Err), Arc->getFileName());
586 }
587 
588 /// Dumps each object file in \a MachO Universal Binary;
589 static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary,
590                                      ScopedPrinter &Writer) {
591   for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) {
592     Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile();
593     if (ObjOrErr)
594       dumpObject(&*ObjOrErr.get(), Writer);
595     else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError()))
596       reportError(ObjOrErr.takeError(), UBinary->getFileName());
597     else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive())
598       dumpArchive(&*AOrErr.get(), Writer);
599   }
600 }
601 
602 /// Dumps \a WinRes, Windows Resource (.res) file;
603 static void dumpWindowsResourceFile(WindowsResource *WinRes,
604                                     ScopedPrinter &Printer) {
605   WindowsRes::Dumper Dumper(WinRes, Printer);
606   if (auto Err = Dumper.printData())
607     reportError(std::move(Err), WinRes->getFileName());
608 }
609 
610 
611 /// Opens \a File and dumps it.
612 static void dumpInput(StringRef File, ScopedPrinter &Writer) {
613   // Attempt to open the binary.
614   Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
615   if (!BinaryOrErr)
616     reportError(BinaryOrErr.takeError(), File);
617   Binary &Binary = *BinaryOrErr.get().getBinary();
618 
619   if (Archive *Arc = dyn_cast<Archive>(&Binary))
620     dumpArchive(Arc, Writer);
621   else if (MachOUniversalBinary *UBinary =
622                dyn_cast<MachOUniversalBinary>(&Binary))
623     dumpMachOUniversalBinary(UBinary, Writer);
624   else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
625     dumpObject(Obj, Writer);
626   else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(&Binary))
627     dumpCOFFImportFile(Import, Writer);
628   else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(&Binary))
629     dumpWindowsResourceFile(WinRes, Writer);
630   else
631     reportError(errorCodeToError(readobj_error::unrecognized_file_format),
632                 File);
633 
634   CVTypes.Binaries.push_back(std::move(*BinaryOrErr));
635 }
636 
637 /// Registers aliases that should only be allowed by readobj.
638 static void registerReadobjAliases() {
639   // -s has meant --sections for a very long time in llvm-readobj despite
640   // meaning --symbols in readelf.
641   static cl::alias SectionsShort("s", cl::desc("Alias for --section-headers"),
642                                  cl::aliasopt(opts::SectionHeaders),
643                                  cl::NotHidden);
644 
645   // Only register -t in llvm-readobj, as readelf reserves it for
646   // --section-details (not implemented yet).
647   static cl::alias SymbolsShort("t", cl::desc("Alias for --symbols"),
648                                 cl::aliasopt(opts::Symbols), cl::NotHidden);
649 
650   // The following two-letter aliases are only provided for readobj, as readelf
651   // allows single-letter args to be grouped together.
652   static cl::alias SectionRelocationsShort(
653       "sr", cl::desc("Alias for --section-relocations"),
654       cl::aliasopt(opts::SectionRelocations));
655   static cl::alias SectionDataShort("sd", cl::desc("Alias for --section-data"),
656                                     cl::aliasopt(opts::SectionData));
657   static cl::alias SectionSymbolsShort("st",
658                                        cl::desc("Alias for --section-symbols"),
659                                        cl::aliasopt(opts::SectionSymbols));
660   static cl::alias DynamicSymbolsShort("dt",
661                                        cl::desc("Alias for --dyn-symbols"),
662                                        cl::aliasopt(opts::DynamicSymbols));
663 }
664 
665 /// Registers aliases that should only be allowed by readelf.
666 static void registerReadelfAliases() {
667   // -s is here because for readobj it means --sections.
668   static cl::alias SymbolsShort("s", cl::desc("Alias for --symbols"),
669                                 cl::aliasopt(opts::Symbols), cl::NotHidden,
670                                 cl::Grouping);
671 
672   // Allow all single letter flags to be grouped together.
673   for (auto &OptEntry : cl::getRegisteredOptions()) {
674     StringRef ArgName = OptEntry.getKey();
675     cl::Option *Option = OptEntry.getValue();
676     if (ArgName.size() == 1)
677       apply(Option, cl::Grouping);
678   }
679 }
680 
681 int main(int argc, const char *argv[]) {
682   InitLLVM X(argc, argv);
683   ToolName = argv[0];
684 
685   // Register the target printer for --version.
686   cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
687 
688   if (sys::path::stem(argv[0]).contains("readelf")) {
689     opts::Output = opts::GNU;
690     registerReadelfAliases();
691   } else {
692     registerReadobjAliases();
693   }
694 
695   cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n");
696 
697   // Default to print error if no filename is specified.
698   if (opts::InputFilenames.empty()) {
699     error("no input files specified");
700   }
701 
702   if (opts::All) {
703     opts::FileHeaders = true;
704     opts::ProgramHeaders = true;
705     opts::SectionHeaders = true;
706     opts::Symbols = true;
707     opts::Relocations = true;
708     opts::DynamicTable = true;
709     opts::Notes = true;
710     opts::VersionInfo = true;
711     opts::UnwindInfo = true;
712     opts::SectionGroups = true;
713     opts::HashHistogram = true;
714     if (opts::Output == opts::LLVM) {
715       opts::Addrsig = true;
716       opts::PrintStackSizes = true;
717     }
718   }
719 
720   if (opts::Headers) {
721     opts::FileHeaders = true;
722     opts::ProgramHeaders = true;
723     opts::SectionHeaders = true;
724   }
725 
726   ScopedPrinter Writer(fouts());
727   for (const std::string &I : opts::InputFilenames)
728     dumpInput(I, Writer);
729 
730   if (opts::CodeViewMergedTypes) {
731     if (opts::CodeViewEnableGHash)
732       dumpCodeViewMergedTypes(Writer, CVTypes.GlobalIDTable.records(),
733                               CVTypes.GlobalTypeTable.records());
734     else
735       dumpCodeViewMergedTypes(Writer, CVTypes.IDTable.records(),
736                               CVTypes.TypeTable.records());
737   }
738 
739   return 0;
740 }
741