[llvm-readobj] Add ELF .dynamic table dumping.
authorMichael J. Spencer <bigcheesegs@gmail.com>
Wed, 20 Feb 2013 02:37:12 +0000 (02:37 +0000)
committerMichael J. Spencer <bigcheesegs@gmail.com>
Wed, 20 Feb 2013 02:37:12 +0000 (02:37 +0000)
llvm-svn: 175592

llvm/include/llvm/Object/ELF.h
llvm/test/Object/readobj-shared-object.test
llvm/tools/llvm-readobj/CMakeLists.txt
llvm/tools/llvm-readobj/ELF.cpp [new file with mode: 0644]
llvm/tools/llvm-readobj/llvm-readobj.cpp
llvm/tools/llvm-readobj/llvm-readobj.h [new file with mode: 0644]

index bd3bbe1..36e35f5 100644 (file)
@@ -471,9 +471,9 @@ public:
   template<class EntT>
   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<typename T>
   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<ELFT>::begin_dynamic_table() const {
 
 template<class ELFT>
 typename ELFObjectFile<ELFT>::Elf_Dyn_iterator
-ELFObjectFile<ELFT>::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<ELFT>::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);
 }
 
index 3065c6f..2c0b54d 100644 (file)
@@ -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
index be80469..676c23d 100644 (file)
@@ -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 (file)
index 0000000..07f15b3
--- /dev/null
@@ -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
index 0a43775..8f0917f 100644 (file)
@@ -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<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");
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.h b/llvm/tools/llvm-readobj/llvm-readobj.h
new file mode 100644 (file)
index 0000000..cf492b2
--- /dev/null
@@ -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