Bug 1414506 - Move dl_phdr_info filling and callback invocation to a separate class. r?froydnj draft
authorMike Hommey <mh+mozilla@glandium.org>
Tue, 23 Jan 2018 15:50:38 +0900
changeset 747314 6d8a03a18ab8f70106530b18ecbc8280a3435140
parent 747313 e0b088f3b2cb2d807718522708d69dbe2262532b
child 747315 3206c56f47a93331dad4aa408ef16da6a1834052
push id96871
push userbmo:mh+mozilla@glandium.org
push dateThu, 25 Jan 2018 21:23:22 +0000
reviewersfroydnj
bugs1414506
milestone60.0a1
Bug 1414506 - Move dl_phdr_info filling and callback invocation to a separate class. r?froydnj We're going to introduce two code paths that need to fill dl_phdr_info from different iterators, so first move the code to a separate class, that both code paths will be able to call.
mozglue/linker/ElfLoader.cpp
--- a/mozglue/linker/ElfLoader.cpp
+++ b/mozglue/linker/ElfLoader.cpp
@@ -100,32 +100,46 @@ int
   if (!handle) {
     return dladdr(addr, info);
   }
   info->dli_fname = handle->GetPath();
   info->dli_fbase = handle->GetBase();
   return 1;
 }
 
-int
-__wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data)
+class DlIteratePhdrHelper
 {
-  if (!ElfLoader::Singleton.dbg)
-    return -1;
+public:
+  DlIteratePhdrHelper()
+  {
+    int pipefd[2];
+    valid_pipe = (pipe(pipefd) == 0);
+    read_fd.reset(pipefd[0]);
+    write_fd.reset(pipefd[1]);
+  }
+
+  int fill_and_call(dl_phdr_cb callback, const void* l_addr,
+                    const char* l_name, void* data);
 
-  int pipefd[2];
-  bool valid_pipe = (pipe(pipefd) == 0);
-  AutoCloseFD read_fd(pipefd[0]);
-  AutoCloseFD write_fd(pipefd[1]);
+private:
+  bool valid_pipe;
+  AutoCloseFD read_fd;
+  AutoCloseFD write_fd;
+};
 
-  for (ElfLoader::DebuggerHelper::iterator it = ElfLoader::Singleton.dbg.begin();
-       it < ElfLoader::Singleton.dbg.end(); ++it) {
+// This function is called for each shared library iterated over by
+// dl_iterate_phdr, and is used to fill a dl_phdr_info which is then
+// sent through to the dl_iterate_phdr callback.
+int
+DlIteratePhdrHelper::fill_and_call(dl_phdr_cb callback, const void* l_addr,
+                                   const char* l_name, void *data)
+{
     dl_phdr_info info;
-    info.dlpi_addr = reinterpret_cast<Elf::Addr>(it->l_addr);
-    info.dlpi_name = it->l_name;
+    info.dlpi_addr = reinterpret_cast<Elf::Addr>(l_addr);
+    info.dlpi_name = l_name;
     info.dlpi_phdr = nullptr;
     info.dlpi_phnum = 0;
 
     // Assuming l_addr points to Elf headers (in most cases, this is true),
     // get the Phdr location from there.
     // Unfortunately, when l_addr doesn't point to Elf headers, it may point
     // to unmapped memory, or worse, unreadable memory. The only way to detect
     // the latter without causing a SIGSEGV is to use the pointer in a system
@@ -142,17 +156,17 @@ int
     // start over with a new pipe.
     int can_read = true;
     if (valid_pipe) {
       int ret;
       char raw_ehdr[sizeof(Elf::Ehdr)];
       static_assert(sizeof(raw_ehdr) < PIPE_BUF, "PIPE_BUF is too small");
       do {
         // writes are atomic when smaller than PIPE_BUF, per POSIX.1-2008.
-        ret = write(write_fd, it->l_addr, sizeof(raw_ehdr));
+        ret = write(write_fd, l_addr, sizeof(raw_ehdr));
       } while (ret == -1 && errno == EINTR);
       if (ret != sizeof(raw_ehdr)) {
         if (ret == -1 && errno == EFAULT) {
           can_read = false;
         } else {
           valid_pipe = false;
         }
       } else {
@@ -167,25 +181,38 @@ int
                  (ret == -1 && errno == EINTR));
         if (nbytes != sizeof(raw_ehdr)) {
           valid_pipe = false;
         }
       }
     }
 
     if (valid_pipe && can_read) {
-      const Elf::Ehdr *ehdr = Elf::Ehdr::validate(it->l_addr);
+      const Elf::Ehdr *ehdr = Elf::Ehdr::validate(l_addr);
       if (ehdr) {
         info.dlpi_phdr = reinterpret_cast<const Elf::Phdr *>(
                          reinterpret_cast<const char *>(ehdr) + ehdr->e_phoff);
         info.dlpi_phnum = ehdr->e_phnum;
       }
     }
 
-    int ret = callback(&info, sizeof(dl_phdr_info), data);
+    return callback(&info, sizeof(dl_phdr_info), data);
+}
+
+int
+__wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data)
+{
+  if (!ElfLoader::Singleton.dbg)
+    return -1;
+
+  DlIteratePhdrHelper helper;
+
+  for (ElfLoader::DebuggerHelper::iterator it = ElfLoader::Singleton.dbg.begin();
+       it < ElfLoader::Singleton.dbg.end(); ++it) {
+    int ret = helper.fill_and_call(callback, it->l_addr, it->l_name, data);
     if (ret)
       return ret;
   }
   return 0;
 }
 
 #ifdef __ARM_EABI__
 const void *