[NFC][Py Reformat] Reformat python files in llvm
[llvm-project.git] / llvm / tools / llvm-readobj / llvm-readobj.cpp
blobd72eec04d06ae255faacd09b8a7c005ce8d461c4
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.
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.
17 // Output should be specialized for each format where appropriate.
19 //===----------------------------------------------------------------------===//
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/InitLLVM.h"
46 #include "llvm/Support/LLVMDriver.h"
47 #include "llvm/Support/Path.h"
48 #include "llvm/Support/ScopedPrinter.h"
49 #include "llvm/Support/WithColor.h"
51 using namespace llvm;
52 using namespace llvm::object;
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
65 #define PREFIX(NAME, VALUE) \
66 static constexpr StringLiteral NAME##_init[] = VALUE; \
67 static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
68 std::size(NAME##_init) - 1);
69 #include "Opts.inc"
70 #undef PREFIX
72 static constexpr opt::OptTable::Info InfoTable[] = {
73 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
74 HELPTEXT, METAVAR, VALUES) \
75 { \
76 PREFIX, NAME, HELPTEXT, \
77 METAVAR, OPT_##ID, opt::Option::KIND##Class, \
78 PARAM, FLAGS, OPT_##GROUP, \
79 OPT_##ALIAS, ALIASARGS, VALUES},
80 #include "Opts.inc"
81 #undef OPTION
84 class ReadobjOptTable : public opt::GenericOptTable {
85 public:
86 ReadobjOptTable() : opt::GenericOptTable(InfoTable) {
87 setGroupedShortOptions(true);
91 enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };
93 enum SortSymbolKeyTy {
94 NAME = 0,
95 TYPE = 1,
96 UNKNOWN = 100,
97 // TODO: add ADDRESS, SIZE as needed.
100 } // namespace
102 namespace opts {
103 static bool Addrsig;
104 static bool All;
105 static bool ArchSpecificInfo;
106 static bool BBAddrMap;
107 bool ExpandRelocs;
108 static bool CGProfile;
109 bool Demangle;
110 static bool DependentLibraries;
111 static bool DynRelocs;
112 static bool DynamicSymbols;
113 static bool FileHeaders;
114 static bool Headers;
115 static std::vector<std::string> HexDump;
116 static bool PrettyPrint;
117 static bool PrintStackMap;
118 static bool PrintStackSizes;
119 static bool Relocations;
120 bool SectionData;
121 static bool SectionDetails;
122 static bool SectionHeaders;
123 bool SectionRelocations;
124 bool SectionSymbols;
125 static std::vector<std::string> StringDump;
126 static bool StringTable;
127 static bool Symbols;
128 static bool UnwindInfo;
129 static cl::boolOrDefault SectionMapping;
130 static SmallVector<SortSymbolKeyTy> SortKeys;
132 // ELF specific options.
133 static bool DynamicTable;
134 static bool ELFLinkerOptions;
135 static bool GnuHashTable;
136 static bool HashSymbols;
137 static bool HashTable;
138 static bool HashHistogram;
139 static bool Memtag;
140 static bool NeededLibraries;
141 static bool Notes;
142 static bool ProgramHeaders;
143 bool RawRelr;
144 static bool SectionGroups;
145 static bool VersionInfo;
147 // Mach-O specific options.
148 static bool MachODataInCode;
149 static bool MachODysymtab;
150 static bool MachOIndirectSymbols;
151 static bool MachOLinkerOptions;
152 static bool MachOSegment;
153 static bool MachOVersionMin;
155 // PE/COFF specific options.
156 static bool CodeView;
157 static bool CodeViewEnableGHash;
158 static bool CodeViewMergedTypes;
159 bool CodeViewSubsectionBytes;
160 static bool COFFBaseRelocs;
161 static bool COFFDebugDirectory;
162 static bool COFFDirectives;
163 static bool COFFExports;
164 static bool COFFImports;
165 static bool COFFLoadConfig;
166 static bool COFFResources;
167 static bool COFFTLSDirectory;
169 // XCOFF specific options.
170 static bool XCOFFAuxiliaryHeader;
171 static bool XCOFFLoaderSectionHeader;
172 static bool XCOFFLoaderSectionSymbol;
173 static bool XCOFFLoaderSectionRelocation;
174 static bool XCOFFExceptionSection;
176 OutputStyleTy Output = OutputStyleTy::LLVM;
177 static std::vector<std::string> InputFilenames;
178 } // namespace opts
180 static StringRef ToolName;
182 namespace llvm {
184 [[noreturn]] static void error(Twine Msg) {
185 // Flush the standard output to print the error at a
186 // proper place.
187 fouts().flush();
188 WithColor::error(errs(), ToolName) << Msg << "\n";
189 exit(1);
192 [[noreturn]] void reportError(Error Err, StringRef Input) {
193 assert(Err);
194 if (Input == "-")
195 Input = "<stdin>";
196 handleAllErrors(createFileError(Input, std::move(Err)),
197 [&](const ErrorInfoBase &EI) { error(EI.message()); });
198 llvm_unreachable("error() call should never return");
201 void reportWarning(Error Err, StringRef Input) {
202 assert(Err);
203 if (Input == "-")
204 Input = "<stdin>";
206 // Flush the standard output to print the warning at a
207 // proper place.
208 fouts().flush();
209 handleAllErrors(
210 createFileError(Input, std::move(Err)), [&](const ErrorInfoBase &EI) {
211 WithColor::warning(errs(), ToolName) << EI.message() << "\n";
215 } // namespace llvm
217 static void parseOptions(const opt::InputArgList &Args) {
218 opts::Addrsig = Args.hasArg(OPT_addrsig);
219 opts::All = Args.hasArg(OPT_all);
220 opts::ArchSpecificInfo = Args.hasArg(OPT_arch_specific);
221 opts::BBAddrMap = Args.hasArg(OPT_bb_addr_map);
222 opts::CGProfile = Args.hasArg(OPT_cg_profile);
223 opts::Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, false);
224 opts::DependentLibraries = Args.hasArg(OPT_dependent_libraries);
225 opts::DynRelocs = Args.hasArg(OPT_dyn_relocations);
226 opts::DynamicSymbols = Args.hasArg(OPT_dyn_syms);
227 opts::ExpandRelocs = Args.hasArg(OPT_expand_relocs);
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);
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 + "'");
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::RawRelr = Args.hasArg(OPT_raw_relr);
276 opts::SectionGroups = Args.hasArg(OPT_section_groups);
277 if (Arg *A = Args.getLastArg(OPT_sort_symbols_EQ)) {
278 std::string SortKeysString = A->getValue();
279 for (StringRef KeyStr : llvm::split(A->getValue(), ",")) {
280 SortSymbolKeyTy KeyType = StringSwitch<SortSymbolKeyTy>(KeyStr)
281 .Case("name", SortSymbolKeyTy::NAME)
282 .Case("type", SortSymbolKeyTy::TYPE)
283 .Default(SortSymbolKeyTy::UNKNOWN);
284 if (KeyType == SortSymbolKeyTy::UNKNOWN)
285 error("--sort-symbols value should be 'name' or 'type', but was '" +
286 Twine(KeyStr) + "'");
287 opts::SortKeys.push_back(KeyType);
290 opts::VersionInfo = Args.hasArg(OPT_version_info);
292 // Mach-O specific options.
293 opts::MachODataInCode = Args.hasArg(OPT_macho_data_in_code);
294 opts::MachODysymtab = Args.hasArg(OPT_macho_dysymtab);
295 opts::MachOIndirectSymbols = Args.hasArg(OPT_macho_indirect_symbols);
296 opts::MachOLinkerOptions = Args.hasArg(OPT_macho_linker_options);
297 opts::MachOSegment = Args.hasArg(OPT_macho_segment);
298 opts::MachOVersionMin = Args.hasArg(OPT_macho_version_min);
300 // PE/COFF specific options.
301 opts::CodeView = Args.hasArg(OPT_codeview);
302 opts::CodeViewEnableGHash = Args.hasArg(OPT_codeview_ghash);
303 opts::CodeViewMergedTypes = Args.hasArg(OPT_codeview_merged_types);
304 opts::CodeViewSubsectionBytes = Args.hasArg(OPT_codeview_subsection_bytes);
305 opts::COFFBaseRelocs = Args.hasArg(OPT_coff_basereloc);
306 opts::COFFDebugDirectory = Args.hasArg(OPT_coff_debug_directory);
307 opts::COFFDirectives = Args.hasArg(OPT_coff_directives);
308 opts::COFFExports = Args.hasArg(OPT_coff_exports);
309 opts::COFFImports = Args.hasArg(OPT_coff_imports);
310 opts::COFFLoadConfig = Args.hasArg(OPT_coff_load_config);
311 opts::COFFResources = Args.hasArg(OPT_coff_resources);
312 opts::COFFTLSDirectory = Args.hasArg(OPT_coff_tls_directory);
314 // XCOFF specific options.
315 opts::XCOFFAuxiliaryHeader = Args.hasArg(OPT_auxiliary_header);
316 opts::XCOFFLoaderSectionHeader = Args.hasArg(OPT_loader_section_header);
317 opts::XCOFFLoaderSectionSymbol = Args.hasArg(OPT_loader_section_symbols);
318 opts::XCOFFLoaderSectionRelocation =
319 Args.hasArg(OPT_loader_section_relocations);
320 opts::XCOFFExceptionSection = Args.hasArg(OPT_exception_section);
322 opts::InputFilenames = Args.getAllArgValues(OPT_INPUT);
325 namespace {
326 struct ReadObjTypeTableBuilder {
327 ReadObjTypeTableBuilder()
328 : IDTable(Allocator), TypeTable(Allocator), GlobalIDTable(Allocator),
329 GlobalTypeTable(Allocator) {}
331 llvm::BumpPtrAllocator Allocator;
332 llvm::codeview::MergingTypeTableBuilder IDTable;
333 llvm::codeview::MergingTypeTableBuilder TypeTable;
334 llvm::codeview::GlobalTypeTableBuilder GlobalIDTable;
335 llvm::codeview::GlobalTypeTableBuilder GlobalTypeTable;
336 std::vector<OwningBinary<Binary>> Binaries;
338 } // namespace
339 static ReadObjTypeTableBuilder CVTypes;
341 /// Creates an format-specific object file dumper.
342 static Expected<std::unique_ptr<ObjDumper>>
343 createDumper(const ObjectFile &Obj, ScopedPrinter &Writer) {
344 if (const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(&Obj))
345 return createCOFFDumper(*COFFObj, Writer);
347 if (const ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj))
348 return createELFDumper(*ELFObj, Writer);
350 if (const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(&Obj))
351 return createMachODumper(*MachOObj, Writer);
353 if (const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(&Obj))
354 return createWasmDumper(*WasmObj, Writer);
356 if (const XCOFFObjectFile *XObj = dyn_cast<XCOFFObjectFile>(&Obj))
357 return createXCOFFDumper(*XObj, Writer);
359 return createStringError(errc::invalid_argument,
360 "unsupported object file format");
363 /// Dumps the specified object file.
364 static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
365 const Archive *A = nullptr) {
366 std::string FileStr =
367 A ? Twine(A->getFileName() + "(" + Obj.getFileName() + ")").str()
368 : Obj.getFileName().str();
370 std::string ContentErrString;
371 if (Error ContentErr = Obj.initContent())
372 ContentErrString = "unable to continue dumping, the file is corrupt: " +
373 toString(std::move(ContentErr));
375 ObjDumper *Dumper;
376 std::optional<SymbolComparator> SymComp;
377 Expected<std::unique_ptr<ObjDumper>> DumperOrErr = createDumper(Obj, Writer);
378 if (!DumperOrErr)
379 reportError(DumperOrErr.takeError(), FileStr);
380 Dumper = (*DumperOrErr).get();
382 if (!opts::SortKeys.empty()) {
383 if (Dumper->canCompareSymbols()) {
384 SymComp = SymbolComparator();
385 for (SortSymbolKeyTy Key : opts::SortKeys) {
386 switch (Key) {
387 case NAME:
388 SymComp->addPredicate([Dumper](SymbolRef LHS, SymbolRef RHS) {
389 return Dumper->compareSymbolsByName(LHS, RHS);
391 break;
392 case TYPE:
393 SymComp->addPredicate([Dumper](SymbolRef LHS, SymbolRef RHS) {
394 return Dumper->compareSymbolsByType(LHS, RHS);
396 break;
397 case UNKNOWN:
398 llvm_unreachable("Unsupported sort key");
402 } else {
403 reportWarning(createStringError(
404 errc::invalid_argument,
405 "--sort-symbols is not supported yet for this format"),
406 FileStr);
409 Dumper->printFileSummary(FileStr, Obj, opts::InputFilenames, A);
411 if (opts::FileHeaders)
412 Dumper->printFileHeaders();
414 // Auxiliary header in XOCFF is right after the file header, so print the data
415 // here.
416 if (Obj.isXCOFF() && opts::XCOFFAuxiliaryHeader)
417 Dumper->printAuxiliaryHeader();
419 // This is only used for ELF currently. In some cases, when an object is
420 // corrupt (e.g. truncated), we can't dump anything except the file header.
421 if (!ContentErrString.empty())
422 reportError(createError(ContentErrString), FileStr);
424 if (opts::SectionDetails || opts::SectionHeaders) {
425 if (opts::Output == opts::GNU && opts::SectionDetails)
426 Dumper->printSectionDetails();
427 else
428 Dumper->printSectionHeaders();
431 if (opts::HashSymbols)
432 Dumper->printHashSymbols();
433 if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE)
434 Dumper->printProgramHeaders(opts::ProgramHeaders, opts::SectionMapping);
435 if (opts::DynamicTable)
436 Dumper->printDynamicTable();
437 if (opts::NeededLibraries)
438 Dumper->printNeededLibraries();
439 if (opts::Relocations)
440 Dumper->printRelocations();
441 if (opts::DynRelocs)
442 Dumper->printDynamicRelocations();
443 if (opts::UnwindInfo)
444 Dumper->printUnwindInfo();
445 if (opts::Symbols || opts::DynamicSymbols)
446 Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols, SymComp);
447 if (!opts::StringDump.empty())
448 Dumper->printSectionsAsString(Obj, opts::StringDump);
449 if (!opts::HexDump.empty())
450 Dumper->printSectionsAsHex(Obj, opts::HexDump);
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();
474 if (opts::Addrsig)
475 Dumper->printAddrsig();
476 if (opts::Notes)
477 Dumper->printNotes();
478 if (opts::Memtag)
479 Dumper->printMemtag();
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);
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();
526 if (Obj.isXCOFF()) {
527 if (opts::XCOFFLoaderSectionHeader || opts::XCOFFLoaderSectionSymbol ||
528 opts::XCOFFLoaderSectionRelocation)
529 Dumper->printLoaderSection(opts::XCOFFLoaderSectionHeader,
530 opts::XCOFFLoaderSectionSymbol,
531 opts::XCOFFLoaderSectionRelocation);
533 if (opts::XCOFFExceptionSection)
534 Dumper->printExceptionSection();
537 if (opts::PrintStackMap)
538 Dumper->printStackMap();
539 if (opts::PrintStackSizes)
540 Dumper->printStackSizes();
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;
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());
565 if (Err)
566 reportError(std::move(Err), Arc->getFileName());
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);
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());
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);
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;
609 Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(
610 Buffer->getMemBufferRef(), /*Context=*/nullptr, /*InitContent=*/false);
611 if (!BinaryOrErr)
612 reportError(BinaryOrErr.takeError(), File);
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");
629 CVTypes.Binaries.push_back(
630 OwningBinary<Binary>(std::move(Bin), std::move(Buffer)));
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());
640 int llvm_readobj_main(int argc, char **argv, const llvm::ToolContext &) {
641 InitLLVM X(argc, argv);
642 BumpPtrAllocator A;
643 StringSaver Saver(A);
644 ReadobjOptTable Tbl;
645 ToolName = argv[0];
646 opt::InputArgList Args =
647 Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
648 error(Msg);
649 exit(1);
651 if (Args.hasArg(OPT_help)) {
652 Tbl.printHelp(
653 outs(),
654 (Twine(ToolName) + " [options] <input object files>").str().c_str(),
655 "LLVM Object Reader");
656 // TODO Replace this with OptTable API once it adds extrahelp support.
657 outs() << "\nPass @FILE as argument to read options from FILE.\n";
658 return 0;
660 if (Args.hasArg(OPT_version)) {
661 cl::PrintVersionMessage();
662 return 0;
665 if (sys::path::stem(argv[0]).contains("readelf"))
666 opts::Output = opts::GNU;
667 parseOptions(Args);
669 // Default to print error if no filename is specified.
670 if (opts::InputFilenames.empty()) {
671 error("no input files specified");
674 if (opts::All) {
675 opts::FileHeaders = true;
676 opts::XCOFFAuxiliaryHeader = true;
677 opts::ProgramHeaders = true;
678 opts::SectionHeaders = true;
679 opts::Symbols = true;
680 opts::Relocations = true;
681 opts::DynamicTable = true;
682 opts::Notes = true;
683 opts::VersionInfo = true;
684 opts::UnwindInfo = true;
685 opts::SectionGroups = true;
686 opts::HashHistogram = true;
687 if (opts::Output == opts::LLVM) {
688 opts::Addrsig = true;
689 opts::PrintStackSizes = true;
691 opts::Memtag = true;
694 if (opts::Headers) {
695 opts::FileHeaders = true;
696 opts::XCOFFAuxiliaryHeader = true;
697 opts::ProgramHeaders = true;
698 opts::SectionHeaders = true;
701 std::unique_ptr<ScopedPrinter> Writer = createWriter();
703 for (const std::string &I : opts::InputFilenames)
704 dumpInput(I, *Writer.get());
706 if (opts::CodeViewMergedTypes) {
707 if (opts::CodeViewEnableGHash)
708 dumpCodeViewMergedTypes(*Writer.get(), CVTypes.GlobalIDTable.records(),
709 CVTypes.GlobalTypeTable.records());
710 else
711 dumpCodeViewMergedTypes(*Writer.get(), CVTypes.IDTable.records(),
712 CVTypes.TypeTable.records());
715 return 0;