You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2016/07/02 21:51:10 UTC

[4/5] mesos git commit: Re-implemented the stout ELF abstraction in terms of ELFIO.

Re-implemented the stout ELF abstraction in terms of ELFIO.

As part of this, we updated the API to include functions written in
snake_case (as is standard for stout). We also removed the 'close()'
call, as the new ELFIO library doesn't require it (as it loads the
file into memory!).

Review: https://reviews.apache.org/r/49562/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/4e2bbdd8
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/4e2bbdd8
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/4e2bbdd8

Branch: refs/heads/master
Commit: 4e2bbdd8f11cd31e0d5218aeb7079a55a9306681
Parents: 0349666
Author: Kevin Klues <kl...@gmail.com>
Authored: Sat Jul 2 13:55:23 2016 -0700
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Sat Jul 2 14:46:58 2016 -0700

----------------------------------------------------------------------
 3rdparty/stout/include/stout/elf.hpp | 202 ++++++++----------------------
 1 file changed, 51 insertions(+), 151 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/4e2bbdd8/3rdparty/stout/include/stout/elf.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/elf.hpp b/3rdparty/stout/include/stout/elf.hpp
index 5382acc..67d8962 100644
--- a/3rdparty/stout/include/stout/elf.hpp
+++ b/3rdparty/stout/include/stout/elf.hpp
@@ -17,218 +17,118 @@
 #ifndef __STOUT_ELF_HPP__
 #define __STOUT_ELF_HPP__
 
-#include <fcntl.h>
-#include <gelf.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-
 #include <map>
 #include <string>
 #include <vector>
 
+#include <elfio/elfio.hpp>
+
 #include <stout/error.hpp>
 #include <stout/foreach.hpp>
