Bug 1822331 [wpt PR 38990] - [@scope] Enable implicit :scope and relative selectors...
[gecko.git] / mozglue / linker / ElfLoader.h
blob059c092f6d80fe8156310ac529c08a9a810960e5
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/Atomics.h"
12 #include "mozilla/RefCounted.h"
13 #include "mozilla/RefPtr.h"
14 #include "mozilla/UniquePtr.h"
15 #include "Zip.h"
16 #include "Elfxx.h"
17 #include "Mappable.h"
19 /**
20 * dlfcn.h replacement functions
22 extern "C" {
23 void* __wrap_dlopen(const char* path, int flags);
24 const char* __wrap_dlerror(void);
25 void* __wrap_dlsym(void* handle, const char* symbol);
26 int __wrap_dlclose(void* handle);
28 #ifndef HAVE_DLADDR
29 typedef struct {
30 const char* dli_fname;
31 void* dli_fbase;
32 const char* dli_sname;
33 void* dli_saddr;
34 } Dl_info;
35 #endif
36 int __wrap_dladdr(const void* addr, Dl_info* info);
38 struct dl_phdr_info {
39 Elf::Addr dlpi_addr;
40 const char* dlpi_name;
41 const Elf::Phdr* dlpi_phdr;
42 Elf::Half dlpi_phnum;
45 typedef int (*dl_phdr_cb)(struct dl_phdr_info*, size_t, void*);
46 int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void* data);
48 #ifdef __ARM_EABI__
49 const void* __wrap___gnu_Unwind_Find_exidx(void* pc, int* pcount);
50 #endif
52 /**
53 * faulty.lib public API
55 MFBT_API size_t __dl_get_mappable_length(void* handle);
57 MFBT_API void* __dl_mmap(void* handle, void* addr, size_t length, off_t offset);
59 MFBT_API void __dl_munmap(void* handle, void* addr, size_t length);
61 MFBT_API bool IsSignalHandlingBroken();
64 /* Forward declarations for use in LibHandle */
65 class BaseElf;
66 class CustomElf;
67 class SystemElf;
69 /**
70 * Specialize RefCounted template for LibHandle. We may get references to
71 * LibHandles during the execution of their destructor, so we need
72 * RefCounted<LibHandle>::Release to support some reentrancy. See further
73 * below.
75 class LibHandle;
77 namespace mozilla {
78 namespace detail {
80 template <>
81 inline void RefCounted<LibHandle, AtomicRefCount>::Release() const;
83 #ifdef DEBUG
84 template <>
85 inline RefCounted<LibHandle, AtomicRefCount>::~RefCounted() {
86 MOZ_ASSERT(mRefCnt == 0x7fffdead);
88 #endif
90 } /* namespace detail */
91 } /* namespace mozilla */
93 /**
94 * Abstract class for loaded libraries. Libraries may be loaded through the
95 * system linker or this linker, both cases will be derived from this class.
97 class LibHandle : public mozilla::external::AtomicRefCounted<LibHandle> {
98 public:
99 MOZ_DECLARE_REFCOUNTED_TYPENAME(LibHandle)
101 * Constructor. Takes the path of the loaded library and will store a copy
102 * of the leaf name.
104 LibHandle(const char* path)
105 : directRefCnt(0),
106 path(path ? strdup(path) : nullptr),
107 mappable(nullptr) {}
110 * Destructor.
112 virtual ~LibHandle();
115 * Returns the pointer to the address to which the given symbol resolves
116 * inside the library. It is not supposed to resolve the symbol in other
117 * libraries, although in practice, it will for system libraries.
119 virtual void* GetSymbolPtr(const char* symbol) const = 0;
122 * Returns whether the given address is part of the virtual address space
123 * covered by the loaded library.
125 virtual bool Contains(void* addr) const = 0;
128 * Returns the base address of the loaded library.
130 virtual void* GetBase() const = 0;
133 * Returns the file name of the library without the containing directory.
135 const char* GetName() const;
138 * Returns the full path of the library, when available. Otherwise, returns
139 * the file name.
141 const char* GetPath() const { return path; }
144 * Library handles can be referenced from other library handles or
145 * externally (when dlopen()ing using this linker). We need to be
146 * able to distinguish between the two kind of referencing for better
147 * bookkeeping.
149 void AddDirectRef() {
150 mozilla::external::AtomicRefCounted<LibHandle>::AddRef();
151 ++directRefCnt;
155 * Releases a direct reference, and returns whether there are any direct
156 * references left.
158 bool ReleaseDirectRef() {
159 const MozRefCountType count = --directRefCnt;
160 MOZ_ASSERT(count + 1 > 0);
161 MOZ_ASSERT(count + 1 <=
162 mozilla::external::AtomicRefCounted<LibHandle>::refCount());
163 mozilla::external::AtomicRefCounted<LibHandle>::Release();
164 return !!count;
168 * Returns the number of direct references
170 MozRefCountType DirectRefCount() { return directRefCnt; }
173 * Returns the complete size of the file or stream behind the library
174 * handle.
176 size_t GetMappableLength() const;
179 * Returns a memory mapping of the file or stream behind the library
180 * handle.
182 void* MappableMMap(void* addr, size_t length, off_t offset) const;
185 * Unmaps a memory mapping of the file or stream behind the library
186 * handle.
188 void MappableMUnmap(void* addr, size_t length) const;
190 #ifdef __ARM_EABI__
192 * Find the address and entry count of the ARM.exidx section
193 * associated with the library
195 virtual const void* FindExidx(int* pcount) const = 0;
196 #endif
198 protected:
200 * Returns a mappable object for use by MappableMMap and related functions.
202 virtual Mappable* GetMappable() const = 0;
205 * Returns the instance, casted as the wanted type. Returns nullptr if
206 * that's not the actual type. (short of a better way to do this without
207 * RTTI)
209 friend class ElfLoader;
210 friend class CustomElf;
211 friend class SEGVHandler;
212 friend int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void* data);
213 virtual BaseElf* AsBaseElf() { return nullptr; }
214 virtual SystemElf* AsSystemElf() { return nullptr; }
216 private:
217 mozilla::Atomic<MozRefCountType> directRefCnt;
218 char* path;
220 /* Mappable object keeping the result of GetMappable() */
221 mutable RefPtr<Mappable> mappable;
225 * Specialized RefCounted<LibHandle>::Release. Under normal operation, when
226 * mRefCnt reaches 0, the LibHandle is deleted. Its mRefCnt is however
227 * increased to 1 on normal builds, and 0x7fffdead on debug builds so that the
228 * LibHandle can still be referenced while the destructor is executing. The
229 * mRefCnt is allowed to grow > 0x7fffdead, but not to decrease under that
230 * value, which would mean too many Releases from within the destructor.
232 namespace mozilla {
233 namespace detail {
235 template <>
236 inline void RefCounted<LibHandle, AtomicRefCount>::Release() const {
237 #ifdef DEBUG
238 if (mRefCnt > 0x7fff0000) MOZ_ASSERT(mRefCnt > 0x7fffdead);
239 #endif
240 MOZ_ASSERT(mRefCnt > 0);
241 if (mRefCnt > 0) {
242 if (0 == --mRefCnt) {
243 #ifdef DEBUG
244 mRefCnt = 0x7fffdead;
245 #else
246 ++mRefCnt;
247 #endif
248 delete static_cast<const LibHandle*>(this);
253 } /* namespace detail */
254 } /* namespace mozilla */
257 * Class handling libraries loaded by the system linker
259 class SystemElf : public LibHandle {
260 public:
262 * Returns a new SystemElf for the given path. The given flags are passed
263 * to dlopen().
265 static already_AddRefed<LibHandle> Load(const char* path, int flags);
268 * Inherited from LibHandle
270 virtual ~SystemElf();
271 virtual void* GetSymbolPtr(const char* symbol) const;
272 virtual bool Contains(void* addr) const { return false; /* UNIMPLEMENTED */ }
273 virtual void* GetBase() const { return nullptr; /* UNIMPLEMENTED */ }
275 #ifdef __ARM_EABI__
276 virtual const void* FindExidx(int* pcount) const;
277 #endif
279 protected:
280 virtual Mappable* GetMappable() const;
283 * Returns the instance, casted as SystemElf. (short of a better way to do
284 * this without RTTI)
286 friend class ElfLoader;
287 virtual SystemElf* AsSystemElf() { return this; }
290 * Remove the reference to the system linker handle. This avoids dlclose()
291 * being called when the instance is destroyed.
293 void Forget() { dlhandle = nullptr; }
295 private:
297 * Private constructor
299 SystemElf(const char* path, void* handle)
300 : LibHandle(path), dlhandle(handle) {}
302 /* Handle as returned by system dlopen() */
303 void* dlhandle;
307 * The ElfLoader registers its own SIGSEGV handler to handle segmentation
308 * faults within the address space of the loaded libraries. It however
309 * allows a handler to be set for faults in other places, and redispatches
310 * to the handler set through signal() or sigaction().
312 class SEGVHandler {
313 public:
314 bool hasRegisteredHandler() {
315 if (!initialized) FinishInitialization();
316 return registeredHandler;
319 bool isSignalHandlingBroken() { return signalHandlingBroken; }
321 static int __wrap_sigaction(int signum, const struct sigaction* act,
322 struct sigaction* oldact);
324 protected:
325 SEGVHandler();
326 ~SEGVHandler();
328 private:
330 * The constructor doesn't do all initialization, and the tail is done
331 * at a later time.
333 void FinishInitialization();
336 * SIGSEGV handler registered with __wrap_signal or __wrap_sigaction.
338 struct sigaction action;
341 * ElfLoader SIGSEGV handler.
343 static void handler(int signum, siginfo_t* info, void* context);
346 * Temporary test handler.
348 static void test_handler(int signum, siginfo_t* info, void* context);
351 * Size of the alternative stack. The printf family requires more than 8KB
352 * of stack, and our signal handler may print a few things.
354 static const size_t stackSize = 12 * 1024;
357 * Alternative stack information used before initialization.
359 stack_t oldStack;
362 * Pointer to an alternative stack for signals. Only set if oldStack is
363 * not set or not big enough.
365 MappedPtr stackPtr;
367 bool initialized;
368 bool registeredHandler;
369 bool signalHandlingBroken;
370 bool signalHandlingSlow;
374 * Elf Loader class in charge of loading and bookkeeping libraries.
376 class ElfLoader : public SEGVHandler {
377 public:
379 * The Elf Loader instance
381 static ElfLoader Singleton;
384 * Loads the given library with the given flags. Equivalent to dlopen()
385 * The extra "parent" argument optionally gives the handle of the library
386 * requesting the given library to be loaded. The loader may look in the
387 * directory containing that parent library for the library to load.
389 already_AddRefed<LibHandle> Load(const char* path, int flags,
390 LibHandle* parent = nullptr);
393 * Returns the handle of the library containing the given address in
394 * its virtual address space, i.e. the library handle for which
395 * LibHandle::Contains returns true. Its purpose is to allow to
396 * implement dladdr().
398 already_AddRefed<LibHandle> GetHandleByPtr(void* addr);
401 * Returns a Mappable object for the path. Paths in the form
402 * /foo/bar/baz/archive!/directory/lib.so
403 * try to load the directory/lib.so in /foo/bar/baz/archive, provided
404 * that file is a Zip archive.
406 static Mappable* GetMappableFromPath(const char* path);
408 void ExpectShutdown(bool val) { expect_shutdown = val; }
409 bool IsShutdownExpected() { return expect_shutdown; }
411 private:
412 bool expect_shutdown;
414 protected:
416 * Registers the given handle. This method is meant to be called by
417 * LibHandle subclass creators.
419 void Register(LibHandle* handle);
420 void Register(CustomElf* handle);
423 * Forget about the given handle. This method is meant to be called by
424 * LibHandle subclass destructors.
426 void Forget(LibHandle* handle);
427 void Forget(CustomElf* handle);
429 friend class SystemElf;
430 friend const char* __wrap_dlerror(void);
431 friend void* __wrap_dlsym(void* handle, const char* symbol);
432 friend int __wrap_dlclose(void* handle);
433 /* __wrap_dlerror() returns this custom last error if non-null or the system
434 * dlerror() value if this is null. Must refer to a string constant. */
435 mozilla::Atomic<const char*, mozilla::Relaxed> lastError;
437 private:
438 ElfLoader() : expect_shutdown(true), lastError(nullptr) {
439 pthread_mutex_init(&handlesMutex, nullptr);
442 ~ElfLoader();
444 /* Initialization code that can't run during static initialization. */
445 void Init();
447 /* System loader handle for the library/program containing our code. This
448 * is used to resolve wrapped functions. */
449 RefPtr<LibHandle> self_elf;
451 #if defined(ANDROID)
452 /* System loader handle for the libc. This is used to resolve weak symbols
453 * that some libcs contain that the Android linker won't dlsym(). Normally,
454 * we wouldn't treat non-Android differently, but glibc uses versioned
455 * symbols which this linker doesn't support. */
456 RefPtr<LibHandle> libc;
458 /* And for libm. */
459 RefPtr<LibHandle> libm;
460 #endif
462 /* Bookkeeping */
463 typedef std::vector<LibHandle*> LibHandleList;
464 LibHandleList handles;
466 pthread_mutex_t handlesMutex;
468 protected:
469 friend class CustomElf;
470 friend class LoadedElf;
472 /* Definition of static destructors as to be used for C++ ABI compatibility */
473 typedef void (*Destructor)(void* object);
476 * C++ ABI makes static initializers register destructors through a specific
477 * atexit interface. On glibc/linux systems, the dso_handle is a pointer
478 * within a given library. On bionic/android systems, it is an undefined
479 * symbol. Making sense of the value is not really important, and all that
480 * is really important is that it is different for each loaded library, so
481 * that they can be discriminated when shutting down. For convenience, on
482 * systems where the dso handle is a symbol, that symbol is resolved to
483 * point at corresponding CustomElf.
485 * Destructors are registered with __*_atexit with an associated object to
486 * be passed as argument when it is called.
488 * When __cxa_finalize is called, destructors registered for the given
489 * DSO handle are called in the reverse order they were registered.
491 #ifdef __ARM_EABI__
492 static int __wrap_aeabi_atexit(void* that, Destructor destructor,
493 void* dso_handle);
494 #else
495 static int __wrap_cxa_atexit(Destructor destructor, void* that,
496 void* dso_handle);
497 #endif
499 static void __wrap_cxa_finalize(void* dso_handle);
502 * Registered destructor. Keeps track of the destructor function pointer,
503 * associated object to call it with, and DSO handle.
505 class DestructorCaller {
506 public:
507 DestructorCaller(Destructor destructor, void* object, void* dso_handle)
508 : destructor(destructor), object(object), dso_handle(dso_handle) {}
511 * Call the destructor function with the associated object.
512 * Call only once, see CustomElf::~CustomElf.
514 void Call();
517 * Returns whether the destructor is associated to the given DSO handle
519 bool IsForHandle(void* handle) const { return handle == dso_handle; }
521 private:
522 Destructor destructor;
523 void* object;
524 void* dso_handle;
527 private:
528 /* Keep track of all registered destructors */
529 std::vector<DestructorCaller> destructors;
531 /* Forward declaration, see further below */
532 class DebuggerHelper;
534 public:
535 /* Loaded object descriptor for the debugger interface below*/
536 struct link_map {
537 /* Base address of the loaded object. */
538 const void* l_addr;
539 /* File name */
540 const char* l_name;
541 /* Address of the PT_DYNAMIC segment. */
542 const void* l_ld;
544 private:
545 friend class ElfLoader::DebuggerHelper;
546 /* Double linked list of loaded objects. */
547 link_map *l_next, *l_prev;
550 private:
551 /* Data structure used by the linker to give details about shared objects it
552 * loaded to debuggers. This is normally defined in link.h, but Android
553 * headers lack this file. */
554 struct r_debug {
555 /* Version number of the protocol. */
556 int r_version;
558 /* Head of the linked list of loaded objects. */
559 link_map* r_map;
561 /* Function to be called when updates to the linked list of loaded objects
562 * are going to occur. The function is to be called before and after
563 * changes. */
564 void (*r_brk)(void);
566 /* Indicates to the debugger what state the linked list of loaded objects
567 * is in when the function above is called. */
568 enum {
569 RT_CONSISTENT, /* Changes are complete */
570 RT_ADD, /* Beginning to add a new object */
571 RT_DELETE /* Beginning to remove an object */
572 } r_state;
575 /* Memory representation of ELF Auxiliary Vectors */
576 struct AuxVector {
577 Elf::Addr type;
578 Elf::Addr value;
581 /* Helper class used to integrate libraries loaded by this linker in
582 * r_debug */
583 class DebuggerHelper {
584 public:
585 DebuggerHelper();
587 void Init(AuxVector* auvx);
589 explicit operator bool() { return dbg; }
591 /* Make the debugger aware of a new loaded object */
592 void Add(link_map* map);
594 /* Make the debugger aware of the unloading of an object */
595 void Remove(link_map* map);
597 /* Iterates over all link_maps */
598 class iterator {
599 public:
600 const link_map* operator->() const { return item; }
602 const link_map& operator++() {
603 item = item->l_next;
604 return *item;
607 bool operator<(const iterator& other) const {
608 if (other.item == nullptr) return item ? true : false;
609 MOZ_CRASH(
610 "DebuggerHelper::iterator::operator< called with something else "
611 "than DebuggerHelper::end()");
614 protected:
615 friend class DebuggerHelper;
616 explicit iterator(const link_map* item) : item(item) {}
618 private:
619 const link_map* item;
622 iterator begin() const { return iterator(dbg ? dbg->r_map : nullptr); }
624 iterator end() const { return iterator(nullptr); }
626 private:
627 r_debug* dbg;
628 link_map* firstAdded;
630 friend int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void* data);
631 DebuggerHelper dbg;
634 #endif /* ElfLoader_h */