[llvm-readobj][ELF] Teach llvm-readobj to show dynamic relocation in REL format

MIPS 32-bit ABI uses REL relocation record format to save dynamic
relocations. The patch teaches llvm-readobj to show dynamic relocations
in this format.

Differential Revision: http://reviews.llvm.org/D16114

llvm-svn: 258001
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 64059ed..4eac7e4 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -75,6 +75,7 @@
   typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range;
   typedef typename ELFO::Elf_Rel Elf_Rel;
   typedef typename ELFO::Elf_Rela Elf_Rela;
+  typedef typename ELFO::Elf_Rel_Range Elf_Rel_Range;
   typedef typename ELFO::Elf_Rela_Range Elf_Rela_Range;
   typedef typename ELFO::Elf_Phdr Elf_Phdr;
   typedef typename ELFO::Elf_Half Elf_Half;
@@ -104,12 +105,16 @@
   void printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab,
                    StringRef StrTable, bool IsDynamic);
 
+  void printDynamicRelocation(Elf_Rela Rel);
   void printRelocations(const Elf_Shdr *Sec);
   void printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab);
   void printValue(uint64_t Type, uint64_t Value);
 
-  const Elf_Rela *dyn_rela_begin() const;
-  const Elf_Rela *dyn_rela_end() const;
+  template <typename RELA>
+  static const RELA *dyn_rela_begin(const DynRegionInfo &region);
+  template <typename RELA>
+  static const RELA *dyn_rela_end(const DynRegionInfo &region);
+  Elf_Rel_Range dyn_rels() const;
   Elf_Rela_Range dyn_relas() const;
   StringRef getDynamicString(uint64_t Offset) const;
   const Elf_Dyn *dynamic_table_begin() const {
@@ -129,6 +134,7 @@
   void LoadVersionDefs(const Elf_Shdr *sec) const;
 
   const ELFO *Obj;
+  DynRegionInfo DynRelRegion;
   DynRegionInfo DynRelaRegion;
   const Elf_Phdr *DynamicProgHeader = nullptr;
   StringRef DynamicStringTable;
@@ -944,6 +950,15 @@
       GnuHashTable =
           reinterpret_cast<const Elf_GnuHash *>(toMappedAddr(Dyn.getPtr()));
       break;
+    case ELF::DT_REL:
+      DynRelRegion.Addr = toMappedAddr(Dyn.getPtr());
+      break;
+    case ELF::DT_RELSZ:
+      DynRelRegion.Size = Dyn.getVal();
+      break;
+    case ELF::DT_RELENT:
+      DynRelRegion.EntSize = Dyn.getVal();
+      break;
     case ELF::DT_RELA:
       DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr());
       break;
@@ -1011,25 +1026,32 @@
 }
 
 template <typename ELFT>
-const typename ELFDumper<ELFT>::Elf_Rela *
-ELFDumper<ELFT>::dyn_rela_begin() const {
-  if (DynRelaRegion.Size && DynRelaRegion.EntSize != sizeof(Elf_Rela))
+template <typename RELA>
+const RELA *ELFDumper<ELFT>::dyn_rela_begin(const DynRegionInfo &Region) {
+  if (Region.Size && Region.EntSize != sizeof(RELA))
     report_fatal_error("Invalid relocation entry size");
-  return reinterpret_cast<const Elf_Rela *>(DynRelaRegion.Addr);
+  return reinterpret_cast<const RELA *>(Region.Addr);
 }
 
 template <typename ELFT>
-const typename ELFDumper<ELFT>::Elf_Rela *
-ELFDumper<ELFT>::dyn_rela_end() const {
-  uint64_t Size = DynRelaRegion.Size;
-  if (Size % sizeof(Elf_Rela))
+template <typename RELA>
+const RELA *ELFDumper<ELFT>::dyn_rela_end(const DynRegionInfo &Region) {
+  uint64_t Size = Region.Size;
+  if (Size % sizeof(RELA))
     report_fatal_error("Invalid relocation table size");
-  return dyn_rela_begin() + Size / sizeof(Elf_Rela);
+  return dyn_rela_begin<RELA>(Region) + Size / sizeof(RELA);
+}
+
+template <typename ELFT>
+typename ELFDumper<ELFT>::Elf_Rel_Range ELFDumper<ELFT>::dyn_rels() const {
+  return make_range(dyn_rela_begin<Elf_Rel>(DynRelRegion),
+                    dyn_rela_end<Elf_Rel>(DynRelRegion));
 }
 
 template <typename ELFT>
 typename ELFDumper<ELFT>::Elf_Rela_Range ELFDumper<ELFT>::dyn_relas() const {
-  return make_range(dyn_rela_begin(), dyn_rela_end());
+  return make_range(dyn_rela_begin<Elf_Rela>(DynRelaRegion),
+                    dyn_rela_end<Elf_Rela>(DynRelaRegion));
 }
 
 template<class ELFT>
@@ -1158,31 +1180,22 @@
   }
 }
 
