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 92419 bb9548c09c19162b5afc66c878de6b49cac0a74c
parent 92418 864ae3bff0b22d6e5edf74f36bfd3d0d77844b9a
child 92420 77e68aa8f24c8da77d4ff7e3c1346394d92c3e05
push id712
push usertim.taubert@gmx.de
push dateFri, 27 Apr 2012 12:45:49 +0000
treeherderfx-team@0f8ea3826bf7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs747033
milestone15.0a1
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 */