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