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