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