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