mozglue/linker/ElfLoader.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #ifndef ElfLoader_h
     6 #define ElfLoader_h
     8 #include <vector>
     9 #include <dlfcn.h>
    10 #include <signal.h>
    11 #include "mozilla/RefPtr.h"
    12 #include "Zip.h"
    13 #include "Elfxx.h"
    14 #include "Mappable.h"
    16 /**
    17  * dlfcn.h replacement functions
    18  */
    19 extern "C" {
    20   void *__wrap_dlopen(const char *path, int flags);
    21   const char *__wrap_dlerror(void);
    22   void *__wrap_dlsym(void *handle, const char *symbol);
    23   int __wrap_dlclose(void *handle);
    25 #ifndef HAVE_DLADDR
    26   typedef struct {
    27     const char *dli_fname;
    28     void *dli_fbase;
    29     const char *dli_sname;
    30     void *dli_saddr;
    31   } Dl_info;
    32 #endif
    33   int __wrap_dladdr(void *addr, Dl_info *info);
    35   struct dl_phdr_info {
    36     Elf::Addr dlpi_addr;
    37     const char *dlpi_name;
    38     const Elf::Phdr *dlpi_phdr;
    39     Elf::Half dlpi_phnum;
    40   };
    42   typedef int (*dl_phdr_cb)(struct dl_phdr_info *, size_t, void *);
    43   int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data);
    45 #ifdef __ARM_EABI__
    46   const void *__wrap___gnu_Unwind_Find_exidx(void *pc, int *pcount);
    47 #endif
    49 /**
    50  * faulty.lib public API
    51  */
    52 MFBT_API size_t
    53 __dl_get_mappable_length(void *handle);
    55 MFBT_API void *
    56 __dl_mmap(void *handle, void *addr, size_t length, off_t offset);
    58 MFBT_API void
    59 __dl_munmap(void *handle, void *addr, size_t length);
    61 MFBT_API bool
    62 IsSignalHandlingBroken();
    64 }
    66 /**
    67  * Specialize RefCounted template for LibHandle. We may get references to
    68  * LibHandles during the execution of their destructor, so we need
    69  * RefCounted<LibHandle>::Release to support some reentrancy. See further
    70  * below.
    71  */
    72 class LibHandle;
    74 namespace mozilla {
    75 namespace detail {
    77 template <> inline void RefCounted<LibHandle, AtomicRefCount>::Release() const;
    79 template <> inline RefCounted<LibHandle, AtomicRefCount>::~RefCounted()
    80 {
    81   MOZ_ASSERT(refCnt == 0x7fffdead);
    82 }
    84 } /* namespace detail */
    85 } /* namespace mozilla */
    87 /**
    88  * Abstract class for loaded libraries. Libraries may be loaded through the
    89  * system linker or this linker, both cases will be derived from this class.
    90  */
    91 class LibHandle: public mozilla::AtomicRefCounted<LibHandle>
    92 {
    93 public:
    94   MOZ_DECLARE_REFCOUNTED_TYPENAME(LibHandle)
    95   /**
    96    * Constructor. Takes the path of the loaded library and will store a copy
    97    * of the leaf name.
    98    */
    99   LibHandle(const char *path)
   100   : directRefCnt(0), path(path ? strdup(path) : nullptr), mappable(nullptr) { }
   102   /**
   103    * Destructor.
   104    */
   105   virtual ~LibHandle();
   107   /**
   108    * Returns the pointer to the address to which the given symbol resolves
   109    * inside the library. It is not supposed to resolve the symbol in other
   110    * libraries, although in practice, it will for system libraries.
   111    */
   112   virtual void *GetSymbolPtr(const char *symbol) const = 0;
   114   /**
   115    * Returns whether the given address is part of the virtual address space
   116    * covered by the loaded library.
   117    */
   118   virtual bool Contains(void *addr) const = 0;
   120   /**
   121    * Returns the file name of the library without the containing directory.
   122    */
   123   const char *GetName() const;
   125   /**
   126    * Returns the full path of the library, when available. Otherwise, returns
   127    * the file name.
   128    */
   129   const char *GetPath() const
   130   {
   131     return path;
   132   }
   134   /**
   135    * Library handles can be referenced from other library handles or
   136    * externally (when dlopen()ing using this linker). We need to be
   137    * able to distinguish between the two kind of referencing for better
   138    * bookkeeping.
   139    */
   140   void AddDirectRef()
   141   {
   142     ++directRefCnt;
   143     mozilla::AtomicRefCounted<LibHandle>::AddRef();
   144   }
   146   /**
   147    * Releases a direct reference, and returns whether there are any direct
   148    * references left.
   149    */
   150   bool ReleaseDirectRef()
   151   {
   152     bool ret = false;
   153     if (directRefCnt) {
   154       MOZ_ASSERT(directRefCnt <=
   155                  mozilla::AtomicRefCounted<LibHandle>::refCount());
   156       if (--directRefCnt)
   157         ret = true;
   158       mozilla::AtomicRefCounted<LibHandle>::Release();
   159     }
   160     return ret;
   161   }
   163   /**
   164    * Returns the number of direct references
   165    */
   166   MozRefCountType DirectRefCount()
   167   {
   168     return directRefCnt;
   169   }
   171   /**
   172    * Returns the complete size of the file or stream behind the library
   173    * handle.
   174    */
   175   size_t GetMappableLength() const;
   177   /**
   178    * Returns a memory mapping of the file or stream behind the library
   179    * handle.
   180    */
   181   void *MappableMMap(void *addr, size_t length, off_t offset) const;
   183   /**
   184    * Unmaps a memory mapping of the file or stream behind the library
   185    * handle.
   186    */
   187   void MappableMUnmap(void *addr, size_t length) const;
   189 #ifdef __ARM_EABI__
   190   /**
   191    * Find the address and entry count of the ARM.exidx section
   192    * associated with the library
   193    */
   194   virtual const void *FindExidx(int *pcount) const = 0;
   195 #endif
   197 protected:
   198   /**
   199    * Returns a mappable object for use by MappableMMap and related functions.
   200    */
   201   virtual Mappable *GetMappable() const = 0;
   203   /**
   204    * Returns whether the handle is a SystemElf or not. (short of a better way
   205    * to do this without RTTI)
   206    */
   207   friend class ElfLoader;
   208   friend class CustomElf;
   209   friend class SEGVHandler;
   210   virtual bool IsSystemElf() const { return false; }
   212 private:
   213   MozRefCountType directRefCnt;
   214   char *path;
   216   /* Mappable object keeping the result of GetMappable() */
   217   mutable mozilla::RefPtr<Mappable> mappable;
   218 };
   220 /**
   221  * Specialized RefCounted<LibHandle>::Release. Under normal operation, when
   222  * refCnt reaches 0, the LibHandle is deleted. Its refCnt is however increased
   223  * to 1 on normal builds, and 0x7fffdead on debug builds so that the LibHandle
   224  * can still be referenced while the destructor is executing. The refCnt is
   225  * allowed to grow > 0x7fffdead, but not to decrease under that value, which
   226  * would mean too many Releases from within the destructor.
   227  */
   228 namespace mozilla {
   229 namespace detail {
   231 template <> inline void RefCounted<LibHandle, AtomicRefCount>::Release() const {
   232 #ifdef DEBUG
   233   if (refCnt > 0x7fff0000)
   234     MOZ_ASSERT(refCnt > 0x7fffdead);
   235 #endif
   236   MOZ_ASSERT(refCnt > 0);
   237   if (refCnt > 0) {
   238     if (0 == --refCnt) {
   239 #ifdef DEBUG
   240       refCnt = 0x7fffdead;
   241 #else
   242       refCnt = 1;
   243 #endif
   244       delete static_cast<const LibHandle*>(this);
   245     }
   246   }
   247 }
   249 } /* namespace detail */
   250 } /* namespace mozilla */
   252 /**
   253  * Class handling libraries loaded by the system linker
   254  */
   255 class SystemElf: public LibHandle
   256 {
   257 public:
   258   /**
   259    * Returns a new SystemElf for the given path. The given flags are passed
   260    * to dlopen().
   261    */
   262   static mozilla::TemporaryRef<LibHandle> Load(const char *path, int flags);
   264   /**
   265    * Inherited from LibHandle
   266    */
   267   virtual ~SystemElf();
   268   virtual void *GetSymbolPtr(const char *symbol) const;
   269   virtual bool Contains(void *addr) const { return false; /* UNIMPLEMENTED */ }
   271 #ifdef __ARM_EABI__
   272   virtual const void *FindExidx(int *pcount) const;
   273 #endif
   275 protected:
   276   virtual Mappable *GetMappable() const;
   278   /**
   279    * Returns whether the handle is a SystemElf or not. (short of a better way
   280    * to do this without RTTI)
   281    */
   282   friend class ElfLoader;
   283   virtual bool IsSystemElf() const { return true; }
   285   /**
   286    * Remove the reference to the system linker handle. This avoids dlclose()
   287    * being called when the instance is destroyed.
   288    */
   289   void Forget()
   290   {
   291     dlhandle = nullptr;
   292   }
   294 private:
   295   /**
   296    * Private constructor
   297    */
   298   SystemElf(const char *path, void *handle)
   299   : LibHandle(path), dlhandle(handle) { }
   301   /* Handle as returned by system dlopen() */
   302   void *dlhandle;
   303 };
   305 /**
   306  * The ElfLoader registers its own SIGSEGV handler to handle segmentation
   307  * faults within the address space of the loaded libraries. It however
   308  * allows a handler to be set for faults in other places, and redispatches
   309  * to the handler set through signal() or sigaction().
   310  */
   311 class SEGVHandler
   312 {
   313 public:
   314   bool hasRegisteredHandler() {
   315     return registeredHandler;
   316   }
   318   bool isSignalHandlingBroken() {
   319     return signalHandlingBroken;
   320   }
   322 protected:
   323   SEGVHandler();
   324   ~SEGVHandler();
   326 private:
   327   static int __wrap_sigaction(int signum, const struct sigaction *act,
   328                               struct sigaction *oldact);
   330   /**
   331    * SIGSEGV handler registered with __wrap_signal or __wrap_sigaction.
   332    */
   333   struct sigaction action;
   335   /**
   336    * ElfLoader SIGSEGV handler.
   337    */
   338   static void handler(int signum, siginfo_t *info, void *context);
   340   /**
   341    * Temporary test handler.
   342    */
   343   static void test_handler(int signum, siginfo_t *info, void *context);
   345   /**
   346    * Size of the alternative stack. The printf family requires more than 8KB
   347    * of stack, and our signal handler may print a few things.
   348    */
   349   static const size_t stackSize = 12 * 1024;
   351   /**
   352    * Alternative stack information used before initialization.
   353    */
   354   stack_t oldStack;
   356   /**
   357    * Pointer to an alternative stack for signals. Only set if oldStack is
   358    * not set or not big enough.
   359    */
   360   MappedPtr stackPtr;
   362   bool registeredHandler;
   363   bool signalHandlingBroken;
   364   bool signalHandlingSlow;
   365 };
   367 /**
   368  * Elf Loader class in charge of loading and bookkeeping libraries.
   369  */
   370 class ElfLoader: public SEGVHandler
   371 {
   372 public:
   373   /**
   374    * The Elf Loader instance
   375    */
   376   static ElfLoader Singleton;
   378   /**
   379    * Loads the given library with the given flags. Equivalent to dlopen()
   380    * The extra "parent" argument optionally gives the handle of the library
   381    * requesting the given library to be loaded. The loader may look in the
   382    * directory containing that parent library for the library to load.
   383    */
   384   mozilla::TemporaryRef<LibHandle> Load(const char *path, int flags,
   385                                         LibHandle *parent = nullptr);
   387   /**
   388    * Returns the handle of the library containing the given address in
   389    * its virtual address space, i.e. the library handle for which
   390    * LibHandle::Contains returns true. Its purpose is to allow to
   391    * implement dladdr().
   392    */
   393   mozilla::TemporaryRef<LibHandle> GetHandleByPtr(void *addr);
   395   /**
   396    * Returns a Mappable object for the path. Paths in the form
   397    *   /foo/bar/baz/archive!/directory/lib.so
   398    * try to load the directory/lib.so in /foo/bar/baz/archive, provided
   399    * that file is a Zip archive.
   400    */
   401   static Mappable *GetMappableFromPath(const char *path);
   403 protected:
   404   /**
   405    * Registers the given handle. This method is meant to be called by
   406    * LibHandle subclass creators.
   407    */
   408   void Register(LibHandle *handle);
   410   /**
   411    * Forget about the given handle. This method is meant to be called by
   412    * LibHandle subclass destructors.
   413    */
   414   void Forget(LibHandle *handle);
   416   /* Last error. Used for dlerror() */
   417   friend class SystemElf;
   418   friend const char *__wrap_dlerror(void);
   419   friend void *__wrap_dlsym(void *handle, const char *symbol);
   420   friend int __wrap_dlclose(void *handle);
   421   const char *lastError;
   423 private:
   424   ~ElfLoader();
   426   /* Bookkeeping */
   427   typedef std::vector<LibHandle *> LibHandleList;
   428   LibHandleList handles;
   430 protected:
   431   friend class CustomElf;
   432   /**
   433    * Show some stats about Mappables in CustomElfs. The when argument is to
   434    * be used by the caller to give an identifier of the when the stats call
   435    * is made.
   436    */
   437   static void stats(const char *when);
   439   /* Definition of static destructors as to be used for C++ ABI compatibility */
   440   typedef void (*Destructor)(void *object);
   442   /**
   443    * C++ ABI makes static initializers register destructors through a specific
   444    * atexit interface. On glibc/linux systems, the dso_handle is a pointer
   445    * within a given library. On bionic/android systems, it is an undefined
   446    * symbol. Making sense of the value is not really important, and all that
   447    * is really important is that it is different for each loaded library, so
   448    * that they can be discriminated when shutting down. For convenience, on
   449    * systems where the dso handle is a symbol, that symbol is resolved to
   450    * point at corresponding CustomElf.
   451    *
   452    * Destructors are registered with __*_atexit with an associated object to
   453    * be passed as argument when it is called.
   454    *
   455    * When __cxa_finalize is called, destructors registered for the given
   456    * DSO handle are called in the reverse order they were registered.
   457    */
   458 #ifdef __ARM_EABI__
   459   static int __wrap_aeabi_atexit(void *that, Destructor destructor,
   460                                  void *dso_handle);
   461 #else
   462   static int __wrap_cxa_atexit(Destructor destructor, void *that,
   463                                void *dso_handle);
   464 #endif
   466   static void __wrap_cxa_finalize(void *dso_handle);
   468   /**
   469    * Registered destructor. Keeps track of the destructor function pointer,
   470    * associated object to call it with, and DSO handle.
   471    */
   472   class DestructorCaller {
   473   public:
   474     DestructorCaller(Destructor destructor, void *object, void *dso_handle)
   475     : destructor(destructor), object(object), dso_handle(dso_handle) { }
   477     /**
   478      * Call the destructor function with the associated object.
   479      * Call only once, see CustomElf::~CustomElf.
   480      */
   481     void Call();
   483     /**
   484      * Returns whether the destructor is associated to the given DSO handle
   485      */
   486     bool IsForHandle(void *handle) const
   487     {
   488       return handle == dso_handle;
   489     }
   491   private:
   492     Destructor destructor;
   493     void *object;
   494     void *dso_handle;
   495   };
   497 private:
   498   /* Keep track of all registered destructors */
   499   std::vector<DestructorCaller> destructors;
   501   /* Forward declaration, see further below */
   502   class DebuggerHelper;
   503 public:
   504   /* Loaded object descriptor for the debugger interface below*/
   505   struct link_map {
   506     /* Base address of the loaded object. */
   507     const void *l_addr;
   508     /* File name */
   509     const char *l_name;
   510     /* Address of the PT_DYNAMIC segment. */
   511     const void *l_ld;
   513   private:
   514     friend class ElfLoader::DebuggerHelper;
   515     /* Double linked list of loaded objects. */
   516     link_map *l_next, *l_prev;
   517   };
   519 private:
   520   /* Data structure used by the linker to give details about shared objects it
   521    * loaded to debuggers. This is normally defined in link.h, but Android
   522    * headers lack this file. */
   523   struct r_debug {
   524     /* Version number of the protocol. */
   525     int r_version;
   527     /* Head of the linked list of loaded objects. */
   528     link_map *r_map;
   530     /* Function to be called when updates to the linked list of loaded objects
   531      * are going to occur. The function is to be called before and after
   532      * changes. */
   533     void (*r_brk)(void);
   535     /* Indicates to the debugger what state the linked list of loaded objects
   536      * is in when the function above is called. */
   537     enum {
   538       RT_CONSISTENT, /* Changes are complete */
   539       RT_ADD,        /* Beginning to add a new object */
   540       RT_DELETE      /* Beginning to remove an object */
   541     } r_state;
   542   };
   544   /* Helper class used to integrate libraries loaded by this linker in
   545    * r_debug */
   546   class DebuggerHelper
   547   {
   548   public:
   549     DebuggerHelper();
   551     operator bool()
   552     {
   553       return dbg;
   554     }
   556     /* Make the debugger aware of a new loaded object */
   557     void Add(link_map *map);
   559     /* Make the debugger aware of the unloading of an object */
   560     void Remove(link_map *map);
   562     /* Iterates over all link_maps */
   563     class iterator
   564     {
   565     public:
   566       const link_map *operator ->() const
   567       {
   568         return item;
   569       }
   571       const link_map &operator ++()
   572       {
   573         item = item->l_next;
   574         return *item;
   575       }
   577       bool operator<(const iterator &other) const
   578       {
   579         if (other.item == nullptr)
   580           return item ? true : false;
   581         MOZ_CRASH("DebuggerHelper::iterator::operator< called with something else than DebuggerHelper::end()");
   582       }
   583     protected:
   584       friend class DebuggerHelper;
   585       iterator(const link_map *item): item(item) { }
   587     private:
   588       const link_map *item;
   589     };
   591     iterator begin() const
   592     {
   593       return iterator(dbg ? dbg->r_map : nullptr);
   594     }
   596     iterator end() const
   597     {
   598       return iterator(nullptr);
   599     }
   601   private:
   602     r_debug *dbg;
   603     link_map *firstAdded;
   604   };
   605   friend int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data);
   606   DebuggerHelper dbg;
   607 };
   609 #endif /* ElfLoader_h */

mercurial