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