[Object][ELF] Add support for dumping dynamic relocations when sections are stripped.
[oota-llvm.git] / include / llvm / Object / ELF.h
index 7c10bbf6e5ab288370196c2b71a082454d6db00b..8b28567f72ce4102a0aa21a11a6b895ce8a6b792 100644 (file)
@@ -94,18 +94,24 @@ public:
       return *this;
     }
 
+    ELFEntityIterator &operator+(difference_type n) {
+      assert(Current && "Attempted to increment an invalid iterator!");
+      Current += (n * EntitySize);
+      return *this;
+    }
+
+    ELFEntityIterator &operator-(difference_type n) {
+      assert(Current && "Attempted to subtract an invalid iterator!");
+      Current -= (n * EntitySize);
+      return *this;
+    }
+
     ELFEntityIterator operator ++(int) {
       ELFEntityIterator Tmp = *this;
       ++*this;
       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 EntitySize!");
@@ -203,12 +209,6 @@ public:
       return *this;
     }
 
-    Elf_Sym_Iter &operator=(const Elf_Sym_Iter &Other) {
-      EntitySize = Other.EntitySize;
-      Current = Other.Current;
-      return *this;
-    }
-
     difference_type operator-(const Elf_Sym_Iter &Other) const {
       assert(EntitySize == Other.EntitySize &&
              "Subtracting iterators of different EntitySize!");
@@ -265,6 +265,7 @@ private:
   DynRegionInfo DynHashRegion;
   DynRegionInfo DynStrRegion;
   DynRegionInfo DynSymRegion;
+  DynRegionInfo DynRelaRegion;
 
   // Pointer to SONAME entry in dynamic string table
   // This is set the first time getLoadName is called.
@@ -318,7 +319,7 @@ public:
   std::pair<const Elf_Shdr *, const Elf_Sym *>
   getRelocationSymbol(const Elf_Shdr *RelSec, const RelT *Rel) const;
 
-  ELFFile(StringRef Object, std::error_code &ec);
+  ELFFile(StringRef Object, std::error_code &EC);
 
   bool isMipsELF64() const {
     return Header->e_machine == ELF::EM_MIPS &&
@@ -363,6 +364,21 @@ public:
     return Elf_Sym_Iter(0, nullptr, true);
   }
 
+  Elf_Rela_Iter begin_dyn_rela() const {
+    if (DynRelaRegion.Addr)
+      return Elf_Rela_Iter(DynRelaRegion.EntSize,
+        (const char *)DynRelaRegion.Addr);
+    return Elf_Rela_Iter(0, nullptr);
+  }
+
+  Elf_Rela_Iter end_dyn_rela() const {
+    if (DynRelaRegion.Addr)
+      return Elf_Rela_Iter(
+        DynRelaRegion.EntSize,
+        (const char *)DynRelaRegion.Addr + DynRelaRegion.Size);
+    return Elf_Rela_Iter(0, nullptr);
+  }
+
   Elf_Rela_Iter begin_rela(const Elf_Shdr *sec) const {
     return Elf_Rela_Iter(sec->sh_entsize,
                          (const char *)(base() + sec->sh_offset));
@@ -401,7 +417,7 @@ public:
 
   uint64_t getNumSections() const;
   uintX_t getStringTableIndex() const;
-  ELF::Elf64_Word getSymbolTableIndex(const Elf_Sym *symb) const;
+  ELF::Elf64_Word getExtendedSymbolTableIndex(const Elf_Sym *symb) const;
   const Elf_Ehdr *getHeader() const { return Header; }
   const Elf_Shdr *getSection(const Elf_Sym *symb) const;
   const Elf_Shdr *getSection(uint32_t Index) const;
@@ -423,12 +439,10 @@ public:
   StringRef getLoadName() const;
 };
 
-// Use an alignment of 2 for the typedefs since that is the worst case for
-// ELF files in archives.
-typedef ELFFile<ELFType<support::little, 2, false> > ELF32LEFile;
-typedef ELFFile<ELFType<support::little, 2, true> > ELF64LEFile;
-typedef ELFFile<ELFType<support::big, 2, false> > ELF32BEFile;
-typedef ELFFile<ELFType<support::big, 2, true> > ELF64BEFile;
+typedef ELFFile<ELFType<support::little, false>> ELF32LEFile;
+typedef ELFFile<ELFType<support::little, true>> ELF64LEFile;
+typedef ELFFile<ELFType<support::big, false>> ELF32BEFile;
+typedef ELFFile<ELFType<support::big, true>> ELF64BEFile;
 
 // Iterate through the version definitions, and place each Elf_Verdef
 // in the VersionMap according to its index.
@@ -512,10 +526,10 @@ void ELFFile<ELFT>::LoadVersionMap() const {
 }
 
 template <class ELFT>
-ELF::Elf64_Word ELFFile<ELFT>::getSymbolTableIndex(const Elf_Sym *symb) const {
-  if (symb->st_shndx == ELF::SHN_XINDEX)
-    return ExtendedSymbolTable.lookup(symb);
-  return symb->st_shndx;
+ELF::Elf64_Word
+ELFFile<ELFT>::getExtendedSymbolTableIndex(const Elf_Sym *symb) const {
+  assert(symb->st_shndx == ELF::SHN_XINDEX);
+  return ExtendedSymbolTable.lookup(symb);
 }
 
 template <class ELFT>
@@ -622,7 +636,7 @@ typename ELFFile<ELFT>::uintX_t ELFFile<ELFT>::getStringTableIndex() const {
 }
 
 template <class ELFT>
-ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &ec)
+ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC)
     : Buf(Object), SectionHeaderTable(nullptr), dot_shstrtab_sec(nullptr),
       dot_strtab_sec(nullptr), dot_symtab_sec(nullptr),
       SymbolTableSectionHeaderIndex(nullptr), dot_gnu_version_sec(nullptr),
