void debugger_signal_handler(int n) { unsigned tid; int s; /* avoid picking up GC interrupts */ signal(SIGUSR1, SIG_IGN); tid = gettid(); s = socket_local_client("android:debuggerd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); if(s >= 0) { /* debugger knows our pid from the credentials on the * local socket but we need to tell it our tid. It * is paranoid and will verify that we are giving a tid * that's actually in our process */ int ret; RETRY_ON_EINTR(ret, write(s, &tid, sizeof(unsigned))); if (ret == sizeof(unsigned)) { /* if the write failed, there is no point to read on * the file descriptor. */ RETRY_ON_EINTR(ret, read(s, &tid, 1)); notify_gdb_of_libraries(); } close(s); } /* remove our net so we fault for real when we return */ signal(n, SIG_IGN); }
static void send_debuggerd_packet(siginfo_t* info) { int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM); if (s == -1) { __libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s", strerror(errno)); return; } // debuggerd knows our pid from the credentials on the // local socket but we need to tell it the tid of the crashing thread. // debuggerd will be paranoid and verify that we sent a tid // that's actually in our process. debugger_msg_t msg; msg.action = DEBUGGER_ACTION_CRASH; msg.tid = gettid(); msg.abort_msg_address = reinterpret_cast<uintptr_t>(g_abort_message); msg.original_si_code = (info != NULL) ? info->si_code : 0; int ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))); if (ret == sizeof(msg)) { char debuggerd_ack; ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1)); int saved_errno = errno; notify_gdb_of_libraries(); errno = saved_errno; } else { // read or write failed -- broken connection? __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s", strerror(errno)); } close(s); }
static void send_debuggerd_packet(siginfo_t* info) { if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) { // process has disabled core dumps and PTRACE_ATTACH, and does not want to be dumped. // Honor that intention by not connecting to debuggerd and asking it // to dump our internal state. __libc_format_log(ANDROID_LOG_INFO, "libc", "Suppressing debuggerd output because prctl(PR_GET_DUMPABLE)==0"); return; } int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM); if (s == -1) { __libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s", strerror(errno)); return; } // debuggerd knows our pid from the credentials on the // local socket but we need to tell it the tid of the crashing thread. // debuggerd will be paranoid and verify that we sent a tid // that's actually in our process. debugger_msg_t msg; msg.action = DEBUGGER_ACTION_CRASH; msg.tid = gettid(); msg.abort_msg_address = reinterpret_cast<uintptr_t>(g_abort_message); msg.original_si_code = (info != NULL) ? info->si_code : 0; int ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))); if (ret == sizeof(msg)) { char debuggerd_ack; ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1)); int saved_errno = errno; notify_gdb_of_libraries(); errno = saved_errno; } else { // read or write failed -- broken connection? __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s", strerror(errno)); } close(s); }
/* * Catches fatal signals so we can ask debuggerd to ptrace us before * we crash. */ void debugger_signal_handler(int n, siginfo_t* info, void*) { char msgbuf[128]; /* * It's possible somebody cleared the SA_SIGINFO flag, which would mean * our "info" arg holds an undefined value. */ if (!haveSiginfo(n)) { info = NULL; } logSignalSummary(n, info); pid_t tid = gettid(); int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM); if (s >= 0) { /* debugger knows our pid from the credentials on the * local socket but we need to tell it our tid. It * is paranoid and will verify that we are giving a tid * that's actually in our process */ int ret; debugger_msg_t msg; msg.action = DEBUGGER_ACTION_CRASH; msg.tid = tid; ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))); if (ret == sizeof(msg)) { /* if the write failed, there is no point to read on * the file descriptor. */ ret = TEMP_FAILURE_RETRY(read(s, &tid, 1)); int saved_errno = errno; notify_gdb_of_libraries(); errno = saved_errno; } if (ret < 0) { /* read or write failed -- broken connection? */ format_buffer(msgbuf, sizeof(msgbuf), "Failed while talking to debuggerd: %s", strerror(errno)); __libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf); } close(s); } else { /* socket failed; maybe process ran out of fds */ format_buffer(msgbuf, sizeof(msgbuf), "Unable to open connection to debuggerd: %s", strerror(errno)); __libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf); } /* remove our net so we fault for real when we return */ signal(n, SIG_DFL); /* * These signals are not re-thrown when we resume. This means that * crashing due to (say) SIGPIPE doesn't work the way you'd expect it * to. We work around this by throwing them manually. We don't want * to do this for *all* signals because it'll screw up the address for * faults like SIGSEGV. */ switch (n) { case SIGABRT: case SIGFPE: case SIGPIPE: #ifdef SIGSTKFLT case SIGSTKFLT: #endif (void) tgkill(getpid(), gettid(), n); break; default: // SIGILL, SIGBUS, SIGSEGV break; } }
/* * Catches fatal signals so we can ask debuggerd to ptrace us before * we crash. */ void debuggerd_signal_handler(int n, siginfo_t* info, void*) { /* * It's possible somebody cleared the SA_SIGINFO flag, which would mean * our "info" arg holds an undefined value. */ if (!have_siginfo(n)) { info = NULL; } log_signal_summary(n, info); pid_t tid = gettid(); int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM); if (s >= 0) { // debuggerd knows our pid from the credentials on the // local socket but we need to tell it the tid of the crashing thread. // debuggerd will be paranoid and verify that we sent a tid // that's actually in our process. debugger_msg_t msg; msg.action = DEBUGGER_ACTION_CRASH; msg.tid = tid; msg.abort_msg_address = reinterpret_cast<uintptr_t>(gAbortMessage); int ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))); if (ret == sizeof(msg)) { #ifdef HAVE_AEE_FEATURE int tmppid = getpid(); __libc_format_log(ANDROID_LOG_FATAL, "libc", "Send stop signal to pid:%d in %s", tmppid, __func__); kill(tmppid, SIGSTOP); #endif // if the write failed, there is no point trying to read a response. ret = TEMP_FAILURE_RETRY(read(s, &tid, 1)); int saved_errno = errno; notify_gdb_of_libraries(); errno = saved_errno; } if (ret < 0) { /* read or write failed -- broken connection? */ __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s", strerror(errno)); } close(s); } else { /* socket failed; maybe process ran out of fds */ __libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s", strerror(errno)); } /* remove our net so we fault for real when we return */ signal(n, SIG_DFL); /* * These signals are not re-thrown when we resume. This means that * crashing due to (say) SIGPIPE doesn't work the way you'd expect it * to. We work around this by throwing them manually. We don't want * to do this for *all* signals because it'll screw up the address for * faults like SIGSEGV. */ switch (n) { case SIGABRT: case SIGFPE: case SIGPIPE: #ifdef SIGSTKFLT case SIGSTKFLT: #endif (void) tgkill(getpid(), gettid(), n); break; default: // SIGILL, SIGBUS, SIGSEGV break; } }