Add dynamic_table iterators back to ELF.h.
authorRafael Espindola <rafael.espindola@gmail.com>
Fri, 7 Aug 2015 15:25:20 +0000 (15:25 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Fri, 7 Aug 2015 15:25:20 +0000 (15:25 +0000)
In tree they are only used by llvm-readobj, but it is also used by
https://github.com/mono/CppSharp.

While at it, add some missing error checking.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@244320 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/ELF.h
include/llvm/Object/Error.h
lib/Object/Error.cpp
test/Object/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 [new file with mode: 0755]
test/Object/corrupt.test
tools/llvm-readobj/ELFDumper.cpp

index f477db64c82424a60f1a9ce064a379fedf2a1b8b..bb949ec9708efbbcb11bd4873dc1c17452609fe7 100644 (file)
@@ -141,6 +141,18 @@ public:
       Header->getDataEncoding() == ELF::ELFDATA2LSB;
   }
 
+  ErrorOr<const Elf_Dyn *> dynamic_table_begin(const Elf_Phdr *Phdr) const;
+  ErrorOr<const Elf_Dyn *> dynamic_table_end(const Elf_Phdr *Phdr) const;
+  ErrorOr<Elf_Dyn_Range> dynamic_table(const Elf_Phdr *Phdr) const {
+    ErrorOr<const Elf_Dyn *> Begin = dynamic_table_begin(Phdr);
+    if (std::error_code EC = Begin.getError())
+      return EC;
+    ErrorOr<const Elf_Dyn *> End = dynamic_table_end(Phdr);
+    if (std::error_code EC = End.getError())
+      return EC;
+    return make_range(*Begin, *End);
+  }
+
   const Elf_Shdr *section_begin() const;
   const Elf_Shdr *section_end() const;
   Elf_Shdr_Range sections() const {
@@ -465,6 +477,34 @@ const typename ELFFile<ELFT>::Elf_Shdr *ELFFile<ELFT>::section_end() const {
   return section_begin() + getNumSections();
 }
 
+template <class ELFT>
+ErrorOr<const typename ELFFile<ELFT>::Elf_Dyn *>
+ELFFile<ELFT>::dynamic_table_begin(const Elf_Phdr *Phdr) const {
+  if (!Phdr)
+    return nullptr;
+  assert(Phdr->p_type == ELF::PT_DYNAMIC && "Got the wrong program header");
+  uintX_t Offset = Phdr->p_offset;
+  if (Offset > Buf.size())
+    return object_error::parse_failed;
+  return reinterpret_cast<const Elf_Dyn *>(base() + Offset);
+}
+
+template <class ELFT>
+ErrorOr<const typename ELFFile<ELFT>::Elf_Dyn *>
+ELFFile<ELFT>::dynamic_table_end(const Elf_Phdr *Phdr) const {
+  if (!Phdr)
+    return nullptr;
+  assert(Phdr->p_type == ELF::PT_DYNAMIC && "Got the wrong program header");
+  uintX_t Size = Phdr->p_filesz;
+  if (Size % sizeof(Elf_Dyn))
+    return object_error::elf_invalid_dynamic_table_size;
+  // FIKME: Check for overflow?
+  uintX_t End = Phdr->p_offset + Size;
+  if (End > Buf.size())
+    return object_error::parse_failed;
+  return reinterpret_cast<const Elf_Dyn *>(base() + End);
+}
+
 template <class ELFT>
 template <typename T>
 const T *ELFFile<ELFT>::getEntry(uint32_t Section, uint32_t Entry) const {
index aa320bb51a46a8ee162683207cb26b53394e4c8c..0f79a6ed0dd81d429e090960c55cede4426ff4ed 100644 (file)
@@ -30,6 +30,7 @@ enum class object_error {
   string_table_non_null_end,
   invalid_section_index,
   bitcode_section_not_found,
+  elf_invalid_dynamic_table_size,
   macho_small_load_command,
   macho_load_segment_too_many_sections,
   macho_load_segment_too_small,
index 7ca2f12f092433b03de4f8c9216167a67b988b37..7ecc3a19af9d9ae78ca9575531f7ae8fe92f382e 100644 (file)
@@ -47,6 +47,8 @@ std::string _object_error_category::message(int EV) const {
     return "Invalid section index";
   case object_error::bitcode_section_not_found:
     return "Bitcode section not found in object file";
+  case object_error::elf_invalid_dynamic_table_size:
+    return "Invalid dynamic table size";
   case object_error::macho_small_load_command:
     return "Mach-O load command with size < 8 bytes";
   case object_error::macho_load_segment_too_many_sections:
diff --git a/test/Object/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 b/test/Object/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64
new file mode 100755 (executable)
index 0000000..d164d82
Binary files /dev/null and b/test/Object/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 differ
index 360e7c8775ed118adb37c6549e18a2ec03b468f1..0d9aad378f8802ba2b1ad8d73f3cda15152fa723 100644 (file)
@@ -56,3 +56,17 @@ RUN:   %p/Inputs/corrupt-invalid-dynamic-table-size.elf.x86-64 2>&1 | \
 RUN:   FileCheck --check-prefix=DYN-TABLE-SIZE %s
 
 DYN-TABLE-SIZE:  Invalid dynamic table size
+
+
+RUN: not llvm-readobj -dyn-relocations \
+RUN:   %p/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 2>&1 | \
+RUN:   FileCheck --check-prefix=DYN-TABLE-OFFSET %s
+
+DYN-TABLE-OFFSET: Invalid data was encountered while parsing the file.
+
+
+RUN: not llvm-readobj -dyn-relocations \
+RUN:   %p/Inputs/corrupt-invalid-dynamic-table-too-large.elf.x86-64 2>&1 | \
+RUN:   FileCheck --check-prefix=DYN-TABLE-TOO-LARGE %s
+
+DYN-TABLE-TOO-LARGE: Invalid data was encountered while parsing the file.
index 916cb2acfb9e37905f3840eba8c1abf89af44f1b..5887d2944d1244a7cfc6993e7638d7b54f56e435 100644 (file)
@@ -104,10 +104,20 @@ private:
   const Elf_Rela *dyn_rela_end() const;
   Elf_Rela_Range dyn_relas() const;
   StringRef getDynamicString(uint64_t Offset) const;
-  const Elf_Dyn *dynamic_table_begin() const;
-  const Elf_Dyn *dynamic_table_end() const;
+  const Elf_Dyn *dynamic_table_begin() const {
+    ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_begin(DynamicProgHeader);
+    error(Ret.getError());
+    return *Ret;
+  }
+  const Elf_Dyn *dynamic_table_end() const {
+    ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_end(DynamicProgHeader);
+    error(Ret.getError());
+    return *Ret;
+  }
   Elf_Dyn_Range dynamic_table() const {
-    return make_range(dynamic_table_begin(), dynamic_table_end());
+    ErrorOr<Elf_Dyn_Range> Ret = Obj->dynamic_table(DynamicProgHeader);
+    error(Ret.getError());
+    return *Ret;
   }
 
   StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb,
@@ -118,7 +128,7 @@ private:
 
   const ELFO *Obj;
   DynRegionInfo DynRelaRegion;
-  DynRegionInfo DynamicRegion;
+  const Elf_Phdr *DynamicProgHeader = nullptr;
   StringRef DynamicStringTable;
   const Elf_Sym *DynSymStart = nullptr;
   StringRef SOName;
@@ -798,11 +808,7 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer)
   SmallVector<const Elf_Phdr *, 4> LoadSegments;
   for (const Elf_Phdr &Phdr : Obj->program_headers()) {
     if (Phdr.p_type == ELF::PT_DYNAMIC) {
-      DynamicRegion.Addr = Obj->base() + Phdr.p_offset;
-      uint64_t Size = Phdr.p_filesz;
-      if (Size % sizeof(Elf_Dyn))
-        report_fatal_error("Invalid dynamic table size");
-      DynamicRegion.Size = Phdr.p_filesz;
+      DynamicProgHeader = &Phdr;
       continue;
     }
     if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0)
@@ -904,19 +910,6 @@ typename ELFDumper<ELFT>::Elf_Rela_Range ELFDumper<ELFT>::dyn_relas() const {
   return make_range(dyn_rela_begin(), dyn_rela_end());
 }
 
-template <typename ELFT>
-const typename ELFDumper<ELFT>::Elf_Dyn *
-ELFDumper<ELFT>::dynamic_table_begin() const {
-  return reinterpret_cast<const Elf_Dyn *>(DynamicRegion.Addr);
-}
-
-template <typename ELFT>
-const typename ELFDumper<ELFT>::Elf_Dyn *
-ELFDumper<ELFT>::dynamic_table_end() const {
-  uint64_t Size = DynamicRegion.Size;
-  return dynamic_table_begin() + Size / sizeof(Elf_Dyn);
-}
-
 template<class ELFT>
 void ELFDumper<ELFT>::printFileHeaders() {
   const Elf_Ehdr *Header = Obj->getHeader();