@@ -630,9 +644,11 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &ec)
       dt_soname(nullptr) {
   const uint64_t FileSize = Buf.size();
 
-  if (sizeof(Elf_Ehdr) > FileSize)
-    // FIXME: Proper error handling.
-    report_fatal_error("File too short!");
+  if (sizeof(Elf_Ehdr) > FileSize) {
+    // File too short!
+    EC = object_error::parse_failed;
+    return;
+  }
 
   Header = reinterpret_cast<const Elf_Ehdr *>(base());
 
@@ -641,40 +657,50 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &ec)
 
   const uint64_t SectionTableOffset = Header->e_shoff;
 
-  if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize)
-    // FIXME: Proper error handling.
-    report_fatal_error("Section header table goes past end of file!");
+  if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize) {
+    // Section header table goes past end of file!
+    EC = object_error::parse_failed;
+    return;
+  }
 
   // The getNumSections() call below depends on SectionHeaderTable being set.
   SectionHeaderTable =
     reinterpret_cast<const Elf_Shdr *>(base() + SectionTableOffset);
   const uint64_t SectionTableSize = getNumSections() * Header->e_shentsize;
 
-  if (SectionTableOffset + SectionTableSize > FileSize)
-    // FIXME: Proper error handling.
-    report_fatal_error("Section table goes past end of file!");
+  if (SectionTableOffset + SectionTableSize > FileSize) {
+    // Section table goes past end of file!
+    EC = object_error::parse_failed;
+    return;
+  }
 
   // Scan sections for special sections.
 
   for (const Elf_Shdr &Sec : sections()) {
     switch (Sec.sh_type) {
     case ELF::SHT_SYMTAB_SHNDX:
-      if (SymbolTableSectionHeaderIndex)
-        // FIXME: Proper error handling.
-        report_fatal_error("More than one .symtab_shndx!");
+      if (SymbolTableSectionHeaderIndex) {
+        // More than one .symtab_shndx!
+        EC = object_error::parse_failed;
+        return;
+      }
       SymbolTableSectionHeaderIndex = &Sec;
       break;
     case ELF::SHT_SYMTAB:
-      if (dot_symtab_sec)
-        // FIXME: Proper error handling.
-        report_fatal_error("More than one .symtab!");
+      if (dot_symtab_sec) {
+        // More than one .symtab!
+        EC = object_error::parse_failed;
+        return;
+      }
       dot_symtab_sec = &Sec;
       dot_strtab_sec = getSection(Sec.sh_link);
       break;
     case ELF::SHT_DYNSYM: {
-      if (DynSymRegion.Addr)
-        // FIXME: Proper error handling.
-        report_fatal_error("More than one .dynsym!");
+      if (DynSymRegion.Addr) {
+        // More than one .dynsym!
+        EC = object_error::parse_failed;
+        return;
+      }
       DynSymRegion.Addr = base() + Sec.sh_offset;
       DynSymRegion.Size = Sec.sh_size;
       DynSymRegion.EntSize = Sec.sh_entsize;
@@ -685,29 +711,37 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &ec)
       break;
     }
     case ELF::SHT_DYNAMIC:
-      if (DynamicRegion.Addr)
-        // FIXME: Proper error handling.
-        report_fatal_error("More than one .dynamic!");
+      if (DynamicRegion.Addr) {
+        // More than one .dynamic!
+        EC = object_error::parse_failed;
+        return;
+      }
       DynamicRegion.Addr = base() + Sec.sh_offset;
       DynamicRegion.Size = Sec.sh_size;
       DynamicRegion.EntSize = Sec.sh_entsize;
       break;
     case ELF::SHT_GNU_versym:
-      if (dot_gnu_version_sec != nullptr)
-        // FIXME: Proper error handling.
-        report_fatal_error("More than one .gnu.version section!");
+      if (dot_gnu_version_sec != nullptr) {
+        // More than one .gnu.version section!
+        EC = object_error::parse_failed;
+        return;
+      }
       dot_gnu_version_sec = &Sec;
       break;
     case ELF::SHT_GNU_verdef:
-      if (dot_gnu_version_d_sec != nullptr)
-        // FIXME: Proper error handling.
-        report_fatal_error("More than one .gnu.version_d section!");
+      if (dot_gnu_version_d_sec != nullptr) {
+        // More than one .gnu.version_d section!
+        EC = object_error::parse_failed;
+        return;
+      }
       dot_gnu_version_d_sec = &Sec;
       break;
     case ELF::SHT_GNU_verneed:
-      if (dot_gnu_version_r_sec != nullptr)
-        // FIXME: Proper error handling.
-        report_fatal_error("More than one .gnu.version_r section!");
+      if (dot_gnu_version_r_sec != nullptr) {
+        // More than one .gnu.version_r section!
+        EC = object_error::parse_failed;
+        return;
+      }
       dot_gnu_version_r_sec = &Sec;
       break;
     }
