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