Thu, 22 Jan 2015 13:21:57 +0100
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 */