Remove extra forward declarations and scrub includes for all in tree InstPrinters...
[oota-llvm.git] / tools / llvm-readobj / ELFDumper.cpp
index 9931163440347b777fcd924ec3a3cadcd5532c9d..02397f382848e4b5c973df4fd09aa481927d1123 100644 (file)
@@ -56,7 +56,9 @@ public:
   void printNeededLibraries() override;
   void printProgramHeaders() override;
   void printHashTable() override;
+  void printGnuHashTable() override;
   void printLoadName() override;
+  void printVersionInfo() override;
 
   void printAttributes() override;
   void printMipsPLTGOT() override;
@@ -75,7 +77,9 @@ private:
   typedef typename ELFO::Elf_Rela Elf_Rela;
   typedef typename ELFO::Elf_Rela_Range Elf_Rela_Range;
   typedef typename ELFO::Elf_Phdr Elf_Phdr;
+  typedef typename ELFO::Elf_Half Elf_Half;
   typedef typename ELFO::Elf_Hash Elf_Hash;
+  typedef typename ELFO::Elf_GnuHash Elf_GnuHash;
   typedef typename ELFO::Elf_Ehdr Elf_Ehdr;
   typedef typename ELFO::Elf_Word Elf_Word;
   typedef typename ELFO::uintX_t uintX_t;
@@ -83,6 +87,7 @@ private:
   typedef typename ELFO::Elf_Verneed Elf_Verneed;
   typedef typename ELFO::Elf_Vernaux Elf_Vernaux;
   typedef typename ELFO::Elf_Verdef Elf_Verdef;
+  typedef typename ELFO::Elf_Verdaux Elf_Verdaux;
 
   /// \brief Represents a region described by entries in the .dynamic table.
   struct DynRegionInfo {
@@ -117,12 +122,6 @@ private:
     error(Ret.getError());
     return *Ret;
   }
-  Elf_Dyn_Range dynamic_table() const {
-    ErrorOr<Elf_Dyn_Range> Ret = Obj->dynamic_table(DynamicProgHeader);
-    error(Ret.getError());
-    return *Ret;
-  }
-
   StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb,
                              bool &IsDefault);
   void LoadVersionMap();
@@ -136,6 +135,7 @@ private:
   const Elf_Sym *DynSymStart = nullptr;
   StringRef SOName;
   const Elf_Hash *HashTable = nullptr;
+  const Elf_GnuHash *GnuHashTable = nullptr;
   const Elf_Shdr *DotDynSymSec = nullptr;
   const Elf_Shdr *DotSymtabSec = nullptr;
   ArrayRef<Elf_Word> ShndxTable;
@@ -168,6 +168,12 @@ private:
   mutable SmallVector<VersionMapEntry, 16> VersionMap;
 
 public:
+  Elf_Dyn_Range dynamic_table() const {
+    ErrorOr<Elf_Dyn_Range> Ret = Obj->dynamic_table(DynamicProgHeader);
+    error(Ret.getError());
+    return *Ret;
+  }
+
   std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable,
                                 bool IsDynamic);
   const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; }
@@ -299,6 +305,95 @@ template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() {
     LoadVersionNeeds(dot_gnu_version_r_sec);
 }
 
