diff options
Diffstat (limited to 'contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp | 683 |
1 files changed, 683 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp new file mode 100644 index 000000000000..e1ebbeb41f28 --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -0,0 +1,683 @@ +//===- llvm-readobj.cpp - Dump contents of an Object File -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is a tool similar to readelf, except it works on multiple object file +// formats. The main purpose of this tool is to provide detailed output suitable +// for FileCheck. +// +// Flags should be similar to readelf where supported, but the output format +// does not need to be identical. The point is to not make users learn yet +// another set of flags. +// +// Output should be specialized for each format where appropriate. +// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "ObjDumper.h" +#include "WindowsResourceDumper.h" +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" +#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/MachOUniversal.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/Wasm.h" +#include "llvm/Object/WindowsResource.h" +#include "llvm/Object/XCOFFObjectFile.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/WithColor.h" + +using namespace llvm; +using namespace llvm::object; + +namespace { +using namespace llvm::opt; // for HelpHidden in Opts.inc +enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OPT_##ID, +#include "Opts.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "Opts.inc" +#undef PREFIX + +const opt::OptTable::Info InfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + { \ + PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, VALUES}, +#include "Opts.inc" +#undef OPTION +}; + +class ReadobjOptTable : public opt::OptTable { +public: + ReadobjOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); } +}; + +enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols }; + +enum SortSymbolKeyTy { + NAME = 0, + TYPE = 1, + UNKNOWN = 100, + // TODO: add ADDRESS, SIZE as needed. +}; + +} // namespace + +namespace opts { +static bool Addrsig; +static bool All; +static bool ArchSpecificInfo; +static bool BBAddrMap; +bool ExpandRelocs; +static bool CGProfile; +bool Demangle; +static bool DependentLibraries; +static bool DynRelocs; +static bool DynamicSymbols; +static bool FileHeaders; +static bool Headers; +static std::vector<std::string> HexDump; +static bool PrettyPrint; +static bool PrintStackMap; +static bool PrintStackSizes; +static bool Relocations; +bool SectionData; +static bool SectionDetails; +static bool SectionHeaders; +bool SectionRelocations; +bool SectionSymbols; +static std::vector<std::string> StringDump; +static bool StringTable; +static bool Symbols; +static bool UnwindInfo; +static cl::boolOrDefault SectionMapping; +static SmallVector<SortSymbolKeyTy> SortKeys; + +// ELF specific options. +static bool DynamicTable; +static bool ELFLinkerOptions; +static bool GnuHashTable; +static bool HashSymbols; +static bool HashTable; +static bool HashHistogram; +static bool NeededLibraries; +static bool Notes; +static bool ProgramHeaders; +bool RawRelr; +static bool SectionGroups; +static bool VersionInfo; + +// Mach-O specific options. +static bool MachODataInCode; +static bool MachODysymtab; +static bool MachOIndirectSymbols; +static bool MachOLinkerOptions; +static bool MachOSegment; +static bool MachOVersionMin; + +// PE/COFF specific options. +static bool CodeView; +static bool CodeViewEnableGHash; +static bool CodeViewMergedTypes; +bool CodeViewSubsectionBytes; +static bool COFFBaseRelocs; +static bool COFFDebugDirectory; +static bool COFFDirectives; +static bool COFFExports; +static bool COFFImports; +static bool COFFLoadConfig; +static bool COFFResources; +static bool COFFTLSDirectory; + +// XCOFF specific options. +static bool XCOFFAuxiliaryHeader; + +OutputStyleTy Output = OutputStyleTy::LLVM; +static std::vector<std::string> InputFilenames; +} // namespace opts + +static StringRef ToolName; + +namespace llvm { + +[[noreturn]] static void error(Twine Msg) { + // Flush the standard output to print the error at a + // proper place. + fouts().flush(); + WithColor::error(errs(), ToolName) << Msg << "\n"; + exit(1); +} + +[[noreturn]] void reportError(Error Err, StringRef Input) { + assert(Err); + if (Input == "-") + Input = "<stdin>"; + handleAllErrors(createFileError(Input, std::move(Err)), + [&](const ErrorInfoBase &EI) { error(EI.message()); }); + llvm_unreachable("error() call should never return"); +} + +void reportWarning(Error Err, StringRef Input) { + assert(Err); + if (Input == "-") + Input = "<stdin>"; + + // Flush the standard output to print the warning at a + // proper place. + fouts().flush(); + handleAllErrors( + createFileError(Input, std::move(Err)), [&](const ErrorInfoBase &EI) { + WithColor::warning(errs(), ToolName) << EI.message() << "\n"; + }); +} + +} // namespace llvm + +static void parseOptions(const opt::InputArgList &Args) { + opts::Addrsig = Args.hasArg(OPT_addrsig); + opts::All = Args.hasArg(OPT_all); + opts::ArchSpecificInfo = Args.hasArg(OPT_arch_specific); + opts::BBAddrMap = Args.hasArg(OPT_bb_addr_map); + opts::CGProfile = Args.hasArg(OPT_cg_profile); + opts::Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, false); + opts::DependentLibraries = Args.hasArg(OPT_dependent_libraries); + opts::DynRelocs = Args.hasArg(OPT_dyn_relocations); + opts::DynamicSymbols = Args.hasArg(OPT_dyn_syms); + opts::ExpandRelocs = Args.hasArg(OPT_expand_relocs); + opts::FileHeaders = Args.hasArg(OPT_file_header); + opts::Headers = Args.hasArg(OPT_headers); + opts::HexDump = Args.getAllArgValues(OPT_hex_dump_EQ); + opts::Relocations = Args.hasArg(OPT_relocs); + opts::SectionData = Args.hasArg(OPT_section_data); + opts::SectionDetails = Args.hasArg(OPT_section_details); + opts::SectionHeaders = Args.hasArg(OPT_section_headers); + opts::SectionRelocations = Args.hasArg(OPT_section_relocations); + opts::SectionSymbols = Args.hasArg(OPT_section_symbols); + if (Args.hasArg(OPT_section_mapping)) + opts::SectionMapping = cl::BOU_TRUE; + else if (Args.hasArg(OPT_section_mapping_EQ_false)) + opts::SectionMapping = cl::BOU_FALSE; + else + opts::SectionMapping = cl::BOU_UNSET; + opts::PrintStackSizes = Args.hasArg(OPT_stack_sizes); + opts::PrintStackMap = Args.hasArg(OPT_stackmap); + opts::StringDump = Args.getAllArgValues(OPT_string_dump_EQ); + opts::StringTable = Args.hasArg(OPT_string_table); + opts::Symbols = Args.hasArg(OPT_symbols); + opts::UnwindInfo = Args.hasArg(OPT_unwind); + + // ELF specific options. + opts::DynamicTable = Args.hasArg(OPT_dynamic_table); + opts::ELFLinkerOptions = Args.hasArg(OPT_elf_linker_options); + if (Arg *A = Args.getLastArg(OPT_elf_output_style_EQ)) { + std::string OutputStyleChoice = A->getValue(); + opts::Output = StringSwitch<opts::OutputStyleTy>(OutputStyleChoice) + .Case("LLVM", opts::OutputStyleTy::LLVM) + .Case("GNU", opts::OutputStyleTy::GNU) + .Case("JSON", opts::OutputStyleTy::JSON) + .Default(opts::OutputStyleTy::UNKNOWN); + if (opts::Output == opts::OutputStyleTy::UNKNOWN) { + error("--elf-output-style value should be either 'LLVM', 'GNU', or " + "'JSON', but was '" + + OutputStyleChoice + "'"); + } + } + opts::GnuHashTable = Args.hasArg(OPT_gnu_hash_table); + opts::HashSymbols = Args.hasArg(OPT_hash_symbols); + opts::HashTable = Args.hasArg(OPT_hash_table); + opts::HashHistogram = Args.hasArg(OPT_histogram); + opts::NeededLibraries = Args.hasArg(OPT_needed_libs); + opts::Notes = Args.hasArg(OPT_notes); + opts::PrettyPrint = Args.hasArg(OPT_pretty_print); + opts::ProgramHeaders = Args.hasArg(OPT_program_headers); + opts::RawRelr = Args.hasArg(OPT_raw_relr); + opts::SectionGroups = Args.hasArg(OPT_section_groups); + if (Arg *A = Args.getLastArg(OPT_sort_symbols_EQ)) { + std::string SortKeysString = A->getValue(); + for (StringRef KeyStr : llvm::split(A->getValue(), ",")) { + SortSymbolKeyTy KeyType = StringSwitch<SortSymbolKeyTy>(KeyStr) + .Case("name", SortSymbolKeyTy::NAME) + .Case("type", SortSymbolKeyTy::TYPE) + .Default(SortSymbolKeyTy::UNKNOWN); + if (KeyType == SortSymbolKeyTy::UNKNOWN) + error("--sort-symbols value should be 'name' or 'type', but was '" + + Twine(KeyStr) + "'"); + opts::SortKeys.push_back(KeyType); + } + } + opts::VersionInfo = Args.hasArg(OPT_version_info); + + // Mach-O specific options. + opts::MachODataInCode = Args.hasArg(OPT_macho_data_in_code); + opts::MachODysymtab = Args.hasArg(OPT_macho_dysymtab); + opts::MachOIndirectSymbols = Args.hasArg(OPT_macho_indirect_symbols); + opts::MachOLinkerOptions = Args.hasArg(OPT_macho_linker_options); + opts::MachOSegment = Args.hasArg(OPT_macho_segment); + opts::MachOVersionMin = Args.hasArg(OPT_macho_version_min); + + // PE/COFF specific options. + opts::CodeView = Args.hasArg(OPT_codeview); + opts::CodeViewEnableGHash = Args.hasArg(OPT_codeview_ghash); + opts::CodeViewMergedTypes = Args.hasArg(OPT_codeview_merged_types); + opts::CodeViewSubsectionBytes = Args.hasArg(OPT_codeview_subsection_bytes); + opts::COFFBaseRelocs = Args.hasArg(OPT_coff_basereloc); + opts::COFFDebugDirectory = Args.hasArg(OPT_coff_debug_directory); + opts::COFFDirectives = Args.hasArg(OPT_coff_directives); + opts::COFFExports = Args.hasArg(OPT_coff_exports); + opts::COFFImports = Args.hasArg(OPT_coff_imports); + opts::COFFLoadConfig = Args.hasArg(OPT_coff_load_config); + opts::COFFResources = Args.hasArg(OPT_coff_resources); + opts::COFFTLSDirectory = Args.hasArg(OPT_coff_tls_directory); + + // XCOFF specific options. + opts::XCOFFAuxiliaryHeader = Args.hasArg(OPT_auxiliary_header); + + opts::InputFilenames = Args.getAllArgValues(OPT_INPUT); +} + +namespace { +struct ReadObjTypeTableBuilder { + ReadObjTypeTableBuilder() + : IDTable(Allocator), TypeTable(Allocator), GlobalIDTable(Allocator), + GlobalTypeTable(Allocator) {} + + llvm::BumpPtrAllocator Allocator; + llvm::codeview::MergingTypeTableBuilder IDTable; + llvm::codeview::MergingTypeTableBuilder TypeTable; + llvm::codeview::GlobalTypeTableBuilder GlobalIDTable; + llvm::codeview::GlobalTypeTableBuilder GlobalTypeTable; + std::vector<OwningBinary<Binary>> Binaries; +}; +} // namespace +static ReadObjTypeTableBuilder CVTypes; + +/// Creates an format-specific object file dumper. +static Expected<std::unique_ptr<ObjDumper>> +createDumper(const ObjectFile &Obj, ScopedPrinter &Writer) { + if (const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(&Obj)) + return createCOFFDumper(*COFFObj, Writer); + + if (const ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj)) + return createELFDumper(*ELFObj, Writer); + + if (const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(&Obj)) + return createMachODumper(*MachOObj, Writer); + + if (const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(&Obj)) + return createWasmDumper(*WasmObj, Writer); + + if (const XCOFFObjectFile *XObj = dyn_cast<XCOFFObjectFile>(&Obj)) + return createXCOFFDumper(*XObj, Writer); + + return createStringError(errc::invalid_argument, + "unsupported object file format"); +} + +/// Dumps the specified object file. +static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer, + const Archive *A = nullptr) { + std::string FileStr = + A ? Twine(A->getFileName() + "(" + Obj.getFileName() + ")").str() + : Obj.getFileName().str(); + + std::string ContentErrString; + if (Error ContentErr = Obj.initContent()) + ContentErrString = "unable to continue dumping, the file is corrupt: " + + toString(std::move(ContentErr)); + + ObjDumper *Dumper; + Optional<SymbolComparator> SymComp; + Expected<std::unique_ptr<ObjDumper>> DumperOrErr = createDumper(Obj, Writer); + if (!DumperOrErr) + reportError(DumperOrErr.takeError(), FileStr); + Dumper = (*DumperOrErr).get(); + + if (!opts::SortKeys.empty()) { + if (Dumper->canCompareSymbols()) { + SymComp = SymbolComparator(); + for (SortSymbolKeyTy Key : opts::SortKeys) { + switch (Key) { + case NAME: + SymComp->addPredicate([Dumper](SymbolRef LHS, SymbolRef RHS) { + return Dumper->compareSymbolsByName(LHS, RHS); + }); + break; + case TYPE: + SymComp->addPredicate([Dumper](SymbolRef LHS, SymbolRef RHS) { + return Dumper->compareSymbolsByType(LHS, RHS); + }); + break; + case UNKNOWN: + llvm_unreachable("Unsupported sort key"); + } + } + + } else { + reportWarning(createStringError( + errc::invalid_argument, + "--sort-symbols is not supported yet for this format"), + FileStr); + } + } + Dumper->printFileSummary(FileStr, Obj, opts::InputFilenames, A); + + if (opts::FileHeaders) + Dumper->printFileHeaders(); + + if (Obj.isXCOFF() && opts::XCOFFAuxiliaryHeader) + Dumper->printAuxiliaryHeader(); + + // This is only used for ELF currently. In some cases, when an object is + // corrupt (e.g. truncated), we can't dump anything except the file header. + if (!ContentErrString.empty()) + reportError(createError(ContentErrString), FileStr); + + if (opts::SectionDetails || opts::SectionHeaders) { + if (opts::Output == opts::GNU && opts::SectionDetails) + Dumper->printSectionDetails(); + else + Dumper->printSectionHeaders(); + } + + if (opts::HashSymbols) + Dumper->printHashSymbols(); + if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE) + Dumper->printProgramHeaders(opts::ProgramHeaders, opts::SectionMapping); + if (opts::DynamicTable) + Dumper->printDynamicTable(); + if (opts::NeededLibraries) + Dumper->printNeededLibraries(); + if (opts::Relocations) + Dumper->printRelocations(); + if (opts::DynRelocs) + Dumper->printDynamicRelocations(); + if (opts::UnwindInfo) + Dumper->printUnwindInfo(); + if (opts::Symbols || opts::DynamicSymbols) + Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols, SymComp); + if (!opts::StringDump.empty()) + Dumper->printSectionsAsString(Obj, opts::StringDump); + if (!opts::HexDump.empty()) + Dumper->printSectionsAsHex(Obj, opts::HexDump); + if (opts::HashTable) + Dumper->printHashTable(); + if (opts::GnuHashTable) + Dumper->printGnuHashTable(); + if (opts::VersionInfo) + Dumper->printVersionInfo(); + if (opts::StringTable) + Dumper->printStringTable(); + if (Obj.isELF()) { + if (opts::DependentLibraries) + Dumper->printDependentLibs(); + if (opts::ELFLinkerOptions) + Dumper->printELFLinkerOptions(); + if (opts::ArchSpecificInfo) + Dumper->printArchSpecificInfo(); + if (opts::SectionGroups) + Dumper->printGroupSections(); + if (opts::HashHistogram) + Dumper->printHashHistograms(); + if (opts::CGProfile) + Dumper->printCGProfile(); + if (opts::BBAddrMap) + Dumper->printBBAddrMaps(); + if (opts::Addrsig) + Dumper->printAddrsig(); + if (opts::Notes) + Dumper->printNotes(); + } + if (Obj.isCOFF()) { + if (opts::COFFImports) + Dumper->printCOFFImports(); + if (opts::COFFExports) + Dumper->printCOFFExports(); + if (opts::COFFDirectives) + Dumper->printCOFFDirectives(); + if (opts::COFFBaseRelocs) + Dumper->printCOFFBaseReloc(); + if (opts::COFFDebugDirectory) + Dumper->printCOFFDebugDirectory(); + if (opts::COFFTLSDirectory) + Dumper->printCOFFTLSDirectory(); + if (opts::COFFResources) + Dumper->printCOFFResources(); + if (opts::COFFLoadConfig) + Dumper->printCOFFLoadConfig(); + if (opts::CGProfile) + Dumper->printCGProfile(); + if (opts::Addrsig) + Dumper->printAddrsig(); + if (opts::CodeView) + Dumper->printCodeViewDebugInfo(); + if (opts::CodeViewMergedTypes) + Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable, + CVTypes.GlobalIDTable, CVTypes.GlobalTypeTable, + opts::CodeViewEnableGHash); + } + if (Obj.isMachO()) { + if (opts::MachODataInCode) + Dumper->printMachODataInCode(); + if (opts::MachOIndirectSymbols) + Dumper->printMachOIndirectSymbols(); + if (opts::MachOLinkerOptions) + Dumper->printMachOLinkerOptions(); + if (opts::MachOSegment) + Dumper->printMachOSegment(); + if (opts::MachOVersionMin) + Dumper->printMachOVersionMin(); + if (opts::MachODysymtab) + Dumper->printMachODysymtab(); + if (opts::CGProfile) + Dumper->printCGProfile(); + } + if (opts::PrintStackMap) + Dumper->printStackMap(); + if (opts::PrintStackSizes) + Dumper->printStackSizes(); +} + +/// Dumps each object file in \a Arc; +static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) { + Error Err = Error::success(); + for (auto &Child : Arc->children(Err)) { + Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + reportError(std::move(E), Arc->getFileName()); + continue; + } + + Binary *Bin = ChildOrErr->get(); + if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin)) + dumpObject(*Obj, Writer, Arc); + else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(Bin)) + dumpCOFFImportFile(Imp, Writer); + else + reportWarning(createStringError(errc::invalid_argument, + Bin->getFileName() + + " has an unsupported file type"), + Arc->getFileName()); + } + if (Err) + reportError(std::move(Err), Arc->getFileName()); +} + +/// Dumps each object file in \a MachO Universal Binary; +static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary, + ScopedPrinter &Writer) { + for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) { + Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile(); + if (ObjOrErr) + dumpObject(*ObjOrErr.get(), Writer); + else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) + reportError(ObjOrErr.takeError(), UBinary->getFileName()); + else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive()) + dumpArchive(&*AOrErr.get(), Writer); + } +} + +/// Dumps \a WinRes, Windows Resource (.res) file; +static void dumpWindowsResourceFile(WindowsResource *WinRes, + ScopedPrinter &Printer) { + WindowsRes::Dumper Dumper(WinRes, Printer); + if (auto Err = Dumper.printData()) + reportError(std::move(Err), WinRes->getFileName()); +} + + +/// Opens \a File and dumps it. +static void dumpInput(StringRef File, ScopedPrinter &Writer) { + ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = + MemoryBuffer::getFileOrSTDIN(File, /*IsText=*/false, + /*RequiresNullTerminator=*/false); + if (std::error_code EC = FileOrErr.getError()) + return reportError(errorCodeToError(EC), File); + + std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get(); + file_magic Type = identify_magic(Buffer->getBuffer()); + if (Type == file_magic::bitcode) { + reportWarning(createStringError(errc::invalid_argument, + "bitcode files are not supported"), + File); + return; + } + + Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary( + Buffer->getMemBufferRef(), /*Context=*/nullptr, /*InitContent=*/false); + if (!BinaryOrErr) + reportError(BinaryOrErr.takeError(), File); + + std::unique_ptr<Binary> Bin = std::move(*BinaryOrErr); + if (Archive *Arc = dyn_cast<Archive>(Bin.get())) + dumpArchive(Arc, Writer); + else if (MachOUniversalBinary *UBinary = + dyn_cast<MachOUniversalBinary>(Bin.get())) + dumpMachOUniversalBinary(UBinary, Writer); + else if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin.get())) + dumpObject(*Obj, Writer); + else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(Bin.get())) + dumpCOFFImportFile(Import, Writer); + else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(Bin.get())) + dumpWindowsResourceFile(WinRes, Writer); + else + llvm_unreachable("unrecognized file type"); + + CVTypes.Binaries.push_back( + OwningBinary<Binary>(std::move(Bin), std::move(Buffer))); +} + +std::unique_ptr<ScopedPrinter> createWriter() { + if (opts::Output == opts::JSON) + return std::make_unique<JSONScopedPrinter>( + fouts(), opts::PrettyPrint ? 2 : 0, std::make_unique<ListScope>()); + return std::make_unique<ScopedPrinter>(fouts()); +} + +int main(int argc, char *argv[]) { + InitLLVM X(argc, argv); + BumpPtrAllocator A; + StringSaver Saver(A); + ReadobjOptTable Tbl; + ToolName = argv[0]; + opt::InputArgList Args = + Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { + error(Msg); + exit(1); + }); + if (Args.hasArg(OPT_help)) { + Tbl.printHelp( + outs(), + (Twine(ToolName) + " [options] <input object files>").str().c_str(), + "LLVM Object Reader"); + // TODO Replace this with OptTable API once it adds extrahelp support. + outs() << "\nPass @FILE as argument to read options from FILE.\n"; + return 0; + } + if (Args.hasArg(OPT_version)) { + cl::PrintVersionMessage(); + return 0; + } + + if (sys::path::stem(argv[0]).contains("readelf")) + opts::Output = opts::GNU; + parseOptions(Args); + + // Default to print error if no filename is specified. + if (opts::InputFilenames.empty()) { + error("no input files specified"); + } + + if (opts::All) { + opts::FileHeaders = true; + opts::XCOFFAuxiliaryHeader = true; + opts::ProgramHeaders = true; + opts::SectionHeaders = true; + opts::Symbols = true; + opts::Relocations = true; + opts::DynamicTable = true; + opts::Notes = true; + opts::VersionInfo = true; + opts::UnwindInfo = true; + opts::SectionGroups = true; + opts::HashHistogram = true; + if (opts::Output == opts::LLVM) { + opts::Addrsig = true; + opts::PrintStackSizes = true; + } + } + + if (opts::Headers) { + opts::FileHeaders = true; + opts::XCOFFAuxiliaryHeader = true; + opts::ProgramHeaders = true; + opts::SectionHeaders = true; + } + + std::unique_ptr<ScopedPrinter> Writer = createWriter(); + + for (const std::string &I : opts::InputFilenames) + dumpInput(I, *Writer.get()); + + if (opts::CodeViewMergedTypes) { + if (opts::CodeViewEnableGHash) + dumpCodeViewMergedTypes(*Writer.get(), CVTypes.GlobalIDTable.records(), + CVTypes.GlobalTypeTable.records()); + else + dumpCodeViewMergedTypes(*Writer.get(), CVTypes.IDTable.records(), + CVTypes.TypeTable.records()); + } + + return 0; +} |