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