diff options
author | Josh Gao <jmgao@google.com> | 2016-06-15 18:33:26 -0700 |
---|---|---|
committer | Josh Gao <jmgao@google.com> | 2016-06-15 18:33:26 -0700 |
commit | 3cc387eff4faaaf02a879518fc4139896b60b79a (patch) | |
tree | 2aa1ee4c122b486fbe5309dc9b0b1bcacac300c0 | |
parent | 112be469bb0671f19f4f61e021693595384142fa (diff) | |
download | bionic-3cc387eff4faaaf02a879518fc4139896b60b79a.tar.gz |
Lose debuggerd client code to libdebuggerd_client.
Bug: http://b/24414818
Change-Id: I524714e081a27df4d2046f0c8eb853a1b20592e6
-rw-r--r-- | linker/Android.mk | 10 | ||||
-rw-r--r-- | linker/debugger.cpp | 321 | ||||
-rw-r--r-- | linker/linker.cpp | 10 | ||||
-rw-r--r-- | linker/linker.h | 3 |
4 files changed, 17 insertions, 327 deletions
diff --git a/linker/Android.mk b/linker/Android.mk index c37d6db67..29520f9e2 100644 --- a/linker/Android.mk +++ b/linker/Android.mk @@ -19,7 +19,6 @@ include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_SRC_FILES := \ - debugger.cpp \ dlfcn.cpp \ linker.cpp \ linker_block_allocator.cpp \ @@ -76,7 +75,14 @@ LOCAL_ASFLAGS := $(LOCAL_CFLAGS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_STATIC_LIBRARIES := libc_nomalloc libziparchive libutils libbase libz liblog +LOCAL_STATIC_LIBRARIES := \ + libc_nomalloc \ + libziparchive \ + libutils \ + libbase \ + libz \ + liblog \ + libdebuggerd_client # Important: The liblinker_malloc should be the last library in the list # to overwrite any other malloc implementations by other static libraries. diff --git a/linker/debugger.cpp b/linker/debugger.cpp deleted file mode 100644 index d4c7928f5..000000000 --- a/linker/debugger.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "linker.h" -#include "linker_gdb_support.h" - -#include <errno.h> -#include <inttypes.h> -#include <pthread.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/mman.h> -#include <sys/prctl.h> -#include <sys/socket.h> -#include <sys/syscall.h> -#include <sys/un.h> -#include <unistd.h> - -extern "C" int tgkill(int tgid, int tid, int sig); - -// Crash actions have to be sent to the proper debuggerd. -// On 64 bit systems, the 32 bit debuggerd is named differently. -#if defined(TARGET_IS_64_BIT) && !defined(__LP64__) -#define DEBUGGER_SOCKET_NAME "android:debuggerd32" -#else -#define DEBUGGER_SOCKET_NAME "android:debuggerd" -#endif - -enum debugger_action_t { - // dump a crash - DEBUGGER_ACTION_CRASH, - // dump a tombstone file - DEBUGGER_ACTION_DUMP_TOMBSTONE, - // dump a backtrace only back to the socket - DEBUGGER_ACTION_DUMP_BACKTRACE, -}; - -// Message sent over the socket. -// NOTE: Any changes to this structure must also be reflected in -// system/core/include/cutils/debugger.h. -struct __attribute__((packed)) debugger_msg_t { - int32_t action; - pid_t tid; - uint64_t abort_msg_address; - int32_t original_si_code; -}; - -// see man(2) prctl, specifically the section about PR_GET_NAME -#define MAX_TASK_NAME_LEN (16) - -static int socket_abstract_client(const char* name, int type) { - sockaddr_un addr; - - // Test with length +1 for the *initial* '\0'. - size_t namelen = strlen(name); - if ((namelen + 1) > sizeof(addr.sun_path)) { - errno = EINVAL; - return -1; - } - - // This is used for abstract socket namespace, we need - // an initial '\0' at the start of the Unix socket path. - // - // Note: The path in this case is *not* supposed to be - // '\0'-terminated. ("man 7 unix" for the gory details.) - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_LOCAL; - addr.sun_path[0] = 0; - memcpy(addr.sun_path + 1, name, namelen); - - socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1; - - int s = socket(AF_LOCAL, type, 0); - if (s == -1) { - return -1; - } - - int rc = TEMP_FAILURE_RETRY(connect(s, reinterpret_cast<sockaddr*>(&addr), alen)); - if (rc == -1) { - close(s); - return -1; - } - - return s; -} - -/* - * Writes a summary of the signal to the log file. We do this so that, if - * for some reason we're not able to contact debuggerd, there is still some - * indication of the failure in the log. - * - * We could be here as a result of native heap corruption, or while a - * mutex is being held, so we don't want to use any libc functions that - * could allocate memory or hold a lock. - */ -static void log_signal_summary(int signum, const siginfo_t* info) { - const char* signal_name = "???"; - bool has_address = false; - switch (signum) { - case SIGABRT: - signal_name = "SIGABRT"; - break; - case SIGBUS: - signal_name = "SIGBUS"; - has_address = true; - break; - case SIGFPE: - signal_name = "SIGFPE"; - has_address = true; - break; - case SIGILL: - signal_name = "SIGILL"; - has_address = true; - break; - case SIGSEGV: - signal_name = "SIGSEGV"; - has_address = true; - break; -#if defined(SIGSTKFLT) - case SIGSTKFLT: - signal_name = "SIGSTKFLT"; - break; -#endif - case SIGTRAP: - signal_name = "SIGTRAP"; - break; - } - - char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination - if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) { - strcpy(thread_name, "<name unknown>"); - } else { - // short names are null terminated by prctl, but the man page - // implies that 16 byte names are not. - thread_name[MAX_TASK_NAME_LEN] = 0; - } - - // "info" will be null if the siginfo_t information was not available. - // Many signals don't have an address or a code. - char code_desc[32]; // ", code -6" - char addr_desc[32]; // ", fault addr 0x1234" - addr_desc[0] = code_desc[0] = 0; - if (info != nullptr) { - // For a rethrown signal, this si_code will be right and the one debuggerd shows will - // always be SI_TKILL. - __libc_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code); - if (has_address) { - __libc_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr); - } - } - __libc_format_log(ANDROID_LOG_FATAL, "libc", - "Fatal signal %d (%s)%s%s in tid %d (%s)", - signum, signal_name, code_desc, addr_desc, gettid(), thread_name); -} - -/* - * Returns true if the handler for signal "signum" has SA_SIGINFO set. - */ -static bool have_siginfo(int signum) { - struct sigaction old_action, new_action; - - 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, &new_action, &old_action) < 0) { - __libc_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s", - strerror(errno)); - return false; - } - bool result = (old_action.sa_flags & SA_SIGINFO) != 0; - - if (sigaction(signum, &old_action, nullptr) == -1) { - __libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s", - strerror(errno)); - } - return result; -} - -static void send_debuggerd_packet(siginfo_t* info) { - // Mutex to prevent multiple crashing threads from trying to talk - // to debuggerd at the same time. - static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER; - int ret = pthread_mutex_trylock(&crash_mutex); - if (ret != 0) { - if (ret == EBUSY) { - __libc_format_log(ANDROID_LOG_INFO, "libc", - "Another thread contacted debuggerd first; not contacting debuggerd."); - // This will never complete since the lock is never released. - pthread_mutex_lock(&crash_mutex); - } else { - __libc_format_log(ANDROID_LOG_INFO, "libc", - "pthread_mutex_trylock failed: %s", strerror(ret)); - } - return; - } - - int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM | SOCK_CLOEXEC); - 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 != nullptr) ? info->si_code : 0; - 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. - */ -static void debuggerd_signal_handler(int signal_number, 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(signal_number)) { - info = nullptr; - } - - log_signal_summary(signal_number, info); - - send_debuggerd_packet(info); - - // We need to return from the signal handler so that debuggerd can dump the - // thread that crashed, but returning here does not guarantee that the signal - // will be thrown again, even for SIGSEGV and friends, since the signal could - // have been sent manually. Resend the signal with rt_tgsigqueueinfo(2) to - // preserve the SA_SIGINFO contents. - signal(signal_number, SIG_DFL); - - struct siginfo si; - if (!info) { - memset(&si, 0, sizeof(si)); - si.si_code = SI_USER; - si.si_pid = getpid(); - si.si_uid = getuid(); - info = &si; - } else if (info->si_code >= 0 || info->si_code == SI_TKILL) { - // rt_tgsigqueueinfo(2)'s documentation appears to be incorrect on kernels - // that contain commit 66dd34a (3.9+). The manpage claims to only allow - // negative si_code values that are not SI_TKILL, but 66dd34a changed the - // check to allow all si_code values in calls coming from inside the house. - } - - int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), signal_number, info); - if (rc != 0) { - __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to resend signal during crash: %s", - strerror(errno)); - _exit(0); - } -} - -__LIBC_HIDDEN__ void debuggerd_init() { - 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, nullptr); - sigaction(SIGBUS, &action, nullptr); - sigaction(SIGFPE, &action, nullptr); - sigaction(SIGILL, &action, nullptr); - sigaction(SIGSEGV, &action, nullptr); -#if defined(SIGSTKFLT) - sigaction(SIGSTKFLT, &action, nullptr); -#endif - sigaction(SIGTRAP, &action, nullptr); -} diff --git a/linker/linker.cpp b/linker/linker.cpp index 9eb3a65c7..8f51533cf 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -61,6 +61,7 @@ #include "linker_utils.h" #include "android-base/strings.h" +#include "debuggerd/client.h" #include "ziparchive/zip_archive.h" extern void __libc_init_globals(KernelArgumentBlock&); @@ -4060,7 +4061,14 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( // Initialize system properties __system_properties_init(); // may use 'environ' - debuggerd_init(); + // Register the debuggerd signal handler. + debuggerd_callbacks_t callbacks = { + .get_abort_message = []() { + return g_abort_message; + }, + .post_dump = ¬ify_gdb_of_libraries, + }; + debuggerd_init(&callbacks); // Get a few environment variables. const char* LD_DEBUG = getenv("LD_DEBUG"); diff --git a/linker/linker.h b/linker/linker.h index 6eab00c3e..fbd236ff7 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -461,9 +461,6 @@ bool do_dlsym(void* handle, const char* sym_name, const char* sym_ver, int do_dladdr(const void* addr, Dl_info* info); -void debuggerd_init(); -extern "C" abort_msg_t* g_abort_message; - char* linker_get_error_buffer(); size_t linker_get_error_buffer_size(); |