|
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/. */ |
|
4 |
|
5 #ifndef ElfLoader_h |
|
6 #define ElfLoader_h |
|
7 |
|
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" |
|
15 |
|
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); |
|
24 |
|
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); |
|
34 |
|
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 }; |
|
41 |
|
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); |
|
44 |
|
45 #ifdef __ARM_EABI__ |
|
46 const void *__wrap___gnu_Unwind_Find_exidx(void *pc, int *pcount); |
|
47 #endif |
|
48 |
|
49 /** |
|
50 * faulty.lib public API |
|
51 */ |
|
52 MFBT_API size_t |
|
53 __dl_get_mappable_length(void *handle); |
|
54 |
|
55 MFBT_API void * |
|
56 __dl_mmap(void *handle, void *addr, size_t length, off_t offset); |
|
57 |
|
58 MFBT_API void |
|
59 __dl_munmap(void *handle, void *addr, size_t length); |
|
60 |
|
61 MFBT_API bool |
|
62 IsSignalHandlingBroken(); |
|
63 |
|
64 } |
|
65 |
|
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; |
|
73 |
|
74 namespace mozilla { |
|
75 namespace detail { |
|
76 |
|
77 template <> inline void RefCounted<LibHandle, AtomicRefCount>::Release() const; |
|
78 |
|
79 template <> inline RefCounted<LibHandle, AtomicRefCount>::~RefCounted() |
|
80 { |
|
81 MOZ_ASSERT(refCnt == 0x7fffdead); |
|
82 } |
|
83 |
|
84 } /* namespace detail */ |
|
85 } /* namespace mozilla */ |
|
86 |
|
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) { } |
|
101 |
|
102 /** |
|
103 * Destructor. |
|
104 */ |
|
105 virtual ~LibHandle(); |
|
106 |
|
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; |
|
113 |
|
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; |
|
119 |
|
120 /** |
|
121 * Returns the file name of the library without the containing directory. |
|
122 */ |
|
123 const char *GetName() const; |
|
124 |
|
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 } |
|
133 |
|
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 } |
|
145 |
|
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 } |
|
162 |
|
163 /** |
|
164 * Returns the number of direct references |
|
165 */ |
|
166 MozRefCountType DirectRefCount() |
|
167 { |
|
168 return directRefCnt; |
|
169 } |
|
170 |
|
171 /** |
|
172 * Returns the complete size of the file or stream behind the library |
|
173 * handle. |
|
174 */ |
|
175 size_t GetMappableLength() const; |
|
176 |
|
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; |
|
182 |
|
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; |
|
188 |
|
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 |
|
196 |
|
197 protected: |
|
198 /** |
|
199 * Returns a mappable object for use by MappableMMap and related functions. |
|
200 */ |
|
201 virtual Mappable *GetMappable() const = 0; |
|
202 |
|
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; } |
|
211 |
|
212 private: |
|
213 MozRefCountType directRefCnt; |
|
214 char *path; |
|
215 |
|
216 /* Mappable object keeping the result of GetMappable() */ |
|
217 mutable mozilla::RefPtr<Mappable> mappable; |
|
218 }; |
|
219 |
|
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 { |
|
230 |
|
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 } |
|
248 |
|
249 } /* namespace detail */ |
|
250 } /* namespace mozilla */ |
|
251 |
|
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); |
|
263 |
|
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 */ } |
|
270 |
|
271 #ifdef __ARM_EABI__ |
|
272 virtual const void *FindExidx(int *pcount) const; |
|
273 #endif |
|
274 |
|
275 protected: |
|
276 virtual Mappable *GetMappable() const; |
|
277 |
|
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; } |
|
284 |
|
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 } |
|
293 |
|
294 private: |
|
295 /** |
|
296 * Private constructor |
|
297 */ |
|
298 SystemElf(const char *path, void *handle) |
|
299 : LibHandle(path), dlhandle(handle) { } |
|
300 |
|
301 /* Handle as returned by system dlopen() */ |
|
302 void *dlhandle; |
|
303 }; |
|
304 |
|
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 } |
|
317 |
|
318 bool isSignalHandlingBroken() { |
|
319 return signalHandlingBroken; |
|
320 } |
|
321 |
|
322 protected: |
|
323 SEGVHandler(); |
|
324 ~SEGVHandler(); |
|
325 |
|
326 private: |
|
327 static int __wrap_sigaction(int signum, const struct sigaction *act, |
|
328 struct sigaction *oldact); |
|
329 |
|
330 /** |
|
331 * SIGSEGV handler registered with __wrap_signal or __wrap_sigaction. |
|
332 */ |
|
333 struct sigaction action; |
|
334 |
|
335 /** |
|
336 * ElfLoader SIGSEGV handler. |
|
337 */ |
|
338 static void handler(int signum, siginfo_t *info, void *context); |
|
339 |
|
340 /** |
|
341 * Temporary test handler. |
|
342 */ |
|
343 static void test_handler(int signum, siginfo_t *info, void *context); |
|
344 |
|
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; |
|
350 |
|
351 /** |
|
352 * Alternative stack information used before initialization. |
|
353 */ |
|
354 stack_t oldStack; |
|
355 |
|
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; |
|
361 |
|
362 bool registeredHandler; |
|
363 bool signalHandlingBroken; |
|
364 bool signalHandlingSlow; |
|
365 }; |
|
366 |
|
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; |
|
377 |
|
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); |
|
386 |
|
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); |
|
394 |
|
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); |
|
402 |
|
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); |
|
409 |
|
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); |
|
415 |
|
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; |
|
422 |
|
423 private: |
|
424 ~ElfLoader(); |
|
425 |
|
426 /* Bookkeeping */ |
|
427 typedef std::vector<LibHandle *> LibHandleList; |
|
428 LibHandleList handles; |
|
429 |
|
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); |
|
438 |
|
439 /* Definition of static destructors as to be used for C++ ABI compatibility */ |
|
440 typedef void (*Destructor)(void *object); |
|
441 |
|
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 |
|
465 |
|
466 static void __wrap_cxa_finalize(void *dso_handle); |
|
467 |
|
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) { } |
|
476 |
|
477 /** |
|
478 * Call the destructor function with the associated object. |
|
479 * Call only once, see CustomElf::~CustomElf. |
|
480 */ |
|
481 void Call(); |
|
482 |
|
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 } |
|
490 |
|
491 private: |
|
492 Destructor destructor; |
|
493 void *object; |
|
494 void *dso_handle; |
|
495 }; |
|
496 |
|
497 private: |
|
498 /* Keep track of all registered destructors */ |
|
499 std::vector<DestructorCaller> destructors; |
|
500 |
|
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; |
|
512 |
|
513 private: |
|
514 friend class ElfLoader::DebuggerHelper; |
|
515 /* Double linked list of loaded objects. */ |
|
516 link_map *l_next, *l_prev; |
|
517 }; |
|
518 |
|
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; |
|
526 |
|
527 /* Head of the linked list of loaded objects. */ |
|
528 link_map *r_map; |
|
529 |
|
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); |
|
534 |
|
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 }; |
|
543 |
|
544 /* Helper class used to integrate libraries loaded by this linker in |
|
545 * r_debug */ |
|
546 class DebuggerHelper |
|
547 { |
|
548 public: |
|
549 DebuggerHelper(); |
|
550 |
|
551 operator bool() |
|
552 { |
|
553 return dbg; |
|
554 } |
|
555 |
|
556 /* Make the debugger aware of a new loaded object */ |
|
557 void Add(link_map *map); |
|
558 |
|
559 /* Make the debugger aware of the unloading of an object */ |
|
560 void Remove(link_map *map); |
|
561 |
|
562 /* Iterates over all link_maps */ |
|
563 class iterator |
|
564 { |
|
565 public: |
|
566 const link_map *operator ->() const |
|
567 { |
|
568 return item; |
|
569 } |
|
570 |
|
571 const link_map &operator ++() |
|
572 { |
|
573 item = item->l_next; |
|
574 return *item; |
|
575 } |
|
576 |
|
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) { } |
|
586 |
|
587 private: |
|
588 const link_map *item; |
|
589 }; |
|
590 |
|
591 iterator begin() const |
|
592 { |
|
593 return iterator(dbg ? dbg->r_map : nullptr); |
|
594 } |
|
595 |
|
596 iterator end() const |
|
597 { |
|
598 return iterator(nullptr); |
|
599 } |
|
600 |
|
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 }; |
|
608 |
|
609 #endif /* ElfLoader_h */ |