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