+
+template <typename ELFO, class ELFT>
+static void printVersionSymbolSection(ELFDumper<ELFT> *Dumper,
+                                      const ELFO *Obj,
+                                      const typename ELFO::Elf_Shdr *Sec,
+                                      StreamWriter &W) {
+  DictScope SS(W, "Version symbols");
+  if (!Sec)
+    return;
+  StringRef Name = errorOrDefault(Obj->getSectionName(Sec));
+  W.printNumber("Section Name", Name, Sec->sh_name);
+  W.printHex("Address", Sec->sh_addr);
+  W.printHex("Offset", Sec->sh_offset);
+  W.printNumber("Link", Sec->sh_link);
+
+  const typename ELFO::Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec();
+  const uint8_t *P = (const uint8_t *)Obj->base() + Sec->sh_offset;
+  ErrorOr<StringRef> StrTableOrErr =
+      Obj->getStringTableForSymtab(*DynSymSec);
+  error(StrTableOrErr.getError());
+
+  // Same number of entries in the dynamic symbol table (DT_SYMTAB).
+  ListScope Syms(W, "Symbols");
+  for (const typename ELFO::Elf_Sym &Sym : Obj->symbols(DynSymSec)) {
+    DictScope S(W, "Symbol");
+    std::string FullSymbolName =
+        Dumper->getFullSymbolName(&Sym, *StrTableOrErr, true /* IsDynamic */);
+    W.printNumber("Version", *P);
+    W.printString("Name", FullSymbolName);
+    P += sizeof(typename ELFO::Elf_Half);
+  }
+}
+
+template <typename ELFO, class ELFT>
+static void printVersionDefinitionSection(ELFDumper<ELFT> *Dumper,
+                                          const ELFO *Obj,
+                                          const typename ELFO::Elf_Shdr *Sec,
+                                          StreamWriter &W) {
+  DictScope SD(W, "Version definition");
+  if (!Sec)
+    return;
+  StringRef Name = errorOrDefault(Obj->getSectionName(Sec));
+  W.printNumber("Section Name", Name, Sec->sh_name);
+  W.printHex("Address", Sec->sh_addr);
+  W.printHex("Offset", Sec->sh_offset);
+  W.printNumber("Link", Sec->sh_link);
+
+  unsigned verdef_entries = 0;
+  // The number of entries in the section SHT_GNU_verdef
+  // is determined by DT_VERDEFNUM tag.
+  for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) {
+    if (Dyn.d_tag == DT_VERDEFNUM)
+      verdef_entries = Dyn.d_un.d_val;
+  }
+  const uint8_t *SecStartAddress =
+      (const uint8_t *)Obj->base() + Sec->sh_offset;
+  const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size;
+  const uint8_t *P = SecStartAddress;
+  ErrorOr<const typename ELFO::Elf_Shdr *> StrTabOrErr =
+      Obj->getSection(Sec->sh_link);
+  error(StrTabOrErr.getError());
+
+  ListScope Entries(W, "Entries");
+  for (unsigned i = 0; i < verdef_entries; ++i) {
+    if (P + sizeof(typename ELFO::Elf_Verdef) > SecEndAddress)
+      report_fatal_error("invalid offset in the section");
+    auto *VD = reinterpret_cast<const typename ELFO::Elf_Verdef *>(P);
+    DictScope Entry(W, "Entry");
+    W.printHex("Offset", (uintptr_t)P - (uintptr_t)SecStartAddress);
+    W.printNumber("Rev", VD->vd_version);
+    // FIXME: print something more readable.
+    W.printNumber("Flags", VD->vd_flags);
+    W.printNumber("Index", VD->vd_ndx);
+    W.printNumber("Cnt", VD->vd_cnt);
+    W.printString("Name", StringRef((const char *)(Obj->base() +
+                                                   (*StrTabOrErr)->sh_offset +
+                                                   VD->getAux()->vda_name)));
+    P += VD->vd_next;
+  }
+}
+
+template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() {
+  // Dump version symbol section.
+  printVersionSymbolSection(this, Obj, dot_gnu_version_sec, W);
+
+  // Dump version definition section.
+  printVersionDefinitionSection(this, Obj, dot_gnu_version_d_sec, W);
+}
+
 template <typename ELFT>
 StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab,
                                             const Elf_Sym *symb,
@@ -338,17 +433,11 @@ StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab,
   if (entry.isVerdef()) {
     // The first Verdaux entry holds the name.
     name_offset = entry.getVerdef()->getAux()->vda_name;
-  } else {
-    name_offset = entry.getVernaux()->vna_name;
-  }
-
-  // Set IsDefault
-  if (entry.isVerdef()) {
     IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN);
   } else {
+    name_offset = entry.getVernaux()->vna_name;
     IsDefault = false;
   }