-template<class ELFT>
-void ELFDumper<ELFT>::printDynamicRelocations() {
+template <class ELFT> void ELFDumper<ELFT>::printDynamicRelocations() {
+  if (DynRelRegion.Size && DynRelaRegion.Size)
+    report_fatal_error("There are both REL and RELA dynamic relocations");
   W.startLine() << "Dynamic Relocations {\n";
   W.indent();
-  for (const Elf_Rela &Rel : dyn_relas()) {
-    SmallString<32> RelocName;
-    Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
-    StringRef SymbolName;
-    uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL());
-    const Elf_Sym *Sym = DynSymStart + SymIndex;
-    SymbolName = errorOrDefault(Sym->getName(DynamicStringTable));
-    if (opts::ExpandRelocs) {
-      DictScope Group(W, "Relocation");
-      W.printHex("Offset", Rel.r_offset);
-      W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL()));
-      W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
-      W.printHex("Addend", Rel.r_addend);
+  if (DynRelaRegion.Size > 0)
+    for (const Elf_Rela &Rela : dyn_relas())
+      printDynamicRelocation(Rela);
+  else
+    for (const Elf_Rel &Rel : dyn_rels()) {
+      Elf_Rela Rela;
+      Rela.r_offset = Rel.r_offset;
+      Rela.r_info = Rel.r_info;
+      Rela.r_addend = 0;
+      printDynamicRelocation(Rela);
     }
-    else {
-      raw_ostream& OS = W.startLine();
-      OS << W.hex(Rel.r_offset) << " " << RelocName << " "
-         << (SymbolName.size() > 0 ? SymbolName : "-") << " "
-         << W.hex(Rel.r_addend) << "\n";
-    }
-  }
   W.unindent();
   W.startLine() << "}\n";
 }
@@ -1243,6 +1256,28 @@
   }
 }
 
+template <class ELFT>
+void ELFDumper<ELFT>::printDynamicRelocation(Elf_Rela Rel) {
+  SmallString<32> RelocName;
+  Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
+  StringRef SymbolName;
+  uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL());
+  const Elf_Sym *Sym = DynSymStart + SymIndex;
+  SymbolName = errorOrDefault(Sym->getName(DynamicStringTable));
+  if (opts::ExpandRelocs) {
+    DictScope Group(W, "Relocation");
+    W.printHex("Offset", Rel.r_offset);
+    W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL()));
+    W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
+    W.printHex("Addend", Rel.r_addend);
+  } else {
+    raw_ostream &OS = W.startLine();
+    OS << W.hex(Rel.r_offset) << " " << RelocName << " "
+       << (SymbolName.size() > 0 ? SymbolName : "-") << " "
+       << W.hex(Rel.r_addend) << "\n";
+  }
+}
+
 template<class ELFT>
 void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) {
   const Elf_Shdr *Symtab = (IsDynamic) ? DotDynSymSec : DotSymtabSec;