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