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