Bug 1751497 - adjust wpt test-verify and test-coverage tasks to be fission only....
[gecko.git] / mozglue / linker / ElfLoader.cpp
blob55b113467a27e0fae08358a7120ee2a9bcf21d42
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 #include <string>
6 #include <cstring>
7 #include <cstdlib>
8 #include <cstdio>
9 #include <dlfcn.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <algorithm>
13 #include <fcntl.h>
14 #include "ElfLoader.h"
15 #include "BaseElf.h"
16 #include "CustomElf.h"
17 #include "Mappable.h"
18 #include "Logging.h"
19 #include "Utils.h"
20 #include <inttypes.h>
22 // From Utils.h
23 mozilla::Atomic<size_t, mozilla::ReleaseAcquire> gPageSize;
25 #if defined(ANDROID)
26 # include <sys/syscall.h>
27 # include <sys/system_properties.h>
28 # include <math.h>
30 # include <android/api-level.h>
32 /**
33 * Return the current Android version, or 0 on failure.
35 static int GetAndroidSDKVersion() {
36 static int version = 0;
37 if (version) {
38 return version;
41 char version_string[PROP_VALUE_MAX] = {'\0'};
42 int len = __system_property_get("ro.build.version.sdk", version_string);
43 if (len) {
44 version = static_cast<int>(strtol(version_string, nullptr, 10));
46 return version;
49 # if __ANDROID_API__ < 8
50 /* Android API < 8 doesn't provide sigaltstack */
52 extern "C" {
54 inline int sigaltstack(const stack_t* ss, stack_t* oss) {
55 return syscall(__NR_sigaltstack, ss, oss);
58 } /* extern "C" */
59 # endif /* __ANDROID_API__ */
60 #endif /* ANDROID */
62 #ifdef __ARM_EABI__
63 extern "C" MOZ_EXPORT const void* __gnu_Unwind_Find_exidx(void* pc, int* pcount)
64 __attribute__((weak));
65 #endif
67 /* Ideally we'd #include <link.h>, but that's a world of pain
68 * Moreover, not all versions of android support it, so we need a weak
69 * reference. */
70 extern "C" MOZ_EXPORT int dl_iterate_phdr(dl_phdr_cb callback, void* data)
71 __attribute__((weak));
73 /* Pointer to the PT_DYNAMIC section of the executable or library
74 * containing this code. */
75 extern "C" Elf::Dyn _DYNAMIC[];
77 /**
78 * dlfcn.h replacements functions
81 void* __wrap_dlopen(const char* path, int flags) {
82 #if defined(ANDROID)
83 if (GetAndroidSDKVersion() >= 23) {
84 return dlopen(path, flags);
86 #endif
88 RefPtr<LibHandle> handle = ElfLoader::Singleton.Load(path, flags);
89 if (handle) handle->AddDirectRef();
90 return handle;
93 const char* __wrap_dlerror(void) {
94 #if defined(ANDROID)
95 if (GetAndroidSDKVersion() >= 23) {
96 return dlerror();
98 #endif
100 const char* error = ElfLoader::Singleton.lastError.exchange(nullptr);
101 if (error) {
102 // Return a custom error if available.
103 return error;
105 // Or fallback to the system error.
106 return dlerror();
109 void* __wrap_dlsym(void* handle, const char* symbol) {
110 #if defined(ANDROID)
111 if (GetAndroidSDKVersion() >= 23) {
112 return dlsym(handle, symbol);
114 #endif
116 if (!handle) {
117 ElfLoader::Singleton.lastError = "dlsym(NULL, sym) unsupported";
118 return nullptr;
120 if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
121 LibHandle* h = reinterpret_cast<LibHandle*>(handle);
122 return h->GetSymbolPtr(symbol);
125 ElfLoader::Singleton.lastError = nullptr; // Use system dlerror.
126 return dlsym(handle, symbol);
129 int __wrap_dlclose(void* handle) {
130 #if defined(ANDROID)
131 if (GetAndroidSDKVersion() >= 23) {
132 return dlclose(handle);
134 #endif
136 if (!handle) {
137 ElfLoader::Singleton.lastError = "No handle given to dlclose()";
138 return -1;
140 reinterpret_cast<LibHandle*>(handle)->ReleaseDirectRef();
141 return 0;
144 int __wrap_dladdr(const void* addr, Dl_info* info) {
145 #if defined(ANDROID)
146 if (GetAndroidSDKVersion() >= 23) {
147 return dladdr(addr, info);
149 #endif
151 RefPtr<LibHandle> handle =
152 ElfLoader::Singleton.GetHandleByPtr(const_cast<void*>(addr));
153 if (!handle) {
154 return dladdr(addr, info);
156 info->dli_fname = handle->GetPath();
157 info->dli_fbase = handle->GetBase();
158 return 1;
161 class DlIteratePhdrHelper {
162 public:
163 DlIteratePhdrHelper() {
164 int pipefd[2];
165 valid_pipe = (pipe(pipefd) == 0);
166 read_fd.reset(pipefd[0]);
167 write_fd.reset(pipefd[1]);
170 int fill_and_call(dl_phdr_cb callback, const void* l_addr, const char* l_name,
171 void* data);
173 private:
174 bool valid_pipe;
175 AutoCloseFD read_fd;
176 AutoCloseFD write_fd;
179 // This function is called for each shared library iterated over by
180 // dl_iterate_phdr, and is used to fill a dl_phdr_info which is then
181 // sent through to the dl_iterate_phdr callback.
182 int DlIteratePhdrHelper::fill_and_call(dl_phdr_cb callback, const void* l_addr,
183 const char* l_name, void* data) {
184 dl_phdr_info info;
185 info.dlpi_addr = reinterpret_cast<Elf::Addr>(l_addr);
186 info.dlpi_name = l_name;
187 info.dlpi_phdr = nullptr;
188 info.dlpi_phnum = 0;
190 // Assuming l_addr points to Elf headers (in most cases, this is true),
191 // get the Phdr location from there.
192 // Unfortunately, when l_addr doesn't point to Elf headers, it may point
193 // to unmapped memory, or worse, unreadable memory. The only way to detect
194 // the latter without causing a SIGSEGV is to use the pointer in a system
195 // call that will try to read from there, and return an EFAULT error if
196 // it can't. One such system call is write(). It used to be possible to
197 // use a file descriptor on /dev/null for these kind of things, but recent
198 // Linux kernels never return an EFAULT error when using /dev/null.
199 // So instead, we use a self pipe. We do however need to read() from the
200 // read end of the pipe as well so as to not fill up the pipe buffer and
201 // block on subsequent writes.
202 // In the unlikely event reads from or write to the pipe fail for some
203 // other reason than EFAULT, we don't try any further and just skip setting
204 // the Phdr location for all subsequent libraries, rather than trying to
205 // start over with a new pipe.
206 int can_read = true;
207 if (valid_pipe) {
208 int ret;
209 char raw_ehdr[sizeof(Elf::Ehdr)];
210 static_assert(sizeof(raw_ehdr) < PIPE_BUF, "PIPE_BUF is too small");
211 do {
212 // writes are atomic when smaller than PIPE_BUF, per POSIX.1-2008.
213 ret = write(write_fd, l_addr, sizeof(raw_ehdr));
214 } while (ret == -1 && errno == EINTR);
215 if (ret != sizeof(raw_ehdr)) {
216 if (ret == -1 && errno == EFAULT) {
217 can_read = false;
218 } else {
219 valid_pipe = false;
221 } else {
222 size_t nbytes = 0;
223 do {
224 // Per POSIX.1-2008, interrupted reads can return a length smaller
225 // than the given one instead of failing with errno EINTR.
226 ret = read(read_fd, raw_ehdr + nbytes, sizeof(raw_ehdr) - nbytes);
227 if (ret > 0) nbytes += ret;
228 } while ((nbytes != sizeof(raw_ehdr) && ret > 0) ||
229 (ret == -1 && errno == EINTR));
230 if (nbytes != sizeof(raw_ehdr)) {
231 valid_pipe = false;
236 if (valid_pipe && can_read) {
237 const Elf::Ehdr* ehdr = Elf::Ehdr::validate(l_addr);
238 if (ehdr) {
239 info.dlpi_phdr = reinterpret_cast<const Elf::Phdr*>(
240 reinterpret_cast<const char*>(ehdr) + ehdr->e_phoff);
241 info.dlpi_phnum = ehdr->e_phnum;
245 return callback(&info, sizeof(dl_phdr_info), data);
248 int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void* data) {
249 #if defined(ANDROID)
250 if (GetAndroidSDKVersion() >= 23) {
251 return dl_iterate_phdr(callback, data);
253 #endif
255 DlIteratePhdrHelper helper;
256 AutoLock lock(&ElfLoader::Singleton.handlesMutex);
258 if (dl_iterate_phdr) {
259 for (ElfLoader::LibHandleList::reverse_iterator it =
260 ElfLoader::Singleton.handles.rbegin();
261 it < ElfLoader::Singleton.handles.rend(); ++it) {
262 BaseElf* elf = (*it)->AsBaseElf();
263 if (!elf) {
264 continue;
266 int ret = helper.fill_and_call(callback, (*it)->GetBase(),
267 (*it)->GetPath(), data);
268 if (ret) return ret;
270 return dl_iterate_phdr(callback, data);
273 /* For versions of Android that don't support dl_iterate_phdr (< 5.0),
274 * we go through the debugger helper data, which is known to be racy, but
275 * there's not much we can do about this :( . */
276 if (!ElfLoader::Singleton.dbg) return -1;
278 for (ElfLoader::DebuggerHelper::iterator it =
279 ElfLoader::Singleton.dbg.begin();
280 it < ElfLoader::Singleton.dbg.end(); ++it) {
281 int ret = helper.fill_and_call(callback, it->l_addr, it->l_name, data);
282 if (ret) return ret;
284 return 0;
287 #ifdef __ARM_EABI__
288 const void* __wrap___gnu_Unwind_Find_exidx(void* pc, int* pcount) {
289 RefPtr<LibHandle> handle = ElfLoader::Singleton.GetHandleByPtr(pc);
290 if (handle) return handle->FindExidx(pcount);
291 if (__gnu_Unwind_Find_exidx) return __gnu_Unwind_Find_exidx(pc, pcount);
292 *pcount = 0;
293 return nullptr;
295 #endif
298 * faulty.lib public API
301 MFBT_API size_t __dl_get_mappable_length(void* handle) {
302 if (!handle) return 0;
303 return reinterpret_cast<LibHandle*>(handle)->GetMappableLength();
306 MFBT_API void* __dl_mmap(void* handle, void* addr, size_t length,
307 off_t offset) {
308 if (!handle) return nullptr;
309 return reinterpret_cast<LibHandle*>(handle)->MappableMMap(addr, length,
310 offset);
313 MFBT_API void __dl_munmap(void* handle, void* addr, size_t length) {
314 if (!handle) return;
315 return reinterpret_cast<LibHandle*>(handle)->MappableMUnmap(addr, length);
318 MFBT_API bool IsSignalHandlingBroken() {
319 return ElfLoader::Singleton.isSignalHandlingBroken();
322 namespace {
325 * Returns the part after the last '/' for the given path
327 const char* LeafName(const char* path) {
328 const char* lastSlash = strrchr(path, '/');
329 if (lastSlash) return lastSlash + 1;
330 return path;
334 * Run the given lambda while holding the internal lock of the system linker.
335 * To take the lock, we call the system dl_iterate_phdr and invoke the lambda
336 * from the callback, which is called while the lock is held. Return true on
337 * success.
339 template <class Lambda>
340 static bool RunWithSystemLinkerLock(Lambda&& aLambda) {
341 if (!dl_iterate_phdr) {
342 // No dl_iterate_phdr support.
343 return false;
346 #if defined(ANDROID)
347 if (GetAndroidSDKVersion() < 23) {
348 // dl_iterate_phdr is _not_ protected by a lock on Android < 23.
349 // Also return false here if we failed to get the version.
350 return false;
352 #endif
354 dl_iterate_phdr(
355 [](dl_phdr_info*, size_t, void* lambda) -> int {
356 (*static_cast<Lambda*>(lambda))();
357 // Return 1 to stop iterating.
358 return 1;
360 &aLambda);
361 return true;
364 } /* Anonymous namespace */
367 * LibHandle
369 LibHandle::~LibHandle() { free(path); }
371 const char* LibHandle::GetName() const {
372 return path ? LeafName(path) : nullptr;
375 size_t LibHandle::GetMappableLength() const {
376 if (!mappable) mappable = GetMappable();
377 if (!mappable) return 0;
378 return mappable->GetLength();
381 void* LibHandle::MappableMMap(void* addr, size_t length, off_t offset) const {
382 if (!mappable) mappable = GetMappable();
383 if (!mappable) return MAP_FAILED;
384 void* mapped = mappable->mmap(addr, length, PROT_READ, MAP_PRIVATE, offset);
385 return mapped;
388 void LibHandle::MappableMUnmap(void* addr, size_t length) const {
389 if (mappable) mappable->munmap(addr, length);
393 * SystemElf
395 already_AddRefed<LibHandle> SystemElf::Load(const char* path, int flags) {
396 /* The Android linker returns a handle when the file name matches an
397 * already loaded library, even when the full path doesn't exist */
398 if (path && path[0] == '/' && (access(path, F_OK) == -1)) {
399 DEBUG_LOG("dlopen(\"%s\", 0x%x) = %p", path, flags, (void*)nullptr);
400 ElfLoader::Singleton.lastError = "Specified file does not exist";
401 return nullptr;
404 ElfLoader::Singleton.lastError = nullptr; // Use system dlerror.
405 void* handle = dlopen(path, flags);
406 DEBUG_LOG("dlopen(\"%s\", 0x%x) = %p", path, flags, handle);
407 if (handle) {
408 SystemElf* elf = new SystemElf(path, handle);
409 ElfLoader::Singleton.Register(elf);
410 RefPtr<LibHandle> lib(elf);
411 return lib.forget();
413 return nullptr;
416 SystemElf::~SystemElf() {
417 if (!dlhandle) return;
418 DEBUG_LOG("dlclose(%p [\"%s\"])", dlhandle, GetPath());
419 ElfLoader::Singleton.lastError = nullptr; // Use system dlerror.
420 dlclose(dlhandle);
421 ElfLoader::Singleton.Forget(this);
424 void* SystemElf::GetSymbolPtr(const char* symbol) const {
425 ElfLoader::Singleton.lastError = nullptr; // Use system dlerror.
426 void* sym = dlsym(dlhandle, symbol);
427 DEBUG_LOG("dlsym(%p [\"%s\"], \"%s\") = %p", dlhandle, GetPath(), symbol,
428 sym);
429 return sym;
432 Mappable* SystemElf::GetMappable() const {
433 const char* path = GetPath();
434 if (!path) return nullptr;
435 #ifdef ANDROID
436 /* On Android, if we don't have the full path, try in /system/lib */
437 const char* name = LeafName(path);
438 std::string systemPath;
439 if (name == path) {
440 systemPath = "/system/lib/";
441 systemPath += path;
442 path = systemPath.c_str();
444 #endif
446 return MappableFile::Create(path);
449 #ifdef __ARM_EABI__
450 const void* SystemElf::FindExidx(int* pcount) const {
451 /* TODO: properly implement when ElfLoader::GetHandleByPtr
452 does return SystemElf handles */
453 *pcount = 0;
454 return nullptr;
456 #endif
459 * ElfLoader
462 /* Unique ElfLoader instance */
463 ElfLoader ElfLoader::Singleton;
465 already_AddRefed<LibHandle> ElfLoader::Load(const char* path, int flags,
466 LibHandle* parent) {
467 /* Ensure logging is initialized or refresh if environment changed. */
468 Logging::Init();
470 /* Ensure self_elf initialization. */
471 if (!self_elf) Init();
473 RefPtr<LibHandle> handle;
475 /* Handle dlopen(nullptr) directly. */
476 if (!path) {
477 handle = SystemElf::Load(nullptr, flags);
478 return handle.forget();
481 /* TODO: Handle relative paths correctly */
482 const char* name = LeafName(path);
484 /* Search the list of handles we already have for a match. When the given
485 * path is not absolute, compare file names, otherwise compare full paths. */
486 if (name == path) {
487 AutoLock lock(&handlesMutex);
488 for (LibHandleList::iterator it = handles.begin(); it < handles.end(); ++it)
489 if ((*it)->GetName() && (strcmp((*it)->GetName(), name) == 0)) {
490 handle = *it;
491 return handle.forget();
493 } else {
494 AutoLock lock(&handlesMutex);
495 for (LibHandleList::iterator it = handles.begin(); it < handles.end(); ++it)
496 if ((*it)->GetPath() && (strcmp((*it)->GetPath(), path) == 0)) {
497 handle = *it;
498 return handle.forget();
502 char* abs_path = nullptr;
503 const char* requested_path = path;
505 /* When the path is not absolute and the library is being loaded for
506 * another, first try to load the library from the directory containing
507 * that parent library. */
508 if ((name == path) && parent) {
509 const char* parentPath = parent->GetPath();
510 abs_path = new char[strlen(parentPath) + strlen(path)];
511 strcpy(abs_path, parentPath);
512 char* slash = strrchr(abs_path, '/');
513 strcpy(slash + 1, path);
514 path = abs_path;
517 Mappable* mappable = GetMappableFromPath(path);
519 /* Try loading with the custom linker if we have a Mappable */
520 if (mappable) handle = CustomElf::Load(mappable, path, flags);
522 /* Try loading with the system linker if everything above failed */
523 if (!handle) handle = SystemElf::Load(path, flags);
525 /* If we didn't have an absolute path and haven't been able to load
526 * a library yet, try in the system search path */
527 if (!handle && abs_path) handle = SystemElf::Load(name, flags);
529 delete[] abs_path;
530 DEBUG_LOG("ElfLoader::Load(\"%s\", 0x%x, %p [\"%s\"]) = %p", requested_path,
531 flags, reinterpret_cast<void*>(parent),
532 parent ? parent->GetPath() : "", static_cast<void*>(handle));
534 return handle.forget();
537 already_AddRefed<LibHandle> ElfLoader::GetHandleByPtr(void* addr) {
538 AutoLock lock(&handlesMutex);
539 /* Scan the list of handles we already have for a match */
540 for (LibHandleList::iterator it = handles.begin(); it < handles.end(); ++it) {
541 if ((*it)->Contains(addr)) {
542 RefPtr<LibHandle> lib = *it;
543 return lib.forget();
546 return nullptr;
549 Mappable* ElfLoader::GetMappableFromPath(const char* path) {
550 const char* name = LeafName(path);
551 Mappable* mappable = nullptr;
552 RefPtr<Zip> zip;
553 const char* subpath;
554 if ((subpath = strchr(path, '!'))) {
555 char* zip_path = strndup(path, subpath - path);
556 while (*(++subpath) == '/') {
558 zip = ZipCollection::GetZip(zip_path);
559 free(zip_path);
560 Zip::Stream s;
561 if (zip && zip->GetStream(subpath, &s)) {
562 /* When the MOZ_LINKER_EXTRACT environment variable is set to "1",
563 * compressed libraries are going to be (temporarily) extracted as
564 * files, in the directory pointed by the MOZ_LINKER_CACHE
565 * environment variable. */
566 const char* extract = getenv("MOZ_LINKER_EXTRACT");
567 if (extract && !strncmp(extract, "1", 2 /* Including '\0' */))
568 mappable = MappableExtractFile::Create(name, zip, &s);
569 if (!mappable) {
570 if (s.GetType() == Zip::Stream::DEFLATE) {
571 mappable = MappableDeflate::Create(name, zip, &s);
576 /* If we couldn't load above, try with a MappableFile */
577 if (!mappable && !zip) mappable = MappableFile::Create(path);
579 return mappable;
582 void ElfLoader::Register(LibHandle* handle) {
583 AutoLock lock(&handlesMutex);
584 handles.push_back(handle);
587 void ElfLoader::Register(CustomElf* handle) {
588 Register(static_cast<LibHandle*>(handle));
589 if (dbg) {
590 // We could race with the system linker when modifying the debug map, so
591 // only do so while holding the system linker's internal lock.
592 RunWithSystemLinkerLock([this, handle] { dbg.Add(handle); });
596 void ElfLoader::Forget(LibHandle* handle) {
597 /* Ensure logging is initialized or refresh if environment changed. */
598 Logging::Init();
600 AutoLock lock(&handlesMutex);
601 LibHandleList::iterator it =
602 std::find(handles.begin(), handles.end(), handle);
603 if (it != handles.end()) {
604 DEBUG_LOG("ElfLoader::Forget(%p [\"%s\"])", reinterpret_cast<void*>(handle),
605 handle->GetPath());
606 handles.erase(it);
607 } else {
608 DEBUG_LOG("ElfLoader::Forget(%p [\"%s\"]): Handle not found",
609 reinterpret_cast<void*>(handle), handle->GetPath());
613 void ElfLoader::Forget(CustomElf* handle) {
614 Forget(static_cast<LibHandle*>(handle));
615 if (dbg) {
616 // We could race with the system linker when modifying the debug map, so
617 // only do so while holding the system linker's internal lock.
618 RunWithSystemLinkerLock([this, handle] { dbg.Remove(handle); });
622 void ElfLoader::Init() {
623 Dl_info info;
624 /* On Android < 4.1 can't reenter dl* functions. So when the library
625 * containing this code is dlopen()ed, it can't call dladdr from a
626 * static initializer. */
627 if (dladdr(_DYNAMIC, &info) != 0) {
628 self_elf = LoadedElf::Create(info.dli_fname, info.dli_fbase);
630 #if defined(ANDROID)
631 // On Android < 5.0, resolving weak symbols via dlsym doesn't work.
632 // The weak symbols Gecko uses are in either libc or libm, so we
633 // wrap those such that this linker does symbol resolution for them.
634 if (GetAndroidSDKVersion() < 21) {
635 if (dladdr(FunctionPtr(syscall), &info) != 0) {
636 libc = LoadedElf::Create(info.dli_fname, info.dli_fbase);
638 if (dladdr(FunctionPtr<int (*)(double)>(isnan), &info) != 0) {
639 libm = LoadedElf::Create(info.dli_fname, info.dli_fbase);
642 #endif
645 ElfLoader::~ElfLoader() {
646 LibHandleList list;
648 if (!Singleton.IsShutdownExpected()) {
649 MOZ_CRASH("Unexpected shutdown");
652 /* Release self_elf and libc */
653 self_elf = nullptr;
654 #if defined(ANDROID)
655 libc = nullptr;
656 libm = nullptr;
657 #endif
659 AutoLock lock(&handlesMutex);
660 /* Build up a list of all library handles with direct (external) references.
661 * We actually skip system library handles because we want to keep at least
662 * some of these open. Most notably, Mozilla codebase keeps a few libgnome
663 * libraries deliberately open because of the mess that libORBit destruction
664 * is. dlclose()ing these libraries actually leads to problems. */
665 for (LibHandleList::reverse_iterator it = handles.rbegin();
666 it < handles.rend(); ++it) {
667 if ((*it)->DirectRefCount()) {
668 if (SystemElf* se = (*it)->AsSystemElf()) {
669 se->Forget();
670 } else {
671 list.push_back(*it);
675 /* Force release all external references to the handles collected above */
676 for (LibHandleList::iterator it = list.begin(); it < list.end(); ++it) {
677 while ((*it)->ReleaseDirectRef()) {
680 /* Remove the remaining system handles. */
681 if (handles.size()) {
682 list = handles;
683 for (LibHandleList::reverse_iterator it = list.rbegin(); it < list.rend();
684 ++it) {
685 if ((*it)->AsSystemElf()) {
686 DEBUG_LOG(
687 "ElfLoader::~ElfLoader(): Remaining handle for \"%s\" "
688 "[%" PRIdPTR " direct refs, %" PRIdPTR " refs total]",
689 (*it)->GetPath(), (*it)->DirectRefCount(), (*it)->refCount());
690 } else {
691 DEBUG_LOG(
692 "ElfLoader::~ElfLoader(): Unexpected remaining handle for \"%s\" "
693 "[%" PRIdPTR " direct refs, %" PRIdPTR " refs total]",
694 (*it)->GetPath(), (*it)->DirectRefCount(), (*it)->refCount());
695 /* Not removing, since it could have references to other libraries,
696 * destroying them as a side effect, and possibly leaving dangling
697 * pointers in the handle list we're scanning */
701 pthread_mutex_destroy(&handlesMutex);
704 #ifdef __ARM_EABI__
705 int ElfLoader::__wrap_aeabi_atexit(void* that, ElfLoader::Destructor destructor,
706 void* dso_handle) {
707 Singleton.destructors.push_back(
708 DestructorCaller(destructor, that, dso_handle));
709 return 0;
711 #else
712 int ElfLoader::__wrap_cxa_atexit(ElfLoader::Destructor destructor, void* that,
713 void* dso_handle) {
714 Singleton.destructors.push_back(
715 DestructorCaller(destructor, that, dso_handle));
716 return 0;
718 #endif
720 void ElfLoader::__wrap_cxa_finalize(void* dso_handle) {
721 /* Call all destructors for the given DSO handle in reverse order they were
722 * registered. */
723 std::vector<DestructorCaller>::reverse_iterator it;
724 for (it = Singleton.destructors.rbegin(); it < Singleton.destructors.rend();
725 ++it) {
726 if (it->IsForHandle(dso_handle)) {
727 it->Call();
732 void ElfLoader::DestructorCaller::Call() {
733 if (destructor) {
734 DEBUG_LOG("ElfLoader::DestructorCaller::Call(%p, %p, %p)",
735 FunctionPtr(destructor), object, dso_handle);
736 destructor(object);
737 destructor = nullptr;
741 ElfLoader::DebuggerHelper::DebuggerHelper()
742 : dbg(nullptr), firstAdded(nullptr) {
743 /* Find ELF auxiliary vectors.
745 * The kernel stores the following data on the stack when starting a
746 * program:
747 * argc
748 * argv[0] (pointer into argv strings defined below)
749 * argv[1] (likewise)
750 * ...
751 * argv[argc - 1] (likewise)
752 * nullptr
753 * envp[0] (pointer into environment strings defined below)
754 * envp[1] (likewise)
755 * ...
756 * envp[n] (likewise)
757 * nullptr
758 * ... (more NULLs on some platforms such as Android 4.3)
759 * auxv[0] (first ELF auxiliary vector)
760 * auxv[1] (second ELF auxiliary vector)
761 * ...
762 * auxv[p] (last ELF auxiliary vector)
763 * (AT_NULL, nullptr)
764 * padding
765 * argv strings, separated with '\0'
766 * environment strings, separated with '\0'
767 * nullptr
769 * What we are after are the auxv values defined by the following struct.
771 struct AuxVector {
772 Elf::Addr type;
773 Elf::Addr value;
776 /* Pointer to the environment variables list */
777 extern char** environ;
779 /* The environment may have changed since the program started, in which
780 * case the environ variables list isn't the list the kernel put on stack
781 * anymore. But in this new list, variables that didn't change still point
782 * to the strings the kernel put on stack. It is quite unlikely that two
783 * modified environment variables point to two consecutive strings in memory,
784 * so we assume that if two consecutive environment variables point to two
785 * consecutive strings, we found strings the kernel put on stack. */
786 char** env;
787 for (env = environ; *env; env++)
788 if (*env + strlen(*env) + 1 == env[1]) break;
789 if (!*env) return;
791 /* Next, we scan the stack backwards to find a pointer to one of those
792 * strings we found above, which will give us the location of the original
793 * envp list. As we are looking for pointers, we need to look at 32-bits or
794 * 64-bits aligned values, depening on the architecture. */
795 char** scan = reinterpret_cast<char**>(reinterpret_cast<uintptr_t>(*env) &
796 ~(sizeof(void*) - 1));
797 while (*env != *scan) scan--;
799 /* Finally, scan forward to find the last environment variable pointer and
800 * thus the first auxiliary vector. */
801 while (*scan++)
804 /* Some platforms have more NULLs here, so skip them if we encounter them */
805 while (!*scan) scan++;
807 AuxVector* auxv = reinterpret_cast<AuxVector*>(scan);
809 /* The two values of interest in the auxiliary vectors are AT_PHDR and
810 * AT_PHNUM, which gives us the the location and size of the ELF program
811 * headers. */
812 Array<Elf::Phdr> phdrs;
813 char* base = nullptr;
814 while (auxv->type) {
815 if (auxv->type == AT_PHDR) {
816 phdrs.Init(reinterpret_cast<Elf::Phdr*>(auxv->value));
817 /* Assume the base address is the first byte of the same page */
818 base = reinterpret_cast<char*>(PageAlignedPtr(auxv->value));
820 if (auxv->type == AT_PHNUM) phdrs.Init(auxv->value);
821 auxv++;
824 if (!phdrs) {
825 DEBUG_LOG("Couldn't find program headers");
826 return;
829 /* In some cases, the address for the program headers we get from the
830 * auxiliary vectors is not mapped, because of the PT_LOAD segments
831 * definitions in the program executable. Trying to map anonymous memory
832 * with a hint giving the base address will return a different address
833 * if something is mapped there, and the base address otherwise. */
834 MappedPtr mem(MemoryRange::mmap(base, PageSize(), PROT_NONE,
835 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
836 if (mem == base) {
837 /* If program headers aren't mapped, try to map them */
838 int fd = open("/proc/self/exe", O_RDONLY);
839 if (fd == -1) {
840 DEBUG_LOG("Failed to open /proc/self/exe");
841 return;
843 mem.Assign(
844 MemoryRange::mmap(base, PageSize(), PROT_READ, MAP_PRIVATE, fd, 0));
845 /* If we don't manage to map at the right address, just give up. */
846 if (mem != base) {
847 DEBUG_LOG("Couldn't read program headers");
848 return;
851 /* Sanity check: the first bytes at the base address should be an ELF
852 * header. */
853 if (!Elf::Ehdr::validate(base)) {
854 DEBUG_LOG("Couldn't find program base");
855 return;
858 /* Search for the program PT_DYNAMIC segment */
859 Array<Elf::Dyn> dyns;
860 for (Array<Elf::Phdr>::iterator phdr = phdrs.begin(); phdr < phdrs.end();
861 ++phdr) {
862 /* While the program headers are expected within the first mapped page of
863 * the program executable, the executable PT_LOADs may actually make them
864 * loaded at an address that is not the wanted base address of the
865 * library. We thus need to adjust the base address, compensating for the
866 * virtual address of the PT_LOAD segment corresponding to offset 0. */
867 if (phdr->p_type == PT_LOAD && phdr->p_offset == 0) base -= phdr->p_vaddr;
868 if (phdr->p_type == PT_DYNAMIC)
869 dyns.Init(base + phdr->p_vaddr, phdr->p_filesz);
871 if (!dyns) {
872 DEBUG_LOG("Failed to find PT_DYNAMIC section in program");
873 return;
876 /* Search for the DT_DEBUG information */
877 for (Array<Elf::Dyn>::iterator dyn = dyns.begin(); dyn < dyns.end(); ++dyn) {
878 if (dyn->d_tag == DT_DEBUG) {
879 dbg = reinterpret_cast<r_debug*>(dyn->d_un.d_ptr);
880 break;
883 DEBUG_LOG("DT_DEBUG points at %p", static_cast<void*>(dbg));
887 * Helper class to ensure the given pointer is writable within the scope of
888 * an instance. Permissions to the memory page where the pointer lies are
889 * restored to their original value when the instance is destroyed.
891 class EnsureWritable {
892 public:
893 template <typename T>
894 explicit EnsureWritable(T* ptr, size_t length_ = sizeof(T)) {
895 MOZ_ASSERT(length_ < PageSize());
896 prot = -1;
897 page = MAP_FAILED;
899 char* firstPage = PageAlignedPtr(reinterpret_cast<char*>(ptr));
900 char* lastPageEnd =
901 PageAlignedEndPtr(reinterpret_cast<char*>(ptr) + length_);
902 length = lastPageEnd - firstPage;
903 uintptr_t start = reinterpret_cast<uintptr_t>(firstPage);
904 uintptr_t end;
906 prot = getProt(start, &end);
907 if (prot == -1 || (start + length) > end) MOZ_CRASH();
909 if (prot & PROT_WRITE) {
910 success = true;
911 return;
914 page = firstPage;
915 int ret = mprotect(page, length, prot | PROT_WRITE);
916 success = ret == 0;
917 if (!success) {
918 ERROR("mprotect(%p, %zu, %d) = %d (errno=%d; %s)", page, length,
919 prot | PROT_WRITE, ret, errno, strerror(errno));
923 bool IsWritable() const { return success; }
925 ~EnsureWritable() {
926 if (success && page != MAP_FAILED) {
927 mprotect(page, length, prot);
931 private:
932 int getProt(uintptr_t addr, uintptr_t* end) {
933 /* The interesting part of the /proc/self/maps format looks like:
934 * startAddr-endAddr rwxp */
935 int result = 0;
936 AutoCloseFILE f(fopen("/proc/self/maps", "r"));
937 while (f) {
938 unsigned long long startAddr, endAddr;
939 char perms[5];
940 if (fscanf(f, "%llx-%llx %4s %*1024[^\n] ", &startAddr, &endAddr,
941 perms) != 3)
942 return -1;
943 if (addr < startAddr || addr >= endAddr) continue;
944 if (perms[0] == 'r')
945 result |= PROT_READ;
946 else if (perms[0] != '-')
947 return -1;
948 if (perms[1] == 'w')
949 result |= PROT_WRITE;
950 else if (perms[1] != '-')
951 return -1;
952 if (perms[2] == 'x')
953 result |= PROT_EXEC;
954 else if (perms[2] != '-')
955 return -1;
956 *end = endAddr;
957 return result;
959 return -1;
962 int prot;
963 void* page;
964 size_t length;
965 bool success;
969 * The system linker maintains a doubly linked list of library it loads
970 * for use by the debugger. Unfortunately, it also uses the list pointers
971 * in a lot of operations and adding our data in the list is likely to
972 * trigger crashes when the linker tries to use data we don't provide or
973 * that fall off the amount data we allocated. Fortunately, the linker only
974 * traverses the list forward and accesses the head of the list from a
975 * private pointer instead of using the value in the r_debug structure.
976 * This means we can safely add members at the beginning of the list.
977 * Unfortunately, gdb checks the coherency of l_prev values, so we have
978 * to adjust the l_prev value for the first element the system linker
979 * knows about. Fortunately, it doesn't use l_prev, and the first element
980 * is not ever going to be released before our elements, since it is the
981 * program executable, so the system linker should not be changing
982 * r_debug::r_map.
984 void ElfLoader::DebuggerHelper::Add(ElfLoader::link_map* map) {
985 if (!dbg->r_brk) return;
987 dbg->r_state = r_debug::RT_ADD;
988 dbg->r_brk();
990 if (!firstAdded) {
991 /* When adding a library for the first time, r_map points to data
992 * handled by the system linker, and that data may be read-only */
993 EnsureWritable w(&dbg->r_map->l_prev);
994 if (!w.IsWritable()) {
995 dbg->r_state = r_debug::RT_CONSISTENT;
996 dbg->r_brk();
997 return;
1000 firstAdded = map;
1001 dbg->r_map->l_prev = map;
1002 } else
1003 dbg->r_map->l_prev = map;
1005 map->l_prev = nullptr;
1006 map->l_next = dbg->r_map;
1008 dbg->r_map = map;
1009 dbg->r_state = r_debug::RT_CONSISTENT;
1010 dbg->r_brk();
1013 void ElfLoader::DebuggerHelper::Remove(ElfLoader::link_map* map) {
1014 if (!dbg->r_brk) return;
1016 dbg->r_state = r_debug::RT_DELETE;
1017 dbg->r_brk();
1019 if (map == firstAdded) {
1020 /* When removing the first added library, its l_next is going to be
1021 * data handled by the system linker, and that data may be read-only */
1022 EnsureWritable w(&map->l_next->l_prev);
1023 if (!w.IsWritable()) {
1024 dbg->r_state = r_debug::RT_CONSISTENT;
1025 dbg->r_brk();
1026 return;
1029 firstAdded = map->l_prev;
1030 map->l_next->l_prev = map->l_prev;
1031 } else if (map->l_next) {
1032 map->l_next->l_prev = map->l_prev;
1035 if (dbg->r_map == map)
1036 dbg->r_map = map->l_next;
1037 else if (map->l_prev) {
1038 map->l_prev->l_next = map->l_next;
1040 dbg->r_state = r_debug::RT_CONSISTENT;
1041 dbg->r_brk();
1044 #if defined(ANDROID) && defined(__NR_sigaction)
1045 /* As some system libraries may be calling signal() or sigaction() to
1046 * set a SIGSEGV handler, effectively breaking MappableSeekableZStream,
1047 * or worse, restore our SIGSEGV handler with wrong flags (which using
1048 * signal() will do), we want to hook into the system's sigaction() to
1049 * replace it with our own wrapper instead, so that our handler is never
1050 * replaced. We used to only do that with libraries this linker loads,
1051 * but it turns out at least one system library does call signal() and
1052 * breaks us (libsc-a3xx.so on the Samsung Galaxy S4).
1053 * As libc's signal (bsd_signal/sysv_signal, really) calls sigaction
1054 * under the hood, instead of calling the signal system call directly,
1055 * we only need to hook sigaction. This is true for both bionic and
1056 * glibc.
1059 /* libc's sigaction */
1060 extern "C" int sigaction(int signum, const struct sigaction* act,
1061 struct sigaction* oldact);
1063 /* Simple reimplementation of sigaction. This is roughly equivalent
1064 * to the assembly that comes in bionic, but not quite equivalent to
1065 * glibc's implementation, so we only use this on Android. */
1066 int sys_sigaction(int signum, const struct sigaction* act,
1067 struct sigaction* oldact) {
1068 return syscall(__NR_sigaction, signum, act, oldact);
1071 /* Replace the first instructions of the given function with a jump
1072 * to the given new function. */
1073 template <typename T>
1074 static bool Divert(T func, T new_func) {
1075 void* ptr = FunctionPtr(func);
1076 uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
1078 # if defined(__i386__)
1079 // A 32-bit jump is a 5 bytes instruction.
1080 EnsureWritable w(ptr, 5);
1081 *reinterpret_cast<unsigned char*>(addr) = 0xe9; // jmp
1082 *reinterpret_cast<intptr_t*>(addr + 1) =
1083 reinterpret_cast<uintptr_t>(new_func) - addr - 5; // target displacement
1084 return true;
1085 # elif defined(__arm__) || defined(__aarch64__)
1086 const unsigned char trampoline[] = {
1087 # ifdef __arm__
1088 // .thumb
1089 0x46, 0x04, // nop
1090 0x78, 0x47, // bx pc
1091 0x46, 0x04, // nop
1092 // .arm
1093 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4]
1094 // .word <new_func>
1095 # else // __aarch64__
1096 0x50, 0x00,
1097 0x00, 0x58, // ldr x16, [pc, #8] ; x16 (aka ip0) is the first
1098 0x00, 0x02,
1099 0x1f, 0xd6, // br x16 ; intra-procedure-call
1100 // .word <new_func.lo> ; scratch register.
1101 // .word <new_func.hi>
1102 # endif
1104 const unsigned char* start;
1105 # ifdef __arm__
1106 if (addr & 0x01) {
1107 /* Function is thumb, the actual address of the code is without the
1108 * least significant bit. */
1109 addr--;
1110 /* The arm part of the trampoline needs to be 32-bit aligned */
1111 if (addr & 0x02)
1112 start = trampoline;
1113 else
1114 start = trampoline + 2;
1115 } else {
1116 /* Function is arm, we only need the arm part of the trampoline */
1117 start = trampoline + 6;
1119 # else // __aarch64__
1120 start = trampoline;
1121 # endif
1123 size_t len = sizeof(trampoline) - (start - trampoline);
1124 EnsureWritable w(reinterpret_cast<void*>(addr), len + sizeof(void*));
1125 memcpy(reinterpret_cast<void*>(addr), start, len);
1126 *reinterpret_cast<void**>(addr + len) = FunctionPtr(new_func);
1127 __builtin___clear_cache(reinterpret_cast<char*>(addr),
1128 reinterpret_cast<char*>(addr + len + sizeof(void*)));
1129 return true;
1130 # else
1131 return false;
1132 # endif
1134 #else
1135 # define sys_sigaction sigaction
1136 template <typename T>
1137 static bool Divert(T func, T new_func) {
1138 return false;
1140 #endif
1142 namespace {
1144 /* Clock that only accounts for time spent in the current process. */
1145 static uint64_t ProcessTimeStamp_Now() {
1146 struct timespec ts;
1147 int rv = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
1149 if (rv != 0) {
1150 return 0;
1153 uint64_t baseNs = (uint64_t)ts.tv_sec * 1000000000;
1154 return baseNs + (uint64_t)ts.tv_nsec;
1157 } // namespace
1159 /* Data structure used to pass data to the temporary signal handler,
1160 * as well as triggering a test crash. */
1161 struct TmpData {
1162 volatile int crash_int;
1163 volatile uint64_t crash_timestamp;
1166 SEGVHandler::SEGVHandler()
1167 : initialized(false),
1168 registeredHandler(false),
1169 signalHandlingBroken(true),
1170 signalHandlingSlow(true) {
1171 /* Ensure logging is initialized before the DEBUG_LOG in the test_handler.
1172 * As this constructor runs before the ElfLoader constructor (by effect
1173 * of ElfLoader inheriting from this class), this also initializes on behalf
1174 * of ElfLoader and DebuggerHelper. */
1175 Logging::Init();
1177 /* Initialize oldStack.ss_flags to an invalid value when used to set
1178 * an alternative stack, meaning we haven't got information about the
1179 * original alternative stack and thus don't mean to restore it in
1180 * the destructor. */
1181 oldStack.ss_flags = SS_ONSTACK;
1183 /* Get the current segfault signal handler. */
1184 struct sigaction old_action;
1185 sys_sigaction(SIGSEGV, nullptr, &old_action);
1187 /* Some devices don't provide useful information to their SIGSEGV handlers,
1188 * making it impossible for on-demand decompression to work. To check if
1189 * we're on such a device, setup a temporary handler and deliberately
1190 * trigger a segfault. The handler will set signalHandlingBroken if the
1191 * provided information is bogus.
1192 * Some other devices have a kernel option enabled that makes SIGSEGV handler
1193 * have an overhead so high that it affects how on-demand decompression
1194 * performs. The handler will also set signalHandlingSlow if the triggered
1195 * SIGSEGV took too much time. */
1196 struct sigaction action;
1197 action.sa_sigaction = &SEGVHandler::test_handler;
1198 sigemptyset(&action.sa_mask);
1199 action.sa_flags = SA_SIGINFO | SA_NODEFER;
1200 action.sa_restorer = nullptr;
1201 stackPtr.Assign(MemoryRange::mmap(nullptr, PageSize(), PROT_READ | PROT_WRITE,
1202 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
1203 if (stackPtr.get() == MAP_FAILED) return;
1204 if (sys_sigaction(SIGSEGV, &action, nullptr)) return;
1206 TmpData* data = reinterpret_cast<TmpData*>(stackPtr.get());
1207 data->crash_timestamp = ProcessTimeStamp_Now();
1208 mprotect(stackPtr, stackPtr.GetLength(), PROT_NONE);
1209 data->crash_int = 123;
1210 /* Restore the original segfault signal handler. */
1211 sys_sigaction(SIGSEGV, &old_action, nullptr);
1212 stackPtr.Assign(MAP_FAILED, 0);
1215 void SEGVHandler::FinishInitialization() {
1216 /* Ideally, we'd need some locking here, but in practice, we're not
1217 * going to race with another thread. */
1218 initialized = true;
1220 if (signalHandlingBroken || signalHandlingSlow) return;
1222 typedef int (*sigaction_func)(int, const struct sigaction*,
1223 struct sigaction*);
1225 sigaction_func libc_sigaction;
1227 #if defined(ANDROID)
1228 /* Android > 4.4 comes with a sigaction wrapper in a LD_PRELOADed library
1229 * (libsigchain) for ART. That wrapper kind of does the same trick as we
1230 * do, so we need extra care in handling it.
1231 * - Divert the libc's sigaction, assuming the LD_PRELOADed library uses
1232 * it under the hood (which is more or less true according to the source
1233 * of that library, since it's doing a lookup in RTLD_NEXT)
1234 * - With the LD_PRELOADed library in place, all calls to sigaction from
1235 * from system libraries will go to the LD_PRELOADed library.
1236 * - The LD_PRELOADed library calls to sigaction go to our __wrap_sigaction.
1237 * - The calls to sigaction from libraries faulty.lib loads are sent to
1238 * the LD_PRELOADed library.
1239 * In practice, for signal handling, this means:
1240 * - The signal handler registered to the kernel is ours.
1241 * - Our handler redispatches to the LD_PRELOADed library's if there's a
1242 * segfault we don't handle.
1243 * - The LD_PRELOADed library redispatches according to whatever system
1244 * library or faulty.lib-loaded library set with sigaction.
1246 * When there is no sigaction wrapper in place:
1247 * - Divert the libc's sigaction.
1248 * - Calls to sigaction from system library and faulty.lib-loaded libraries
1249 * all go to the libc's sigaction, which end up in our __wrap_sigaction.
1250 * - The signal handler registered to the kernel is ours.
1251 * - Our handler redispatches according to whatever system library or
1252 * faulty.lib-loaded library set with sigaction.
1254 void* libc = dlopen("libc.so", RTLD_GLOBAL | RTLD_LAZY);
1255 if (libc) {
1257 * Lollipop bionic only has a small trampoline in sigaction, with the real
1258 * work happening in __sigaction. Divert there instead of sigaction if it
1259 * exists. Bug 1154803
1261 libc_sigaction =
1262 reinterpret_cast<sigaction_func>(dlsym(libc, "__sigaction"));
1264 if (!libc_sigaction) {
1265 libc_sigaction =
1266 reinterpret_cast<sigaction_func>(dlsym(libc, "sigaction"));
1268 } else
1269 #endif
1271 libc_sigaction = sigaction;
1274 if (!Divert(libc_sigaction, __wrap_sigaction)) return;
1276 /* Setup an alternative stack if the already existing one is not big
1277 * enough, or if there is none. */
1278 if (sigaltstack(nullptr, &oldStack) == 0) {
1279 if (oldStack.ss_flags == SS_ONSTACK) oldStack.ss_flags = 0;
1280 if (!oldStack.ss_sp || oldStack.ss_size < stackSize) {
1281 stackPtr.Assign(MemoryRange::mmap(nullptr, stackSize,
1282 PROT_READ | PROT_WRITE,
1283 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
1284 if (stackPtr.get() == MAP_FAILED) return;
1285 stack_t stack;
1286 stack.ss_sp = stackPtr;
1287 stack.ss_size = stackSize;
1288 stack.ss_flags = 0;
1289 if (sigaltstack(&stack, nullptr) != 0) return;
1292 /* Register our own handler, and store the already registered one in
1293 * SEGVHandler's struct sigaction member */
1294 action.sa_sigaction = &SEGVHandler::handler;
1295 action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
1296 registeredHandler = !sys_sigaction(SIGSEGV, &action, &this->action);
1299 SEGVHandler::~SEGVHandler() {
1300 /* Restore alternative stack for signals */
1301 if (oldStack.ss_flags != SS_ONSTACK) sigaltstack(&oldStack, nullptr);
1302 /* Restore original signal handler */
1303 if (registeredHandler) sys_sigaction(SIGSEGV, &this->action, nullptr);
1306 /* Test handler for a deliberately triggered SIGSEGV that determines whether
1307 * useful information is provided to signal handlers, particularly whether
1308 * si_addr is filled in properly, and whether the segfault handler is called
1309 * quickly enough. */
1310 void SEGVHandler::test_handler(int signum, siginfo_t* info, void* context) {
1311 SEGVHandler& that = ElfLoader::Singleton;
1312 if (signum == SIGSEGV && info && info->si_addr == that.stackPtr.get())
1313 that.signalHandlingBroken = false;
1314 mprotect(that.stackPtr, that.stackPtr.GetLength(), PROT_READ | PROT_WRITE);
1315 TmpData* data = reinterpret_cast<TmpData*>(that.stackPtr.get());
1316 uint64_t latency = ProcessTimeStamp_Now() - data->crash_timestamp;
1317 DEBUG_LOG("SEGVHandler latency: %" PRIu64, latency);
1318 /* See bug 886736 for timings on different devices, 150 µs is reasonably above
1319 * the latency on "working" devices and seems to be short enough to not incur
1320 * a huge overhead to on-demand decompression. */
1321 if (latency <= 150000) that.signalHandlingSlow = false;
1324 /* TODO: "properly" handle signal masks and flags */
1325 void SEGVHandler::handler(int signum, siginfo_t* info, void* context) {
1326 // ASSERT(signum == SIGSEGV);
1327 DEBUG_LOG("Caught segmentation fault @%p", info->si_addr);
1329 /* Redispatch to the registered handler */
1330 SEGVHandler& that = ElfLoader::Singleton;
1331 if (that.action.sa_flags & SA_SIGINFO) {
1332 DEBUG_LOG("Redispatching to registered handler @%p",
1333 FunctionPtr(that.action.sa_sigaction));
1334 that.action.sa_sigaction(signum, info, context);
1335 } else if (that.action.sa_handler == SIG_DFL) {
1336 DEBUG_LOG("Redispatching to default handler");
1337 /* Reset the handler to the default one, and trigger it. */
1338 sys_sigaction(signum, &that.action, nullptr);
1339 raise(signum);
1340 } else if (that.action.sa_handler != SIG_IGN) {
1341 DEBUG_LOG("Redispatching to registered handler @%p",
1342 FunctionPtr(that.action.sa_handler));
1343 that.action.sa_handler(signum);
1344 } else {
1345 DEBUG_LOG("Ignoring");
1349 int SEGVHandler::__wrap_sigaction(int signum, const struct sigaction* act,
1350 struct sigaction* oldact) {
1351 SEGVHandler& that = ElfLoader::Singleton;
1353 /* Use system sigaction() function for all but SIGSEGV signals. */
1354 if (!that.registeredHandler || (signum != SIGSEGV))
1355 return sys_sigaction(signum, act, oldact);
1357 if (oldact) *oldact = that.action;
1358 if (act) that.action = *act;
1359 return 0;