thread->tls[i] = NULL;
}
+ // Create and set an alternate signal stack.
+ stack_t ss;
+ ss.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
+ if (ss.ss_sp != MAP_FAILED) {
+ ss.ss_size = SIGSTKSZ;
+ ss.ss_flags = 0;
+ sigaltstack(&ss, NULL);
+ }
+
// Slot 0 must point to itself. The x86 Linux kernel reads the TLS from %fs:0.
thread->tls[TLS_SLOT_SELF] = thread->tls;
thread->tls[TLS_SLOT_THREAD_ID] = thread;
__set_tls(thread->tls);
}
-// This trampoline is called from the assembly _pthread_clone() function.
+// This trampoline is called from the assembly _pthread_clone function.
+// Our 'tls' and __pthread_clone's 'child_stack' are one and the same, just growing in
+// opposite directions.
extern "C" void __thread_entry(void* (*func)(void*), void* arg, void** tls) {
// Wait for our creating thread to release us. This lets it have time to
// notify gdb about this thread before we start doing anything.
thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_STACK;
}
- // Make room for TLS.
+ // Make room for the TLS area.
+ // The child stack is the same address, just growing in the opposite direction.
+ // At offsets >= 0, we have the TLS slots.
+ // At offsets < 0, we have the child stack.
void** tls = (void**)((uint8_t*)(thread->attr.stack_base) + thread->attr.stack_size - BIONIC_TLS_SLOTS * sizeof(void*));
+ void* child_stack = tls;
// Create a mutex for the thread in TLS_SLOT_SELF to wait on once it starts so we can keep
// it from doing anything until after we notify the debugger about it
int flags = CLONE_FILES | CLONE_FS | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM;
- int tid = __pthread_clone(start_routine, tls, flags, arg);
+ int tid = __pthread_clone(start_routine, child_stack, flags, arg);
if (tid < 0) {
int clone_errno = errno;
if ((thread->attr.flags & PTHREAD_ATTR_FLAG_USER_STACK) == 0) {
#include "linker.h"
+#include <errno.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
+#include <sys/mman.h>
#include <sys/prctl.h>
-#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <unistd.h>
extern "C" int tgkill(int tgid, int tid, int sig);
* mutex is being held, so we don't want to use any libc functions that
* could allocate memory or hold a lock.
*/
-static void logSignalSummary(int signum, const siginfo_t* info) {
+static void log_signal_summary(int signum, const siginfo_t* info) {
const char* signal_name;
switch (signum) {
case SIGILL: signal_name = "SIGILL"; break;
/*
* Returns true if the handler for signal "signum" has SA_SIGINFO set.
*/
-static bool haveSiginfo(int signum) {
- struct sigaction oldact, newact;
+static bool have_siginfo(int signum) {
+ struct sigaction old_action, new_action;
- memset(&newact, 0, sizeof(newact));
- newact.sa_handler = SIG_DFL;
- newact.sa_flags = SA_RESTART;
- sigemptyset(&newact.sa_mask);
+ memset(&new_action, 0, sizeof(new_action));
+ new_action.sa_handler = SIG_DFL;
+ new_action.sa_flags = SA_RESTART;
+ sigemptyset(&new_action.sa_mask);
- if (sigaction(signum, &newact, &oldact) < 0) {
+ if (sigaction(signum, &new_action, &old_action) < 0) {
__libc_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s",
strerror(errno));
return false;
}
- bool ret = (oldact.sa_flags & SA_SIGINFO) != 0;
+ bool result = (old_action.sa_flags & SA_SIGINFO) != 0;
- if (sigaction(signum, &oldact, NULL) == -1) {
+ if (sigaction(signum, &old_action, NULL) == -1) {
__libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s",
strerror(errno));
}
- return ret;
+ return result;
}
/*
* It's possible somebody cleared the SA_SIGINFO flag, which would mean
* our "info" arg holds an undefined value.
*/
- if (!haveSiginfo(n)) {
+ if (!have_siginfo(n)) {
info = NULL;
}
- logSignalSummary(n, info);
+ log_signal_summary(n, info);
pid_t tid = gettid();
int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM);
}
void debuggerd_init() {
- struct sigaction act;
- memset(&act, 0, sizeof(act));
- act.sa_sigaction = debuggerd_signal_handler;
- act.sa_flags = SA_RESTART | SA_SIGINFO;
- sigemptyset(&act.sa_mask);
-
- sigaction(SIGILL, &act, NULL);
- sigaction(SIGABRT, &act, NULL);
- sigaction(SIGBUS, &act, NULL);
- sigaction(SIGFPE, &act, NULL);
- sigaction(SIGSEGV, &act, NULL);
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ action.sa_sigaction = debuggerd_signal_handler;
+ action.sa_flags = SA_RESTART | SA_SIGINFO;
+
+ // Use the alternate signal stack if available so we can catch stack overflows.
+ action.sa_flags |= SA_ONSTACK;
+
+ sigaction(SIGABRT, &action, NULL);
+ sigaction(SIGBUS, &action, NULL);
+ sigaction(SIGFPE, &action, NULL);
+ sigaction(SIGILL, &action, NULL);
+ sigaction(SIGPIPE, &action, NULL);
+ sigaction(SIGSEGV, &action, NULL);
#if defined(SIGSTKFLT)
- sigaction(SIGSTKFLT, &act, NULL);
+ sigaction(SIGSTKFLT, &action, NULL);
#endif
- sigaction(SIGPIPE, &act, NULL);
+ sigaction(SIGTRAP, &action, NULL);
}