From 6a8746b7e6a854f248b041cac527d6127c6cdf8c Mon Sep 17 00:00:00 2001 From: "Michael J. Spencer" Date: Wed, 20 Feb 2013 02:37:12 +0000 Subject: [PATCH] [llvm-readobj] Add ELF .dynamic table dumping. llvm-svn: 175592 --- llvm/include/llvm/Object/ELF.h | 49 +++++-- llvm/test/Object/readobj-shared-object.test | 13 ++ llvm/tools/llvm-readobj/CMakeLists.txt | 1 + llvm/tools/llvm-readobj/ELF.cpp | 196 ++++++++++++++++++++++++++++ llvm/tools/llvm-readobj/llvm-readobj.cpp | 9 ++ llvm/tools/llvm-readobj/llvm-readobj.h | 22 ++++ 6 files changed, 281 insertions(+), 9 deletions(-) create mode 100644 llvm/tools/llvm-readobj/ELF.cpp create mode 100644 llvm/tools/llvm-readobj/llvm-readobj.h diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h index bd3bbe1..36e35f5 100644 --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -471,9 +471,9 @@ public: template class ELFEntityIterator { public: - typedef void difference_type; + typedef ptrdiff_t difference_type; typedef EntT value_type; - typedef std::forward_iterator_tag iterator_category; + typedef std::random_access_iterator_tag iterator_category; typedef value_type &reference; typedef value_type *pointer; @@ -513,10 +513,22 @@ public: return Tmp; } + ELFEntityIterator &operator =(const ELFEntityIterator &Other) { + EntitySize = Other.EntitySize; + Current = Other.Current; + return *this; + } + + difference_type operator -(const ELFEntityIterator &Other) const { + assert(EntitySize == Other.EntitySize && + "Subtracting iterators of different EntitiySize!"); + return (Current - Other.Current) / EntitySize; + } + const char *get() const { return Current; } private: - const uint64_t EntitySize; + uint64_t EntitySize; const char *Current; }; @@ -605,6 +617,7 @@ private: return getSection(Rel.w.b); } +public: bool isRelocationHasAddend(DataRefImpl Rel) const; template const T *getEntry(uint16_t Section, uint32_t Entry) const; @@ -706,8 +719,14 @@ public: return SymbolTableSections[0]; } + const Elf_Shdr *getDynamicStringTableSectionHeader() const { + return dot_dynstr_sec; + } + Elf_Dyn_iterator begin_dynamic_table() const; - Elf_Dyn_iterator end_dynamic_table() const; + /// \param NULLEnd use one past the first DT_NULL entry as the end instead of + /// the section size. + Elf_Dyn_iterator end_dynamic_table(bool NULLEnd = false) const; Elf_Sym_iterator begin_elf_dynamic_symbols() const { const Elf_Shdr *DynSymtab = SymbolTableSections[0]; @@ -2276,11 +2295,23 @@ ELFObjectFile::begin_dynamic_table() const { template typename ELFObjectFile::Elf_Dyn_iterator -ELFObjectFile::end_dynamic_table() const { - if (dot_dynamic_sec) - return Elf_Dyn_iterator(dot_dynamic_sec->sh_entsize, - (const char *)base() + dot_dynamic_sec->sh_offset + - dot_dynamic_sec->sh_size); +ELFObjectFile::end_dynamic_table(bool NULLEnd) const { + if (dot_dynamic_sec) { + Elf_Dyn_iterator Ret(dot_dynamic_sec->sh_entsize, + (const char *)base() + dot_dynamic_sec->sh_offset + + dot_dynamic_sec->sh_size); + + if (NULLEnd) { + Elf_Dyn_iterator Start = begin_dynamic_table(); + for (; Start != Ret && Start->getTag() != ELF::DT_NULL; ++Start) + ; + // Include the DT_NULL. + if (Start != Ret) + ++Start; + Ret = Start; + } + return Ret; + } return Elf_Dyn_iterator(0, 0); } diff --git a/llvm/test/Object/readobj-shared-object.test b/llvm/test/Object/readobj-shared-object.test index 3065c6f..2c0b54d 100644 --- a/llvm/test/Object/readobj-shared-object.test +++ b/llvm/test/Object/readobj-shared-object.test @@ -71,6 +71,19 @@ ELF: .symtab {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} r ELF: .strtab {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} rodata ELF: Total: 14 +ELF:Dynamic section contains 9 entries +ELF: Tag Type Name/Value +ELF: 00000001 (NEEDED) Shared library: [libc.so.6] +ELF: 00000001 (NEEDED) Shared library: [libm.so.6] +ELF: 0000000e (SONAME) Library soname: [libfoo.so] +ELF: 00000004 (HASH) {{[0-9a-f]+}} +ELF: 00000005 (STRTAB) {{[0-9a-f]+}} +ELF: 00000006 (SYMTAB) {{[0-9a-f]+}} +ELF: 0000000a (STRSZ) {{[0-9]+}} (bytes) +ELF: 0000000b (SYMENT) {{[0-9]+}} (bytes) +ELF: 00000000 (NULL) 0x0 +ELF: Total: 9 + ELF:Libraries needed: ELF: libc.so.6 ELF: libm.so.6 diff --git a/llvm/tools/llvm-readobj/CMakeLists.txt b/llvm/tools/llvm-readobj/CMakeLists.txt index be80469..676c23d 100644 --- a/llvm/tools/llvm-readobj/CMakeLists.txt +++ b/llvm/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/llvm/tools/llvm-readobj/ELF.cpp b/llvm/tools/llvm-readobj/ELF.cpp new file mode 100644 index 0000000..07f15b3 --- /dev/null +++ b/llvm/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 +void printValue(const ELFObjectFile *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 +ErrorOr dumpDynamicTable(const ELFObjectFile *O, raw_ostream &OS) { + typedef ELFObjectFile 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 dumpELFDynamicTable(ObjectFile *O, raw_ostream &OS) { + // Little-endian 32-bit + if (const ELFObjectFile > *ELFObj = + dyn_cast > >(O)) + return dumpDynamicTable(ELFObj, OS); + + // Big-endian 32-bit + if (const ELFObjectFile > *ELFObj = + dyn_cast > >(O)) + return dumpDynamicTable(ELFObj, OS); + + // Little-endian 64-bit + if (const ELFObjectFile > *ELFObj = + dyn_cast > >(O)) + return dumpDynamicTable(ELFObj, OS); + + // Big-endian 64-bit + if (const ELFObjectFile > *ELFObj = + dyn_cast > >(O)) + return dumpDynamicTable(ELFObj, OS); + return error_code(object_error::invalid_file_type); +} +} // end namespace llvm diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp index 0a43775..8f0917f 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -19,6 +19,8 @@ // //===----------------------------------------------------------------------===// +#include "llvm-readobj.h" + #include "llvm/ADT/Triple.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Object/ELF.h" @@ -263,6 +265,13 @@ int main(int argc, char** argv) { dump(obj, &dumpSection, obj->begin_sections(), obj->end_sections(), "Section iteration failed"); + if (obj->isELF()) { + if (ErrorOr 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"); diff --git a/llvm/tools/llvm-readobj/llvm-readobj.h b/llvm/tools/llvm-readobj/llvm-readobj.h new file mode 100644 index 0000000..cf492b2 --- /dev/null +++ b/llvm/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 dumpELFDynamicTable(object::ObjectFile *O, raw_ostream &OS); +} // end namespace llvm + +#endif -- 2.7.4