X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=tools%2Fllvm-readobj%2Fllvm-readobj.cpp;h=2a75ababb2e8a60f7eff67a8cab760556079cb04;hp=252a37798cff691d6b760b60a4fa75f676551709;hb=3aa1034794ef6a4c9b9196c00debbd318b36fdd3;hpb=1318e14f3e9d786ea108d99ecaee7b5baa9b8fd0;ds=sidebyside diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 252a37798cf..2a75ababb2e 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -7,202 +7,444 @@ // //===----------------------------------------------------------------------===// // -// This program is a utility that works like traditional Unix "readelf", -// except that it can handle any type of object file recognized by lib/Object. +// 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. // -// It makes use of the generic ObjectFile interface. +// 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. // -// Caution: This utility is new, experimental, unsupported, and incomplete. +// Output should be specialized for each format where appropriate. // //===----------------------------------------------------------------------===// -#include "llvm/ADT/Triple.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Object/ELF.h" +#include "llvm-readobj.h" +#include "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.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/Support/Casting.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include +#include using namespace llvm; using namespace llvm::object; -static cl::opt -InputFilename(cl::Positional, cl::desc(""), cl::init("")); - -static const char *getTypeStr(SymbolRef::Type Type) { - switch (Type) { - case SymbolRef::ST_Unknown: return "?"; - case SymbolRef::ST_Data: return "DATA"; - case SymbolRef::ST_Debug: return "DBG"; - case SymbolRef::ST_File: return "FILE"; - case SymbolRef::ST_Function: return "FUNC"; - case SymbolRef::ST_Other: return "-"; - } - return "INV"; +namespace opts { + cl::list InputFilenames(cl::Positional, + cl::desc(""), + cl::ZeroOrMore); + + // -file-headers, -h + cl::opt FileHeaders("file-headers", + cl::desc("Display file headers ")); + cl::alias FileHeadersShort("h", + cl::desc("Alias for --file-headers"), + cl::aliasopt(FileHeaders)); + + // -sections, -s + cl::opt Sections("sections", + cl::desc("Display all sections.")); + cl::alias SectionsShort("s", + cl::desc("Alias for --sections"), + cl::aliasopt(Sections)); + + // -section-relocations, -sr + cl::opt SectionRelocations("section-relocations", + cl::desc("Display relocations for each section shown.")); + cl::alias SectionRelocationsShort("sr", + cl::desc("Alias for --section-relocations"), + cl::aliasopt(SectionRelocations)); + + // -section-symbols, -st + cl::opt SectionSymbols("section-symbols", + cl::desc("Display symbols for each section shown.")); + cl::alias SectionSymbolsShort("st", + cl::desc("Alias for --section-symbols"), + cl::aliasopt(SectionSymbols)); + + // -section-data, -sd + cl::opt SectionData("section-data", + cl::desc("Display section data for each section shown.")); + cl::alias SectionDataShort("sd", + cl::desc("Alias for --section-data"), + cl::aliasopt(SectionData)); + + // -relocations, -r + cl::opt Relocations("relocations", + cl::desc("Display the relocation entries in the file")); + cl::alias RelocationsShort("r", + cl::desc("Alias for --relocations"), + cl::aliasopt(Relocations)); + + // -dyn-relocations + cl::opt DynRelocs("dyn-relocations", + cl::desc("Display the dynamic relocation entries in the file")); + + // -symbols, -t + cl::opt Symbols("symbols", + cl::desc("Display the symbol table")); + cl::alias SymbolsShort("t", + cl::desc("Alias for --symbols"), + cl::aliasopt(Symbols)); + + // -dyn-symbols, -dt + cl::opt DynamicSymbols("dyn-symbols", + cl::desc("Display the dynamic symbol table")); + cl::alias DynamicSymbolsShort("dt", + cl::desc("Alias for --dyn-symbols"), + cl::aliasopt(DynamicSymbols)); + + // -unwind, -u + cl::opt UnwindInfo("unwind", + cl::desc("Display unwind information")); + cl::alias UnwindInfoShort("u", + cl::desc("Alias for --unwind"), + cl::aliasopt(UnwindInfo)); + + // -dynamic-table + cl::opt DynamicTable("dynamic-table", + cl::desc("Display the ELF .dynamic section table")); + + // -needed-libs + cl::opt NeededLibraries("needed-libs", + cl::desc("Display the needed libraries")); + + // -program-headers + cl::opt ProgramHeaders("program-headers", + cl::desc("Display ELF program headers")); + + // -hash-table + cl::opt HashTable("hash-table", + cl::desc("Display ELF hash table")); + + // -gnu-hash-table + cl::opt GnuHashTable("gnu-hash-table", + cl::desc("Display ELF .gnu.hash section")); + + // -expand-relocs + cl::opt ExpandRelocs("expand-relocs", + cl::desc("Expand each shown relocation to multiple lines")); + + // -codeview + cl::opt CodeView("codeview", + cl::desc("Display CodeView debug information")); + + // -codeview-subsection-bytes + cl::opt CodeViewSubsectionBytes( + "codeview-subsection-bytes", + cl::desc("Dump raw contents of codeview debug sections and records")); + + // -arm-attributes, -a + cl::opt ARMAttributes("arm-attributes", + cl::desc("Display the ARM attributes section")); + cl::alias ARMAttributesShort("-a", cl::desc("Alias for --arm-attributes"), + cl::aliasopt(ARMAttributes)); + + // -mips-plt-got + cl::opt + MipsPLTGOT("mips-plt-got", + cl::desc("Display the MIPS GOT and PLT GOT sections")); + + // -mips-abi-flags + cl::opt MipsABIFlags("mips-abi-flags", + cl::desc("Display the MIPS.abiflags section")); + + // -mips-reginfo + cl::opt MipsReginfo("mips-reginfo", + cl::desc("Display the MIPS .reginfo section")); + + // -coff-imports + cl::opt + COFFImports("coff-imports", cl::desc("Display the PE/COFF import table")); + + // -coff-exports + cl::opt + COFFExports("coff-exports", cl::desc("Display the PE/COFF export table")); + + // -coff-directives + cl::opt + COFFDirectives("coff-directives", + cl::desc("Display the PE/COFF .drectve section")); + + // -coff-basereloc + cl::opt + COFFBaseRelocs("coff-basereloc", + cl::desc("Display the PE/COFF .reloc section")); + + // -macho-data-in-code + cl::opt + MachODataInCode("macho-data-in-code", + cl::desc("Display MachO Data in Code command")); + + // -macho-indirect-symbols + cl::opt + MachOIndirectSymbols("macho-indirect-symbols", + cl::desc("Display MachO indirect symbols")); + + // -macho-linker-options + cl::opt + MachOLinkerOptions("macho-linker-options", + cl::desc("Display MachO linker options")); + + // -macho-segment + cl::opt + MachOSegment("macho-segment", + cl::desc("Display MachO Segment command")); + + // -macho-version-min + cl::opt + MachOVersionMin("macho-version-min", + cl::desc("Display MachO version min command")); + + // -macho-dysymtab + cl::opt + MachODysymtab("macho-dysymtab", + cl::desc("Display MachO Dysymtab command")); + + // -stackmap + cl::opt + PrintStackMap("stackmap", + cl::desc("Display contents of stackmap section")); + + // -version-info + cl::opt + VersionInfo("version-info", + cl::desc("Display ELF version sections (if present)")); + cl::alias VersionInfoShort("V", cl::desc("Alias for -version-info"), + cl::aliasopt(VersionInfo)); +} // namespace opts + +namespace llvm { + +LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) { + outs() << "\nError reading file: " << Msg << ".\n"; + outs().flush(); + exit(1); } -static std::string getSymbolFlagStr(uint32_t Flags) { - std::string result; - if (Flags & SymbolRef::SF_Undefined) - result += "undef,"; - if (Flags & SymbolRef::SF_Global) - result += "global,"; - if (Flags & SymbolRef::SF_Weak) - result += "weak,"; - if (Flags & SymbolRef::SF_Absolute) - result += "absolute,"; - if (Flags & SymbolRef::SF_ThreadLocal) - result += "threadlocal,"; - if (Flags & SymbolRef::SF_Common) - result += "common,"; - if (Flags & SymbolRef::SF_FormatSpecific) - result += "formatspecific,"; - - // Remove trailing comma - if (result.size() > 0) { - result.erase(result.size() - 1); - } - return result; +void error(std::error_code EC) { + if (!EC) + return; + + reportError(EC.message()); } -static void -dumpSymbol(const SymbolRef &Sym, const ObjectFile *obj, bool IsDynamic) { - StringRef Name; - SymbolRef::Type Type; - uint32_t Flags; - uint64_t Address; - uint64_t Size; - uint64_t FileOffset; - Sym.getName(Name); - Sym.getAddress(Address); - Sym.getSize(Size); - Sym.getFileOffset(FileOffset); - Sym.getType(Type); - Sym.getFlags(Flags); - std::string FullName = Name; - - // If this is a dynamic symbol from an ELF object, append - // the symbol's version to the name. - if (IsDynamic && obj->isELF()) { - StringRef Version; - bool IsDefault; - GetELFSymbolVersion(obj, Sym, Version, IsDefault); - if (!Version.empty()) { - FullName += (IsDefault ? "@@" : "@"); - FullName += Version; - } - } +bool relocAddressLess(RelocationRef a, RelocationRef b) { + return a.getOffset() < b.getOffset(); +} - // format() can't handle StringRefs - outs() << format(" %-32s", FullName.c_str()) - << format(" %-4s", getTypeStr(Type)) - << format(" %16" PRIx64, Address) - << format(" %16" PRIx64, Size) - << format(" %16" PRIx64, FileOffset) - << " " << getSymbolFlagStr(Flags) - << "\n"; +} // namespace llvm + +static void reportError(StringRef Input, std::error_code EC) { + if (Input == "-") + Input = ""; + + reportError(Twine(Input) + ": " + EC.message()); +} + +static void reportError(StringRef Input, StringRef Message) { + if (Input == "-") + Input = ""; + + reportError(Twine(Input) + ": " + Message); } -// Iterate through the normal symbols in the ObjectFile -static void dumpSymbols(const ObjectFile *obj) { - error_code ec; - uint32_t count = 0; - outs() << "Symbols:\n"; - symbol_iterator it = obj->begin_symbols(); - symbol_iterator ie = obj->end_symbols(); - while (it != ie) { - dumpSymbol(*it, obj, false); - it.increment(ec); - if (ec) - report_fatal_error("Symbol iteration failed"); - ++count; +static bool isMipsArch(unsigned Arch) { + switch (Arch) { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + return true; + default: + return false; } - outs() << " Total: " << count << "\n\n"; } -// Iterate through the dynamic symbols in the ObjectFile. -static void dumpDynamicSymbols(const ObjectFile *obj) { - error_code ec; - uint32_t count = 0; - outs() << "Dynamic Symbols:\n"; - symbol_iterator it = obj->begin_dynamic_symbols(); - symbol_iterator ie = obj->end_dynamic_symbols(); - while (it != ie) { - dumpSymbol(*it, obj, true); - it.increment(ec); - if (ec) - report_fatal_error("Symbol iteration failed"); - ++count; +/// @brief Creates an format-specific object file dumper. +static std::error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer, + std::unique_ptr &Result) { + if (!Obj) + return readobj_error::unsupported_file_format; + + if (Obj->isCOFF()) + return createCOFFDumper(Obj, Writer, Result); + if (Obj->isELF()) + return createELFDumper(Obj, Writer, Result); + if (Obj->isMachO()) + return createMachODumper(Obj, Writer, Result); + + return readobj_error::unsupported_obj_file_format; +} + +/// @brief Dumps the specified object file. +static void dumpObject(const ObjectFile *Obj) { + StreamWriter Writer(outs()); + std::unique_ptr Dumper; + if (std::error_code EC = createDumper(Obj, Writer, Dumper)) + reportError(Obj->getFileName(), EC); + + outs() << '\n'; + outs() << "File: " << Obj->getFileName() << "\n"; + outs() << "Format: " << Obj->getFileFormatName() << "\n"; + outs() << "Arch: " + << Triple::getArchTypeName((llvm::Triple::ArchType)Obj->getArch()) + << "\n"; + outs() << "AddressSize: " << (8*Obj->getBytesInAddress()) << "bit\n"; + Dumper->printLoadName(); + + if (opts::FileHeaders) + Dumper->printFileHeaders(); + if (opts::Sections) + Dumper->printSections(); + if (opts::Relocations) + Dumper->printRelocations(); + if (opts::DynRelocs) + Dumper->printDynamicRelocations(); + if (opts::Symbols) + Dumper->printSymbols(); + if (opts::DynamicSymbols) + Dumper->printDynamicSymbols(); + if (opts::UnwindInfo) + Dumper->printUnwindInfo(); + if (opts::DynamicTable) + Dumper->printDynamicTable(); + if (opts::NeededLibraries) + Dumper->printNeededLibraries(); + if (opts::ProgramHeaders) + Dumper->printProgramHeaders(); + if (opts::HashTable) + Dumper->printHashTable(); + if (opts::GnuHashTable) + Dumper->printGnuHashTable(); + if (opts::VersionInfo) + Dumper->printVersionInfo(); + if (Obj->getArch() == llvm::Triple::arm && Obj->isELF()) + if (opts::ARMAttributes) + Dumper->printAttributes(); + if (isMipsArch(Obj->getArch()) && Obj->isELF()) { + if (opts::MipsPLTGOT) + Dumper->printMipsPLTGOT(); + if (opts::MipsABIFlags) + Dumper->printMipsABIFlags(); + if (opts::MipsReginfo) + Dumper->printMipsReginfo(); } - outs() << " Total: " << count << "\n\n"; + if (Obj->isCOFF()) { + if (opts::COFFImports) + Dumper->printCOFFImports(); + if (opts::COFFExports) + Dumper->printCOFFExports(); + if (opts::COFFDirectives) + Dumper->printCOFFDirectives(); + if (opts::COFFBaseRelocs) + Dumper->printCOFFBaseReloc(); + } + 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::PrintStackMap) + Dumper->printStackMap(); } -static void dumpLibrary(const LibraryRef &lib) { - StringRef path; - lib.getPath(path); - outs() << " " << path << "\n"; +/// @brief Dumps each object file in \a Arc; +static void dumpArchive(const Archive *Arc) { + for (auto &ErrorOrChild : Arc->children()) { + if (std::error_code EC = ErrorOrChild.getError()) + reportError(Arc->getFileName(), EC.message()); + const auto &Child = *ErrorOrChild; + ErrorOr> ChildOrErr = Child.getAsBinary(); + if (std::error_code EC = ChildOrErr.getError()) { + // Ignore non-object files. + if (EC != object_error::invalid_file_type) + reportError(Arc->getFileName(), EC.message()); + continue; + } + + if (ObjectFile *Obj = dyn_cast(&*ChildOrErr.get())) + dumpObject(Obj); + else + reportError(Arc->getFileName(), readobj_error::unrecognized_file_format); + } } -// Iterate through needed libraries -static void dumpLibrariesNeeded(const ObjectFile *obj) { - error_code ec; - uint32_t count = 0; - library_iterator it = obj->begin_libraries_needed(); - library_iterator ie = obj->end_libraries_needed(); - outs() << "Libraries needed:\n"; - while (it != ie) { - dumpLibrary(*it); - it.increment(ec); - if (ec) - report_fatal_error("Needed libraries iteration failed"); - ++count; +/// @brief Dumps each object file in \a MachO Universal Binary; +static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary) { + for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) { + ErrorOr> ObjOrErr = Obj.getAsObjectFile(); + if (ObjOrErr) + dumpObject(&*ObjOrErr.get()); + else if (ErrorOr> AOrErr = Obj.getAsArchive()) + dumpArchive(&*AOrErr.get()); + else + reportError(UBinary->getFileName(), ObjOrErr.getError().message()); } - outs() << " Total: " << count << "\n\n"; } -static void dumpHeaders(const ObjectFile *obj) { - outs() << "File Format : " << obj->getFileFormatName() << "\n"; - outs() << "Arch : " - << Triple::getArchTypeName((llvm::Triple::ArchType)obj->getArch()) - << "\n"; - outs() << "Address Size: " << (8*obj->getBytesInAddress()) << " bits\n"; - outs() << "Load Name : " << obj->getLoadName() << "\n"; - outs() << "\n"; +/// @brief Opens \a File and dumps it. +static void dumpInput(StringRef File) { + + // Attempt to open the binary. + ErrorOr> BinaryOrErr = createBinary(File); + if (std::error_code EC = BinaryOrErr.getError()) + reportError(File, EC); + Binary &Binary = *BinaryOrErr.get().getBinary(); + + if (Archive *Arc = dyn_cast(&Binary)) + dumpArchive(Arc); + else if (MachOUniversalBinary *UBinary = + dyn_cast(&Binary)) + dumpMachOUniversalBinary(UBinary); + else if (ObjectFile *Obj = dyn_cast(&Binary)) + dumpObject(Obj); + else if (COFFImportFile *Import = dyn_cast(&Binary)) + dumpCOFFImportFile(Import); + else + reportError(File, readobj_error::unrecognized_file_format); } -int main(int argc, char** argv) { - error_code ec; +int main(int argc, const char *argv[]) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; - cl::ParseCommandLineOptions(argc, argv, - "LLVM Object Reader\n"); + // Register the target printer for --version. + cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); - if (InputFilename.empty()) { - errs() << "Please specify an input filename\n"; - return 1; - } + cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n"); - // Open the object file - OwningPtr File; - if (MemoryBuffer::getFile(InputFilename, File)) { - errs() << InputFilename << ": Open failed\n"; - return 1; - } + // Default to stdin if no filename is specified. + if (opts::InputFilenames.size() == 0) + opts::InputFilenames.push_back("-"); - ObjectFile *obj = ObjectFile::createObjectFile(File.take()); - if (!obj) { - errs() << InputFilename << ": Object type not recognized\n"; - } + std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), + dumpInput); - dumpHeaders(obj); - dumpSymbols(obj); - dumpDynamicSymbols(obj); - dumpLibrariesNeeded(obj); return 0; } -