folly::ElfFile - add support to iterate over program headers
authorMirek Klimos <miro@fb.com>
Wed, 16 Aug 2017 04:04:27 +0000 (21:04 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Wed, 16 Aug 2017 04:10:04 +0000 (21:10 -0700)
Summary: Adding iterateProgramHeaders, similar to iterateSections, just iterates over program headers instead of section headers. I want this to get the size of the first PT_LOAD header.

Differential Revision: D5602575

fbshipit-source-id: f73989cade20214f884571c1099761ecaa4841f7

folly/experimental/symbolizer/Elf-inl.h
folly/experimental/symbolizer/Elf.cpp
folly/experimental/symbolizer/Elf.h
folly/experimental/symbolizer/test/ElfTests.cpp

index 1679f5c7afc68aaa20f2262e27b574b16096142e..bd9b0a4029252332494027a9e7d147f3334d9640 100644 (file)
 namespace folly {
 namespace symbolizer {
 
+template <class Fn>
+const ElfPhdr* ElfFile::iterateProgramHeaders(Fn fn) const {
+  const ElfPhdr* ptr = &at<ElfPhdr>(elfHeader().e_phoff);
+  for (size_t i = 0; i < elfHeader().e_phnum; i++, ptr++) {
+    if (fn(*ptr)) {
+      return ptr;
+    }
+  }
+
+  return nullptr;
+}
+
 template <class Fn>
 const ElfShdr* ElfFile::iterateSections(Fn fn) const {
   const ElfShdr* ptr = &at<ElfShdr>(elfHeader().e_shoff);
index 038bea7a02a64a0de9b25203a971f0d546f193d0..a0dfe9ce9b1e66baa4ba8d140690c7f456519424 100644 (file)
@@ -263,24 +263,18 @@ bool ElfFile::init(const char** msg) {
     }
   }
 
-  const ElfPhdr* programHeader = &at<ElfPhdr>(elfHeader.e_phoff);
-  bool foundBase = false;
-  for (size_t i = 0; i < elfHeader.e_phnum; programHeader++, i++) {
-    // Program headers are sorted by load address, so the first PT_LOAD
-    // header gives us the base address.
-    if (programHeader->p_type == PT_LOAD) {
-      baseAddress_ = programHeader->p_vaddr;
-      foundBase = true;
-      break;
-    }
-  }
+  // Program headers are sorted by load address, so the first PT_LOAD
+  // header gives us the base address.
+  const ElfPhdr* programHeader =
+      iterateProgramHeaders([](auto& h) { return h.p_type == PT_LOAD; });
 
-  if (!foundBase) {
+  if (!programHeader) {
     if (msg) {
       *msg = "could not find base address";
     }
     return false;
   }
+  baseAddress_ = programHeader->p_vaddr;
 
   return true;
 }
index 48b5f8fb03d56d5ba0311376cf094ae3d21c231c..2bf37a9def6754cdab44ec314c5465fcb5456d40 100644 (file)
@@ -122,6 +122,14 @@ class ElfFile {
   template <class Fn>
   const char* iterateStrings(const ElfShdr& stringTable, Fn fn) const;
 
+  /**
+   * Iterate over program headers as long as fn(section) returns false.
+   * Returns a pointer to the current ("found") section when fn returned
+   * true, or nullptr if fn returned false for all sections.
+   */
+  template <class Fn>
+  const ElfPhdr* iterateProgramHeaders(Fn fn) const;
+
   /**
    * Iterate over all sections for as long as fn(section) returns false.
    * Returns a pointer to the current ("found") section when fn returned
index f27fef4147764eecec6a7a7a9350b4a777571eae..51d8531db9baff7e8546278d6c5da9dc13c57b45 100644 (file)
@@ -52,6 +52,13 @@ TEST_F(ElfTest, PointerValue) {
   EXPECT_STREQ(kStringValue, str);
 }
 
+TEST_F(ElfTest, iterateProgramHeaders) {
+  auto phdr = elfFile_.iterateProgramHeaders(
+      [](auto& h) { return h.p_type == PT_LOAD; });
+  EXPECT_NE(nullptr, phdr);
+  EXPECT_GE(phdr->p_filesz, 0);
+}
+
 int main(int argc, char** argv) {
   testing::InitGoogleTest(&argc, argv);
   gflags::ParseCommandLineFlags(&argc, &argv, true);