-#include <stout/nothing.hpp>
-#include <stout/option.hpp>
-#include <stout/stringify.hpp>
 #include <stout/try.hpp>
 
 namespace elf {
 
-enum Class {
+enum Class
+{
   CLASSNONE = ELFCLASSNONE,
   CLASS32 = ELFCLASS32,
   CLASS64 = ELFCLASS64,
 };
 
-enum class SectionType {
+enum class SectionType
+{
   DYNAMIC = SHT_DYNAMIC,
 };
 
-enum class DynamicTag {
+enum class DynamicTag
+{
   STRTAB = DT_STRTAB,
   SONAME = DT_SONAME,
   NEEDED = DT_NEEDED,
 };
 
+
 // This class is used to represent the contents of a standard ELF
 // binary. The current implementation is incomplete.
 //
-// TODO(klueska): For now, we only include functionality to extract
-// the SONAME from shared libraries and read their external library
-// dependencies. In the future, we will expand this class to include
-// helpers for full access to an ELF file's contents.
-class File {
+// NOTE: We use ELFIO under the hood to do our elf parsing for us.
+// Unfortunately, ELFIO reads the *entire* elf file into memory when
+// it is first loaded instead of relying on something like `mmap` to
+// only page in the parts of the file we are interested in. If this
+// becomes a problem, we will have to use something like `libelf`
+// instead (but note that libelf is not header-only and will
+// therefore introduce a runtime library dependency).
+class File
+{
 public:
-  // Open an ELF binary. We do some preliminary parsing as part of
-  // opening the ELF to get quick references to all of its internal
-  // sections for all future calls.
-  //
-  // TODO(klueska): Consider adding a 'stout::Owned' type to avoid
-  // returning a raw pointer here.
-  static Try<File*> open(const std::string& path)
+  // TODO(klueska): Return a unique_ptr here.
+  static Try<File*> load(const std::string& path)
   {
-    // Set the elf library operating version.
-    if (elf_version(EV_CURRENT) == EV_NONE) {
-      return Error("Failed to set ELF library version: " +
-                   stringify(elf_errmsg(-1)));
-    }
-
     File* file = new File();
 
-    file->fd = ::open(path.c_str(), O_RDONLY);
-    if (file->fd < 0) {
+    if (!file->elf.load(path.c_str())) {
       delete file;
-      return ErrnoError("Failed to open file");
+      return Error("Unknown error during elfio::load");
     }
 
-    file->elf = elf_begin(file->fd, ELF_C_READ, nullptr);
-    if (file->elf == nullptr) {
-      delete file;
-      return Error("elf_begin() failed: " + stringify(elf_errmsg(-1)));
-    }
-
-    if (elf_kind(file->elf) != ELF_K_ELF) {
-      delete file;
-      return Error("File is not an ELF binary");
-    }
-
-    // Create the mapping from section type to section locations.
-    Elf_Scn* section = nullptr;
-    while ((section = elf_nextscn(file->elf, section)) != nullptr) {
-      GElf_Shdr section_header;
-      if (gelf_getshdr(section, &section_header) == nullptr) {
-        delete file;
-        return Error("gelf_getshdr() failed: " + stringify(elf_errmsg(-1)));
-      }
-
-      SectionType section_type = (SectionType) section_header.sh_type;
-      switch (section_type) {
-        case SectionType::DYNAMIC:
-          file->sections[section_type].push_back(section);
-      }
+    // Create the mapping from section type to sections.
+    foreach (ELFIO::section* section, file->elf.sections) {
+      SectionType section_type = (SectionType) section->get_type();
+      file->sections_by_type[section_type].push_back(section);
     }
 
     return file;
   }
 
-  void close()
-  {
-    if (elf != nullptr) {
-      elf_end(elf);
-      elf = nullptr;
-    }
-
-    if (fd >= 0) {
-      ::close(fd);
-      fd = -1;
-    }
-  }
-
-  ~File()
-  {
-    close();
-  };
-
-
-  // Returns the ELF class of an
-  // ELF file (CLASS32, or CLASS64).
-  Try<Class> GetClass() const
+  // Returns the ELF class of an ELF file (CLASS32, or CLASS64).
+  Try<Class> get_class() const
   {
-    Class c = (Class)gelf_getclass(elf);
+    Class c = Class(elf.get_class());
     if (c == CLASSNONE) {
-      return Error("gelf_getclass() failed: " + stringify(elf_errmsg(-1)));
+      return Error("Unknown error");
     }
     return c;
   }
 
 
-  // Extract the strings associated with the provided `DynamicTag`
-  // from the DYNAMIC section of the ELF binary.
-  Try<std::vector<std::string>> GetDynamicStrings(DynamicTag tag) const
+  // Extract the strings associated with the provided
+  // `DynamicTag` from all DYNAMIC sections in the ELF binary.
+  Try<std::vector<std::string>> get_dynamic_strings(DynamicTag tag) const
   {
-    if (sections.count(SectionType::DYNAMIC) == 0) {
+    if (sections_by_type.count(SectionType::DYNAMIC) == 0) {
       return Error("No DYNAMIC sections found in ELF");
     }
 
-    if (sections.count(SectionType::DYNAMIC) != 1) {
-      return Error("Multiple DYNAMIC sections found in ELF");
-    }
-
-    Elf_Scn* dynamic_section = sections.at(SectionType::DYNAMIC)[0];
-
-    // Walk through the entries in the dynamic section and look for
-    // entries with the provided tag. These entries contain offsets to
-    // strings in the dynamic section's string table. Consequently, we
-    // also have to look for an entry containing a pointer to the
-    // dynamic section's string table so we can resolve the strings
-    // associated with the provided tag later on.
-    Elf_Data* dynamic_data = elf_getdata(dynamic_section, nullptr);
-    if (dynamic_data == nullptr) {
-      return Error("elf_getdata() failed: " + stringify(elf_errmsg(-1)));
-    }
-
-    Option<uintptr_t> strtab_pointer = None();
-    std::vector<uintptr_t> strtab_offsets;
-
-    for (size_t i = 0; i < dynamic_data->d_size / sizeof(GElf_Dyn); i++) {
-      GElf_Dyn entry;
-      if (gelf_getdyn(dynamic_data, i, &entry) == nullptr) {
-          return Error("gelf_getdyn() failed: " + stringify(elf_errmsg(-1)));
-      }
-
-      if ((DynamicTag)entry.d_tag == DynamicTag::STRTAB) {
-        strtab_pointer = entry.d_un.d_ptr;
-      }
-
-      if ((DynamicTag)entry.d_tag == tag) {
-        strtab_offsets.push_back(entry.d_un.d_ptr);
-      }
-    }
-
-    if (strtab_offsets.empty()) {
-      return std::vector<std::string>();
-    }
+    std::vector<std::string> strings;
 
-    if (strtab_pointer.isNone()) {
-      return Error("Failed to find string table");
-    }
+    foreach (ELFIO::section* section,
+             sections_by_type.at(SectionType::DYNAMIC)) {
+      auto accessor = ELFIO::dynamic_section_accessor(elf, section);
 
-    // Get a reference to the actual string table so we can index into it.
-    Elf_Scn* string_table_section = gelf_offscn(elf, strtab_pointer.get());
-    if (string_table_section == nullptr) {
-      return Error("gelf_offscn() failed: " + stringify(elf_errmsg(-1)));
-    }
+      for (ELFIO::Elf_Xword i = 0; i < accessor.get_entries_num(); ++i) {
+        ELFIO::Elf_Xword entry_tag;
+        ELFIO::Elf_Xword entry_value;
+        std::string entry_string;
 
-    size_t strtab_index = elf_ndxscn(string_table_section);
-    if (strtab_index == SHN_UNDEF) {
-      return Error("elf_ndxscn() failed: " + stringify(elf_errmsg(-1)));
-    }
+        if (!accessor.get_entry(i, entry_tag, entry_value, entry_string)) {
+          return Error("Failed to get entry from DYNAMIC section of elf");
+        }
 
-    // Find the strings in the string table from their offsets and return them.
-    std::vector<std::string> strings;
-    foreach (uintptr_t offset, strtab_offsets) {
-      char* string = elf_strptr(elf, strtab_index, offset);
-      if (string == nullptr) {
-        return Error("elf_strptr() failed: " + stringify(elf_errmsg(-1)));
+        if (tag == DynamicTag(entry_tag)) {
+          strings.push_back(entry_string);
+        }
       }
-
-      strings.push_back(string);
     }
 
     return strings;
   }
 
 private:
-  explicit File()
-    : fd(-1),
-      elf(nullptr) {}
+  explicit File() {}
 
-  int fd;
-  Elf* elf;
-  std::map<SectionType, std::vector<Elf_Scn*>> sections;
+  ELFIO::elfio elf;
+  std::map<SectionType, std::vector<ELFIO::section*>> sections_by_type;
 };
 
 } // namespace elf {