-
   if (name_offset >= StrTab.size())
     reportError("Invalid string offset");
   return StringRef(StrTab.data() + name_offset);
@@ -850,6 +939,10 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer)
       HashTable =
           reinterpret_cast<const Elf_Hash *>(toMappedAddr(Dyn.getPtr()));
       break;
+    case ELF::DT_GNU_HASH:
+      GnuHashTable =
+          reinterpret_cast<const Elf_GnuHash *>(toMappedAddr(Dyn.getPtr()));
+      break;
     case ELF::DT_RELA:
       DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr());
       break;
@@ -1237,6 +1330,8 @@ static const char *getTypeString(uint64_t Type) {
   LLVM_READOBJ_TYPE_CASE(SYMENT);
   LLVM_READOBJ_TYPE_CASE(SYMTAB);
   LLVM_READOBJ_TYPE_CASE(TEXTREL);
+  LLVM_READOBJ_TYPE_CASE(VERDEF);
+  LLVM_READOBJ_TYPE_CASE(VERDEFNUM);
   LLVM_READOBJ_TYPE_CASE(VERNEED);
   LLVM_READOBJ_TYPE_CASE(VERNEEDNUM);
   LLVM_READOBJ_TYPE_CASE(VERSYM);
@@ -1371,6 +1466,7 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
   case DT_FINI_ARRAY:
   case DT_PREINIT_ARRAY:
   case DT_DEBUG:
+  case DT_VERDEF:
   case DT_VERNEED:
   case DT_VERSYM:
   case DT_GNU_HASH:
@@ -1384,6 +1480,7 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
     OS << format("0x%" PRIX64, Value);
     break;
   case DT_RELCOUNT:
+  case DT_VERDEFNUM:
   case DT_VERNEEDNUM:
   case DT_MIPS_RLD_VERSION:
   case DT_MIPS_LOCAL_GOTNO:
@@ -1474,12 +1571,11 @@ void ELFDumper<ELFT>::printDynamicTable() {
      << "                 " << "Name/Value\n";
   while (I != E) {
     const Elf_Dyn &Entry = *I;
+    uintX_t Tag = Entry.getTag();
     ++I;
-    W.startLine()
-       << "  "
-       << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Entry.getTag())
-       << " " << format("%-21s", getTypeString(Entry.getTag()));
-    printValue(Entry.getTag(), Entry.getVal());
+    W.startLine() << "  " << format_hex(Tag, Is64 ? 18 : 10, true) << " "
+                  << format("%-21s", getTypeString(Tag));
+    printValue(Tag, Entry.getVal());
     OS << "\n";
   }
 
@@ -1534,6 +1630,23 @@ void ELFDumper<ELFT>::printHashTable() {
   W.printList("Chains", HashTable->chains());
 }
 
+template <typename ELFT>
+void ELFDumper<ELFT>::printGnuHashTable() {
+  DictScope D(W, "GnuHashTable");
+  if (!GnuHashTable)
+    return;
+  W.printNumber("Num Buckets", GnuHashTable->nbuckets);
+  W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx);
+  W.printNumber("Num Mask Words", GnuHashTable->maskwords);
+  W.printNumber("Shift Count", GnuHashTable->shift2);
+  W.printHexList("Bloom Filter", GnuHashTable->filter());
+  W.printList("Buckets", GnuHashTable->buckets());
+  if (!DotDynSymSec)
+    reportError("No dynamic symbol section");
+  W.printHexList("Values",
+                 GnuHashTable->values(DotDynSymSec->getEntityCount()));
+}
+
 template <typename ELFT> void ELFDumper<ELFT>::printLoadName() {
   outs() << "LoadName: " << SOName << '\n';
 }