@@ -744,7 +778,39 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &ec)
     }
   }
 
-  ec = std::error_code();
+  // Scan dynamic table.
+  for (Elf_Dyn_Iter DynI = begin_dynamic_table(), DynE = end_dynamic_table();
+  DynI != DynE; ++DynI) {
+    switch (DynI->d_tag) {
+    case ELF::DT_RELA: {
+      uint64_t VBase = 0;
+      const uint8_t *FBase = nullptr;
+      for (Elf_Phdr_Iter PhdrI = begin_program_headers(),
+        PhdrE = end_program_headers();
+        PhdrI != PhdrE; ++PhdrI) {
+        if (PhdrI->p_type != ELF::PT_LOAD)
+          continue;
+        if (DynI->getPtr() >= PhdrI->p_vaddr &&
+            DynI->getPtr() < PhdrI->p_vaddr + PhdrI->p_memsz) {
+          VBase = PhdrI->p_vaddr;
+          FBase = base() + PhdrI->p_offset;
+          break;
+        }
+      }
+      if (!VBase)
+        return;
+      DynRelaRegion.Addr = FBase + DynI->getPtr() - VBase;
+      break;
+    }
+    case ELF::DT_RELASZ:
+      DynRelaRegion.Size = DynI->getVal();
+      break;
+    case ELF::DT_RELAENT:
+      DynRelaRegion.EntSize = DynI->getVal();
+    }
+  }
+
+  EC = std::error_code();
 }
 
 // Get the symbol table index in the symtab section given a symbol
@@ -898,11 +964,8 @@ ErrorOr<StringRef> ELFFile<ELFT>::getSymbolName(Elf_Sym_Iter Sym) const {
 template <class ELFT>
 ErrorOr<StringRef> ELFFile<ELFT>::getSymbolName(const Elf_Shdr *Section,
                                                 const Elf_Sym *Symb) const {
-  if (Symb->st_name == 0) {
-    const Elf_Shdr *ContainingSec = getSection(Symb);
-    if (ContainingSec)
-      return getSectionName(ContainingSec);
-  }
+  if (Symb->st_name == 0)
+    return StringRef("");
 
   const Elf_Shdr *StrTab = getSection(Section->sh_link);
   if (Symb->st_name >= StrTab->sh_size)