Bug 747033 - Implement dl_iterate_phdr in the custom linker. r=froydnj
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 25 Apr 2012 09:05:02 +0200
changeset 96460 bb9548c09c19162b5afc66c878de6b49cac0a74c
parent 96459 864ae3bff0b22d6e5edf74f36bfd3d0d77844b9a
child 96461 77e68aa8f24c8da77d4ff7e3c1346394d92c3e05
push id1116
push userlsblakk@mozilla.com
push dateMon, 16 Jul 2012 19:38:18 +0000
treeherdermozilla-beta@95f959a8b4dc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs747033
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 747033 - Implement dl_iterate_phdr in the custom linker. r=froydnj
mozglue/linker/CustomElf.cpp
mozglue/linker/CustomElf.h
mozglue/linker/ElfLoader.cpp
mozglue/linker/ElfLoader.h
mozglue/linker/Elfxx.h
--- a/mozglue/linker/CustomElf.cpp
+++ b/mozglue/linker/CustomElf.cpp
@@ -286,16 +286,18 @@ CustomElf::GetSymbolPtrInDeps(const char
     if (strcmp(symbol + 2, "error") == 0)
       return FunctionPtr(__wrap_dlerror);
     if (strcmp(symbol + 2, "close") == 0)
       return FunctionPtr(__wrap_dlclose);
     if (strcmp(symbol + 2, "sym") == 0)
       return FunctionPtr(__wrap_dlsym);
     if (strcmp(symbol + 2, "addr") == 0)
       return FunctionPtr(__wrap_dladdr);
+    if (strcmp(symbol + 2, "_iterate_phdr") == 0)
+      return FunctionPtr(__wrap_dl_iterate_phdr);
   } else if (symbol[0] == '_' && symbol[1] == '_') {
   /* Resolve a few C++ ABI specific functions to point to ours */
 #ifdef __ARM_EABI__
     if (strcmp(symbol + 2, "aeabi_atexit") == 0)
       return FunctionPtr(&ElfLoader::__wrap_aeabi_atexit);
 #else
     if (strcmp(symbol + 2, "cxa_atexit") == 0)
       return FunctionPtr(&ElfLoader::__wrap_cxa_atexit);
--- a/mozglue/linker/CustomElf.h
+++ b/mozglue/linker/CustomElf.h
@@ -1,243 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef CustomElf_h
 #define CustomElf_h
 
-/**
- * Android system headers have two different elf.h file. The one under linux/
- * is the most complete.
- */
-#ifdef ANDROID
-#include <linux/elf.h>
-#else
-#include <elf.h>
-#endif
-#include <endian.h>
 #include "ElfLoader.h"
 #include "Logging.h"
-
-/**
- * Generic ELF macros for the target system
- */
-#ifdef HAVE_64BIT_OS
-#define Elf_(type) Elf64_ ## type
-#define ELFCLASS ELFCLASS64
-#define ELF_R_TYPE ELF64_R_TYPE
-#define ELF_R_SYM ELF64_R_SYM
-#ifndef ELF_ST_BIND
-#define ELF_ST_BIND ELF64_ST_BIND
-#endif
-#define PRIxAddr "lx"
-#else
-#define Elf_(type) Elf32_ ## type
-#define ELFCLASS ELFCLASS32
-#define ELF_R_TYPE ELF32_R_TYPE
-#define ELF_R_SYM ELF32_R_SYM
-#ifndef ELF_ST_BIND
-#define ELF_ST_BIND ELF32_ST_BIND
-#endif
-#define PRIxAddr "x"
-#endif
-
-#ifndef __BYTE_ORDER
-#error Cannot find endianness
-#endif
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define ELFDATA ELFDATA2LSB
-#elif __BYTE_ORDER == __BIG_ENDIAN
-#define ELFDATA ELFDATA2MSB
-#endif
-
-#ifdef __linux__
-#define ELFOSABI ELFOSABI_LINUX
-#ifdef EI_ABIVERSION
-#define ELFABIVERSION 0
-#endif
-#else
-#error Unknown ELF OSABI
-#endif
-
-#if defined(__i386__)
-#define ELFMACHINE EM_386
-
-// Doing this way probably doesn't scale to other architectures
-#define R_ABS R_386_32
-#define R_GLOB_DAT R_386_GLOB_DAT
-#define R_JMP_SLOT R_386_JMP_SLOT
-#define R_RELATIVE R_386_RELATIVE
-#define RELOC(n) DT_REL ## n
-#define UNSUPPORTED_RELOC(n) DT_RELA ## n
-#define STR_RELOC(n) "DT_REL" # n
-#define Reloc Rel
-
-#elif defined(__x86_64__)
-#define ELFMACHINE EM_X86_64
-
-#define R_ABS R_X86_64_64
-#define R_GLOB_DAT R_X86_64_GLOB_DAT
-#define R_JMP_SLOT R_X86_64_JUMP_SLOT
-#define R_RELATIVE R_X86_64_RELATIVE
-#define RELOC(n) DT_RELA ## n
-#define UNSUPPORTED_RELOC(n) DT_REL ## n
-#define STR_RELOC(n) "DT_RELA" # n
-#define Reloc Rela
-
-#elif defined(__arm__)
-#define ELFMACHINE EM_ARM
-
-#ifndef R_ARM_ABS32
-#define R_ARM_ABS32 2
-#endif
-#ifndef R_ARM_GLOB_DAT
-#define R_ARM_GLOB_DAT 21
-#endif
-#ifndef R_ARM_JUMP_SLOT
-#define R_ARM_JUMP_SLOT 22
-#endif
-#ifndef R_ARM_RELATIVE
-#define R_ARM_RELATIVE 23
-#endif
-
-#define R_ABS R_ARM_ABS32
-#define R_GLOB_DAT R_ARM_GLOB_DAT
-#define R_JMP_SLOT R_ARM_JUMP_SLOT
-#define R_RELATIVE R_ARM_RELATIVE
-#define RELOC(n) DT_REL ## n
-#define UNSUPPORTED_RELOC(n) DT_RELA ## n
-#define STR_RELOC(n) "DT_REL" # n
-#define Reloc Rel
-
-#else
-#error Unknown ELF machine type
-#endif
-
-/**
- * Android system headers don't have all definitions
- */
-#ifndef STN_UNDEF
-#define STN_UNDEF 0
-#endif
-#ifndef DT_INIT_ARRAY
-#define DT_INIT_ARRAY 25
-#endif
-#ifndef DT_FINI_ARRAY
-#define DT_FINI_ARRAY 26
-#endif
-#ifndef DT_INIT_ARRAYSZ
-#define DT_INIT_ARRAYSZ 27
-#endif
-#ifndef DT_FINI_ARRAYSZ
-#define DT_FINI_ARRAYSZ 28
-#endif
-#ifndef DT_RELACOUNT
-#define DT_RELACOUNT 0x6ffffff9
-#endif
-#ifndef DT_RELCOUNT
-#define DT_RELCOUNT 0x6ffffffa
-#endif
-#ifndef DT_VERSYM
-#define DT_VERSYM 0x6ffffff0
-#endif
-#ifndef DT_VERDEF
-#define DT_VERDEF 0x6ffffffc
-#endif
-#ifndef DT_VERDEFNUM
-#define DT_VERDEFNUM 0x6ffffffd
-#endif
-#ifndef DT_VERNEED
-#define DT_VERNEED 0x6ffffffe
-#endif
-#ifndef DT_VERNEEDNUM
-#define DT_VERNEEDNUM 0x6fffffff
-#endif
-#ifndef DT_FLAGS
-#define DT_FLAGS 30
-#endif
-#ifndef DF_SYMBOLIC
-#define DF_SYMBOLIC 0x00000002
-#endif
-#ifndef DF_TEXTREL
-#define DF_TEXTREL 0x00000004
-#endif
-
-namespace Elf {
-
-/**
- * Define a few basic Elf Types
- */
-typedef Elf_(Phdr) Phdr;
-typedef Elf_(Dyn) Dyn;
-typedef Elf_(Sym) Sym;
-typedef Elf_(Addr) Addr;
-typedef Elf_(Word) Word;
-
-/**
- * Helper class around the standard Elf header struct
- */
-struct Ehdr: public Elf_(Ehdr)
-{
-  /**
-   * Equivalent to reinterpret_cast<const Ehdr *>(buf), but additionally
-   * checking that this is indeed an Elf header and that the Elf type
-   * corresponds to that of the system
-   */
-  static const Ehdr *validate(const void *buf);
-};
-
-/**
- * Elf String table
- */
-class Strtab: public UnsizedArray<const char>
-{
-public:
-  /**
-   * Returns the string at the given index in the table
-   */
-  const char *GetStringAt(off_t index) const
-  {
-    return &UnsizedArray<const char>::operator[](index);
-  }
-};
-
-/**
- * Helper class around Elf relocation.
- */
-struct Rel: public Elf_(Rel)
-{
-  /**
-   * Returns the addend for the relocation, which is the value stored
-   * at r_offset.
-   */
-  Addr GetAddend(void *base) const
-  {
-    return *(reinterpret_cast<const Addr *>(
-                   reinterpret_cast<const char *>(base) + r_offset));
-  }
-};
-
-/**
- * Helper class around Elf relocation with addend.
- */
-struct Rela: public Elf_(Rela)
-{
-  /**
-   * Returns the addend for the relocation.
-   */
-  Addr GetAddend(void *base) const
-  {
-    return r_addend;
-  }
-};
-
-} /* namespace Elf */
+#include "Elfxx.h"
 
 class Mappable;
 
 /**
  * Library Handle class for ELF libraries we don't let the system linker
  * handle.
  */
 class CustomElf: public LibHandle, private ElfLoader::link_map
--- a/mozglue/linker/ElfLoader.cpp
+++ b/mozglue/linker/ElfLoader.cpp
@@ -87,16 +87,36 @@ int
 {
   RefPtr<LibHandle> handle = ElfLoader::Singleton.GetHandleByPtr(addr);
   if (!handle)
     return 0;
   info->dli_fname = handle->GetPath();
   return 1;
 }
 
+int
+__wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data)
+{
+  if (ElfLoader::Singleton.dbg == NULL)
+    return -1;
+
+  for (ElfLoader::r_debug::iterator it = ElfLoader::Singleton.dbg->begin();
+       it < ElfLoader::Singleton.dbg->end(); ++it) {
+    dl_phdr_info info;
+    info.dlpi_addr = reinterpret_cast<Elf::Addr>(it->l_addr);
+    info.dlpi_name = it->l_name;
+    info.dlpi_phdr = NULL;
+    info.dlpi_phnum = 0;
+    int ret = callback(&info, sizeof(dl_phdr_info), data);
+    if (ret)
+      return ret;
+  }
+  return 0;
+}
+
 namespace {
 
 /**
  * Returns the part after the last '/' for the given path
  */
 const char *
 LeafName(const char *path)
 {
--- a/mozglue/linker/ElfLoader.h
+++ b/mozglue/linker/ElfLoader.h
@@ -5,16 +5,17 @@
 #ifndef ElfLoader_h
 #define ElfLoader_h
 
 #include <vector>
 #include <dlfcn.h>
 #include <signal.h>
 #include "mozilla/RefPtr.h"
 #include "Zip.h"
+#include "Elfxx.h"
 
 /**
  * dlfcn.h replacement functions
  */
 extern "C" {
   void *__wrap_dlopen(const char *path, int flags);
   const char *__wrap_dlerror(void);
   void *__wrap_dlsym(void *handle, const char *symbol);
@@ -28,16 +29,26 @@ extern "C" {
     void *dli_saddr;
   } Dl_info;
 #endif
   int __wrap_dladdr(void *addr, Dl_info *info);
 
   sighandler_t __wrap_signal(int signum, sighandler_t handler);
   int __wrap_sigaction(int signum, const struct sigaction *act,
                        struct sigaction *oldact);
+
+  struct dl_phdr_info {
+    Elf::Addr dlpi_addr;
+    const char *dlpi_name;
+    const Elf::Phdr *dlpi_phdr;
+    Elf::Half dlpi_phnum;
+  };
+
+  typedef int (*dl_phdr_cb)(struct dl_phdr_info *, size_t, void *);
+  int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data);
 }
 
 /**
  * Abstract class for loaded libraries. Libraries may be loaded through the
  * system linker or this linker, both cases will be derived from this class.
  */
 class LibHandle: public mozilla::RefCounted<LibHandle>
 {
@@ -351,41 +362,85 @@ protected:
 
 private:
   /* Keep track of all registered destructors */
   std::vector<DestructorCaller> destructors;
 
   /* Keep track of Zips used for library loading */
   ZipCollection zips;
 
+  /* Forward declaration, see further below */
+  class r_debug;
 public:
   /* Loaded object descriptor for the debugger interface below*/
   struct link_map {
     /* Base address of the loaded object. */
     const void *l_addr;
     /* File name */
     const char *l_name;
     /* Address of the PT_DYNAMIC segment. */
     const void *l_ld;
+
+  private:
+    friend class ElfLoader::r_debug;
     /* Double linked list of loaded objects. */
     link_map *l_next, *l_prev;
   };
 
 private:
   /* Data structure used by the linker to give details about shared objects it
    * loaded to debuggers. This is normally defined in link.h, but Android
    * headers lack this file. This also gives the opportunity to make it C++. */
   class r_debug {
   public:
     /* Make the debugger aware of a new loaded object */
     void Add(link_map *map);
 
     /* Make the debugger aware of the unloading of an object */
     void Remove(link_map *map);
 
+    /* Iterates over all link_maps */
+    class iterator
+    {
+    public:
+      const link_map *operator ->() const
+      {
+        return item;
+      }
+
+      const link_map &operator ++()
+      {
+        item = item->l_next;
+        return *item;
+      }
+
+      bool operator<(const iterator &other) const
+      {
+        if (other.item == NULL)
+          return item ? true : false;
+        MOZ_NOT_REACHED("r_debug::iterator::operator< called with something else than r_debug::end()");
+      }
+    protected:
+      friend class r_debug;
+      iterator(const link_map *item): item(item) { }
+
+    private:
+      const link_map *item;
+    };
+
+    iterator begin() const
+    {
+      return iterator(r_map);
+    }
+
+    iterator end() const
+    {
+      return iterator(NULL);
+    }
+
   private:
     /* Version number of the protocol. */
     int r_version;
 
     /* Head of the linked list of loaded objects. */
     struct link_map *r_map;
 
     /* Function to be called when updates to the linked list of loaded objects
@@ -396,16 +451,17 @@ private:
     /* Indicates to the debugger what state the linked list of loaded objects
      * is in when the function above is called. */
     enum {
       RT_CONSISTENT, /* Changes are complete */
       RT_ADD,        /* Beginning to add a new object */
       RT_DELETE      /* Beginning to remove an object */
     } r_state;
   };
+  friend int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data);
   r_debug *dbg;
 
   /**
    * Initializes the pointer to the debugger data structure.
    */
   void InitDebugger();
 };
 
