diff options
author | Alexander Kornienko <alexfh@google.com> | 2013-03-14 09:43:28 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2013-03-14 09:43:28 +0000 |
commit | 868d4470cdfa9472353ea2a49a6c456ddae9c95b (patch) | |
tree | 5a5e56606d41060263048b5a5586b3d2380898ba /tools/llvm-readobj | |
parent | 41d2daa9344a4c4e8bb88dba51cd087c0648b695 (diff) | |
parent | f635ef401786c84df32090251a8cf45981ecca33 (diff) |
Updating branches/google/testing to r176857
git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/google/testing@177020 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/llvm-readobj')
-rw-r--r-- | tools/llvm-readobj/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tools/llvm-readobj/ELF.cpp | 196 | ||||
-rw-r--r-- | tools/llvm-readobj/llvm-readobj.cpp | 231 | ||||
-rw-r--r-- | tools/llvm-readobj/llvm-readobj.h | 22 |
4 files changed, 366 insertions, 84 deletions
diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt index be80469f28..676c23d7ae 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS archive bitreader object) add_llvm_tool(llvm-readobj + ELF.cpp llvm-readobj.cpp ) diff --git a/tools/llvm-readobj/ELF.cpp b/tools/llvm-readobj/ELF.cpp new file mode 100644 index 0000000000..07f15b3a6d --- /dev/null +++ b/tools/llvm-readobj/ELF.cpp @@ -0,0 +1,196 @@ +//===- llvm-readobj/ELF.cpp - ELF Specific Dumper -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" + +#include "llvm/Object/ELF.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Format.h" + +namespace llvm { +using namespace object; +using namespace ELF; + +const char *getTypeString(uint64_t Type) { + switch (Type) { + case DT_BIND_NOW: + return "(BIND_NOW)"; + case DT_DEBUG: + return "(DEBUG)"; + case DT_FINI: + return "(FINI)"; + case DT_FINI_ARRAY: + return "(FINI_ARRAY)"; + case DT_FINI_ARRAYSZ: + return "(FINI_ARRAYSZ)"; + case DT_FLAGS: + return "(FLAGS)"; + case DT_HASH: + return "(HASH)"; + case DT_INIT: + return "(INIT)"; + case DT_INIT_ARRAY: + return "(INIT_ARRAY)"; + case DT_INIT_ARRAYSZ: + return "(INIT_ARRAYSZ)"; + case DT_PREINIT_ARRAY: + return "(PREINIT_ARRAY)"; + case DT_PREINIT_ARRAYSZ: + return "(PREINIT_ARRAYSZ)"; + case DT_JMPREL: + return "(JMPREL)"; + case DT_NEEDED: + return "(NEEDED)"; + case DT_NULL: + return "(NULL)"; + case DT_PLTGOT: + return "(PLTGOT)"; + case DT_PLTREL: + return "(PLTREL)"; + case DT_PLTRELSZ: + return "(PLTRELSZ)"; + case DT_REL: + return "(REL)"; + case DT_RELA: + return "(RELA)"; + case DT_RELENT: + return "(RELENT)"; + case DT_RELSZ: + return "(RELSZ)"; + case DT_RELAENT: + return "(RELAENT)"; + case DT_RELASZ: + return "(RELASZ)"; + case DT_RPATH: + return "(RPATH)"; + case DT_RUNPATH: + return "(RUNPATH)"; + case DT_SONAME: + return "(SONAME)"; + case DT_STRSZ: + return "(STRSZ)"; + case DT_STRTAB: + return "(STRTAB)"; + case DT_SYMBOLIC: + return "(SYMBOLIC)"; + case DT_SYMENT: + return "(SYMENT)"; + case DT_SYMTAB: + return "(SYMTAB)"; + case DT_TEXTREL: + return "(TEXTREL)"; + default: + return "unknown"; + } +} + +template <class ELFT> +void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, uint64_t Value, + bool Is64, raw_ostream &OS) { + switch (Type) { + case DT_PLTREL: + if (Value == DT_REL) { + OS << "REL"; + break; + } else if (Value == DT_RELA) { + OS << "RELA"; + break; + } + // Fallthrough. + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + case DT_DEBUG: + case DT_NULL: + OS << format("0x%" PRIx64, Value); + break; + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_RELSZ: + case DT_RELENT: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_PREINIT_ARRAYSZ: + OS << Value << " (bytes)"; + break; + case DT_NEEDED: + OS << "Shared library: [" + << O->getString(O->getDynamicStringTableSectionHeader(), Value) << "]"; + break; + case DT_SONAME: + OS << "Library soname: [" + << O->getString(O->getDynamicStringTableSectionHeader(), Value) << "]"; + break; + } +} + +template <class ELFT> +ErrorOr<void> dumpDynamicTable(const ELFObjectFile<ELFT> *O, raw_ostream &OS) { + typedef ELFObjectFile<ELFT> ELFO; + typedef typename ELFO::Elf_Dyn_iterator EDI; + EDI Start = O->begin_dynamic_table(), + End = O->end_dynamic_table(true); + + if (Start == End) + return error_code::success(); + + ptrdiff_t Total = std::distance(Start, End); + OS << "Dynamic section contains " << Total << " entries\n"; + + bool Is64 = O->getBytesInAddress() == 8; + + OS << " Tag" << (Is64 ? " " : " ") << "Type" + << " " << "Name/Value\n"; + for (; Start != End; ++Start) { + OS << " " + << format(Is64 ? "0x%016" PRIx64 : "0x%08" PRIx64, Start->getTag()) + << " " << format("%-21s", getTypeString(Start->getTag())); + printValue(O, Start->getTag(), Start->getVal(), Is64, OS); + OS << "\n"; + } + + OS << " Total: " << Total << "\n\n"; + return error_code::success(); +} + +ErrorOr<void> dumpELFDynamicTable(ObjectFile *O, raw_ostream &OS) { + // Little-endian 32-bit + if (const ELFObjectFile<ELFType<support::little, 4, false> > *ELFObj = + dyn_cast<ELFObjectFile<ELFType<support::little, 4, false> > >(O)) + return dumpDynamicTable(ELFObj, OS); + + // Big-endian 32-bit + if (const ELFObjectFile<ELFType<support::big, 4, false> > *ELFObj = + dyn_cast<ELFObjectFile<ELFType<support::big, 4, false> > >(O)) + return dumpDynamicTable(ELFObj, OS); + + // Little-endian 64-bit + if (const ELFObjectFile<ELFType<support::little, 8, true> > *ELFObj = + dyn_cast<ELFObjectFile<ELFType<support::little, 8, true> > >(O)) + return dumpDynamicTable(ELFObj, OS); + + // Big-endian 64-bit + if (const ELFObjectFile<ELFType<support::big, 8, true> > *ELFObj = + dyn_cast<ELFObjectFile<ELFType<support::big, 8, true> > >(O)) + return dumpDynamicTable(ELFObj, OS); + return error_code(object_error::invalid_file_type); +} +} // end namespace llvm diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 40e3b8c933..8f0917fc91 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -7,15 +7,20 @@ // //===----------------------------------------------------------------------===// // -// 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-readobj.h" + #include "llvm/ADT/Triple.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Object/ELF.h" @@ -33,7 +38,7 @@ using namespace llvm::object; static cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input object>"), cl::init("")); -void DumpSymbolHeader() { +static void dumpSymbolHeader() { outs() << format(" %-32s", (const char*)"Name") << format(" %-4s", (const char*)"Type") << format(" %-16s", (const char*)"Address") @@ -43,7 +48,16 @@ void DumpSymbolHeader() { << "\n"; } -const char *GetTypeStr(SymbolRef::Type Type) { +static void dumpSectionHeader() { + outs() << format(" %-24s", (const char*)"Name") + << format(" %-16s", (const char*)"Address") + << format(" %-16s", (const char*)"Size") + << format(" %-8s", (const char*)"Align") + << format(" %-26s", (const char*)"Flags") + << "\n"; +} + +static const char *getTypeStr(SymbolRef::Type Type) { switch (Type) { case SymbolRef::ST_Unknown: return "?"; case SymbolRef::ST_Data: return "DATA"; @@ -55,7 +69,7 @@ const char *GetTypeStr(SymbolRef::Type Type) { return "INV"; } -std::string GetFlagStr(uint32_t Flags) { +static std::string getSymbolFlagStr(uint32_t Flags) { std::string result; if (Flags & SymbolRef::SF_Undefined) result += "undef,"; @@ -79,102 +93,126 @@ std::string GetFlagStr(uint32_t Flags) { return result; } -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; - } - } - - // 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) - << " " << GetFlagStr(Flags) - << "\n"; +static void checkError(error_code ec, const char *msg) { + if (ec) + report_fatal_error(std::string(msg) + ": " + ec.message()); } +static std::string getSectionFlagStr(const SectionRef &Section) { + const struct { + error_code (SectionRef::*MemF)(bool &) const; + const char *FlagStr, *ErrorStr; + } Work[] = + {{ &SectionRef::isText, "text,", "Section.isText() failed" }, + { &SectionRef::isData, "data,", "Section.isData() failed" }, + { &SectionRef::isBSS, "bss,", "Section.isBSS() failed" }, + { &SectionRef::isRequiredForExecution, "required,", + "Section.isRequiredForExecution() failed" }, + { &SectionRef::isVirtual, "virtual,", "Section.isVirtual() failed" }, + { &SectionRef::isZeroInit, "zeroinit,", "Section.isZeroInit() failed" }, + { &SectionRef::isReadOnlyData, "rodata,", + "Section.isReadOnlyData() failed" }}; -// Iterate through the normal symbols in the ObjectFile -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; + std::string result; + for (uint32_t I = 0; I < sizeof(Work)/sizeof(*Work); ++I) { + bool B; + checkError((Section.*Work[I].MemF)(B), Work[I].ErrorStr); + if (B) + result += Work[I].FlagStr; } - outs() << " Total: " << count << "\n\n"; + + // Remove trailing comma + if (result.size() > 0) { + result.erase(result.size() - 1); + } + return result; } -// Iterate through the dynamic symbols in the ObjectFile. -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; +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; + checkError(Sym.getName(Name), "SymbolRef.getName() failed"); + checkError(Sym.getAddress(Address), "SymbolRef.getAddress() failed"); + checkError(Sym.getSize(Size), "SymbolRef.getSize() failed"); + checkError(Sym.getFileOffset(FileOffset), + "SymbolRef.getFileOffset() failed"); + checkError(Sym.getType(Type), "SymbolRef.getType() failed"); + checkError(Sym.getFlags(Flags), "SymbolRef.getFlags() failed"); + 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; + } } - outs() << " Total: " << count << "\n\n"; + + // 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"; +} + +static void dumpStaticSymbol(const SymbolRef &Sym, const ObjectFile *obj) { + return dumpSymbol(Sym, obj, false); } -void DumpLibrary(const LibraryRef &lib) { +static void dumpDynamicSymbol(const SymbolRef &Sym, const ObjectFile *obj) { + return dumpSymbol(Sym, obj, true); +} + +static void dumpSection(const SectionRef &Section, const ObjectFile *obj) { + StringRef Name; + checkError(Section.getName(Name), "SectionRef::getName() failed"); + uint64_t Addr, Size, Align; + checkError(Section.getAddress(Addr), "SectionRef::getAddress() failed"); + checkError(Section.getSize(Size), "SectionRef::getSize() failed"); + checkError(Section.getAlignment(Align), "SectionRef::getAlignment() failed"); + outs() << format(" %-24s", std::string(Name).c_str()) + << format(" %16" PRIx64, Addr) + << format(" %16" PRIx64, Size) + << format(" %8" PRIx64, Align) + << " " << getSectionFlagStr(Section) + << "\n"; +} + +static void dumpLibrary(const LibraryRef &lib, const ObjectFile *obj) { StringRef path; lib.getPath(path); outs() << " " << path << "\n"; } -// Iterate through needed libraries -void DumpLibrariesNeeded(const ObjectFile *obj) { +template<typename Iterator, typename Func> +static void dump(const ObjectFile *obj, Func f, Iterator begin, Iterator end, + const char *errStr) { 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"; + Iterator it = begin, ie = end; while (it != ie) { - DumpLibrary(*it); + f(*it, obj); it.increment(ec); if (ec) - report_fatal_error("Needed libraries iteration failed"); + report_fatal_error(errStr); ++count; } outs() << " Total: " << count << "\n\n"; } -void DumpHeaders(const ObjectFile *obj) { +static void dumpHeaders(const ObjectFile *obj) { outs() << "File Format : " << obj->getFileFormatName() << "\n"; outs() << "Arch : " << Triple::getArchTypeName((llvm::Triple::ArchType)obj->getArch()) @@ -204,15 +242,40 @@ int main(int argc, char** argv) { return 1; } - ObjectFile *obj = ObjectFile::createObjectFile(File.take()); + OwningPtr<ObjectFile> o(ObjectFile::createObjectFile(File.take())); + ObjectFile *obj = o.get(); if (!obj) { errs() << InputFilename << ": Object type not recognized\n"; } - DumpHeaders(obj); - DumpSymbols(obj); - DumpDynamicSymbols(obj); - DumpLibrariesNeeded(obj); + dumpHeaders(obj); + + outs() << "Symbols:\n"; + dumpSymbolHeader(); + dump(obj, dumpStaticSymbol, obj->begin_symbols(), obj->end_symbols(), + "Symbol iteration failed"); + + outs() << "Dynamic Symbols:\n"; + dumpSymbolHeader(); + dump(obj, dumpDynamicSymbol, obj->begin_dynamic_symbols(), + obj->end_dynamic_symbols(), "Symbol iteration failed"); + + outs() << "Sections:\n"; + dumpSectionHeader(); + dump(obj, &dumpSection, obj->begin_sections(), obj->end_sections(), + "Section iteration failed"); + + if (obj->isELF()) { + if (ErrorOr<void> e = dumpELFDynamicTable(obj, outs())) + ; + else + errs() << "InputFilename" << ": " << error_code(e).message() << "\n"; + } + + outs() << "Libraries needed:\n"; + dump(obj, &dumpLibrary, obj->begin_libraries_needed(), + obj->end_libraries_needed(), "Needed libraries iteration failed"); + return 0; } diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h new file mode 100644 index 0000000000..cf492b2a8d --- /dev/null +++ b/tools/llvm-readobj/llvm-readobj.h @@ -0,0 +1,22 @@ +//===- llvm-readobj.h - Dump contents of an Object File -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_READ_OBJ_H +#define LLVM_TOOLS_READ_OBJ_H + +#include "llvm/Support/ErrorOr.h" + +namespace llvm { +namespace object { class ObjectFile; } +class raw_ostream; + +ErrorOr<void> dumpELFDynamicTable(object::ObjectFile *O, raw_ostream &OS); +} // end namespace llvm + +#endif |