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