[llvm-readobj] Add ELF .dynamic table dumping.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@175592 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/llvm-readobj/ELF.cpp b/tools/llvm-readobj/ELF.cpp
new file mode 100644
index 0000000..07f15b3
--- /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