copy from mozglue/linker/CustomElf.h
copy to mozglue/linker/Elfxx.h
--- a/mozglue/linker/CustomElf.h
+++ b/mozglue/linker/Elfxx.h
@@ -1,27 +1,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef CustomElf_h
-#define CustomElf_h
+#ifndef Elfxx_h
+#define Elfxx_h
 
 /**
  * Android system headers have two different elf.h file. The one under linux/
  * is the most complete.
  */
 #ifdef ANDROID
 #include <linux/elf.h>
 #else
 #include <elf.h>
 #endif
 #include <endian.h>
-#include "ElfLoader.h"
-#include "Logging.h"
 
 /**
  * Generic ELF macros for the target system
  */
 #ifdef HAVE_64BIT_OS
 #define Elf_(type) Elf64_ ## type
 #define ELFCLASS ELFCLASS64
 #define ELF_R_TYPE ELF64_R_TYPE
@@ -168,16 +166,17 @@ namespace Elf {
 /**
  * Define a few basic Elf Types
  */
 typedef Elf_(Phdr) Phdr;
 typedef Elf_(Dyn) Dyn;
 typedef Elf_(Sym) Sym;
 typedef Elf_(Addr) Addr;
 typedef Elf_(Word) Word;
+typedef Elf_(Half) Half;
 
 /**
  * Helper class around the standard Elf header struct
  */
 struct Ehdr: public Elf_(Ehdr)
 {
   /**
    * Equivalent to reinterpret_cast<const Ehdr *>(buf), but additionally
@@ -229,188 +228,9 @@ struct Rela: public Elf_(Rela)
   Addr GetAddend(void *base) const
   {
     return r_addend;
   }
 };
 
 } /* namespace Elf */
 
-class Mappable;
-
-/**
- * Library Handle class for ELF libraries we don't let the system linker
- * handle.
- */
-class CustomElf: public LibHandle, private ElfLoader::link_map
-{
-  friend class ElfLoader;
-  friend class SEGVHandler;
-public:
-  /**
-   * Returns a new CustomElf using the given file descriptor to map ELF
-   * content. The file descriptor ownership is stolen, and it will be closed
-   * in CustomElf's destructor if an instance is created, or by the Load
-   * method otherwise. The path corresponds to the file descriptor, and flags
-   * are the same kind of flags that would be given to dlopen(), though
-   * currently, none are supported and the behaviour is more or less that of
-   * RTLD_GLOBAL | RTLD_BIND_NOW.
-   */
-  static mozilla::TemporaryRef<LibHandle> Load(Mappable *mappable,
-                                               const char *path, int flags);
-
-  /**
-   * Inherited from LibHandle
-   */
-  virtual ~CustomElf();
-  virtual void *GetSymbolPtr(const char *symbol) const;
-  virtual bool Contains(void *addr) const;
-
-  /**
-   * Shows some stats about the Mappable instance. The when argument is to be
-   * used by the caller to give an identifier of the when the stats call is
-   * made.
-   */
-  void stats(const char *when) const;
-
-private:
-  /**
-   * Returns a pointer to the Elf Symbol in the Dynamic Symbol table
-   * corresponding to the given symbol name (with a pre-computed hash).
-   */
-  const Elf::Sym *GetSymbol(const char *symbol, unsigned long hash) const;
-
-  /**
-   * Returns the address corresponding to the given symbol name (with a
-   * pre-computed hash).
-   */
-  void *GetSymbolPtr(const char *symbol, unsigned long hash) const;
-
-  /**
-   * Scan dependent libraries to find the address corresponding to the
-   * given symbol name. This is used to find symbols that are undefined
-   * in the Elf object.
-   */
-  void *GetSymbolPtrInDeps(const char *symbol) const;
-
-  /**
-   * Private constructor
-   */
-  CustomElf(Mappable *mappable, const char *path)
-  : LibHandle(path), mappable(mappable), init(0), fini(0), initialized(false)
-  { }
-
-  /**
-   * Returns a pointer relative to the base address where the library is
-   * loaded.
-   */
-  void *GetPtr(const Elf::Addr offset) const
-  {
-    return base + offset;
-  }
-
-  /**
-   * Like the above, but returns a typed (const) pointer
-   */
-  template <typename T>
-  const T *GetPtr(const Elf::Addr offset) const
-  {
-    return reinterpret_cast<const T *>(base + offset);
-  }
-
-  /**
-   * Loads an Elf segment defined by the given PT_LOAD header.
-   * Returns whether this succeeded or failed.
-   */
-  bool LoadSegment(const Elf::Phdr *pt_load) const;
-
-  /**
-   * Initializes the library according to information found in the given
-   * PT_DYNAMIC header.
-   * Returns whether this succeeded or failed.
-   */
-  bool InitDyn(const Elf::Phdr *pt_dyn);
-
-  /**
-   * Apply .rel.dyn/.rela.dyn relocations.
-   * Returns whether this succeeded or failed.
-   */
-  bool Relocate();
-
-  /**
-   * Apply .rel.plt/.rela.plt relocations.
-   * Returns whether this succeeded or failed.
-   */
-  bool RelocateJumps();
-
-  /**
-   * Call initialization functions (.init/.init_array)
-   * Returns true;
-   */
-  bool CallInit();
-
-  /**
-   * Call destructor functions (.fini_array/.fini)
-   * Returns whether this succeeded or failed.
-   */
-  void CallFini();
-
-  /**
-   * Call a function given a pointer to its location.
-   */
-  void CallFunction(void *ptr) const
-  {
-    /* C++ doesn't allow direct conversion between pointer-to-object
-     * and pointer-to-function. */
-    union {
-      void *ptr;
-      void (*func)(void);
-    } f;
-    f.ptr = ptr;
-    debug("%s: Calling function @%p", GetPath(), ptr);
-    f.func();
-  }
-
-  /**
-   * Call a function given a an address relative to the library base
-   */
-  void CallFunction(Elf::Addr addr) const
-  {
-    return CallFunction(GetPtr(addr));
-  }
-
-  /* Appropriated Mappable */
-  Mappable *mappable;
-
-  /* Base address where the library is loaded */
-  MappedPtr base;
-
-  /* String table */
-  Elf::Strtab strtab;
-
-  /* Symbol table */
-  UnsizedArray<Elf::Sym> symtab;
-
-  /* Buckets and chains for the System V symbol hash table */
-  Array<Elf::Word> buckets;
-  UnsizedArray<Elf::Word> chains;
-
-  /* List of dependent libraries */
-  std::vector<mozilla::RefPtr<LibHandle> > dependencies;
-
-  /* List of .rel.dyn/.rela.dyn relocations */
-  Array<Elf::Reloc> relocations;
-
-  /* List of .rel.plt/.rela.plt relocation */
-  Array<Elf::Reloc> jumprels;
-
-  /* Relative address of the initialization and destruction functions
-   * (.init/.fini) */
-  Elf::Addr init, fini;
-
-  /* List of initialization and destruction functions
-   * (.init_array/.fini_array) */
-  Array<void *> init_array, fini_array;
-
-  bool initialized;
-};
-
-#endif /* CustomElf_h */
+#endif /* Elfxx_h */