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