diff options
Diffstat (limited to 'linker/debugger.c')
| -rw-r--r-- | linker/debugger.c | 53 |
1 files changed, 50 insertions, 3 deletions
diff --git a/linker/debugger.c b/linker/debugger.c index 648dc78..899a5b2 100644 --- a/linker/debugger.c +++ b/linker/debugger.c @@ -32,6 +32,7 @@ #include <ctype.h> #include <signal.h> #include <sys/mman.h> +#include <sys/prctl.h> #include <errno.h> #include "linker.h" @@ -39,6 +40,8 @@ #include <sys/socket.h> #include <sys/un.h> +extern int tgkill(int tgid, int tid, int sig); + void notify_gdb_of_libraries(); #define RETRY_ON_EINTR(ret,cond) \ @@ -46,6 +49,8 @@ void notify_gdb_of_libraries(); ret = (cond); \ } while (ret < 0 && errno == EINTR) +// 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) { @@ -100,6 +105,7 @@ static int socket_abstract_client(const char *name, int type) static void logSignalSummary(int signum, const siginfo_t* info) { char buffer[128]; + char threadname[MAX_TASK_NAME_LEN + 1]; // one more for termination char* signame; switch (signum) { @@ -113,9 +119,16 @@ static void logSignalSummary(int signum, const siginfo_t* info) default: signame = "???"; break; } + if (prctl(PR_GET_NAME, (unsigned long)threadname, 0, 0, 0) != 0) { + strcpy(threadname, "<name unknown>"); + } else { + // short names are null terminated by prctl, but the manpage + // implies that 16 byte names are not. + threadname[MAX_TASK_NAME_LEN] = 0; + } format_buffer(buffer, sizeof(buffer), - "Fatal signal %d (%s) at 0x%08x (code=%d)", - signum, signame, info->si_addr, info->si_code); + "Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)", + signum, signame, info->si_addr, info->si_code, gettid(), threadname); __libc_android_log_write(ANDROID_LOG_FATAL, "libc", buffer); } @@ -126,6 +139,7 @@ static void logSignalSummary(int signum, const siginfo_t* info) */ void debugger_signal_handler(int n, siginfo_t* info, void* unused) { + char msgbuf[128]; unsigned tid; int s; @@ -134,7 +148,7 @@ void debugger_signal_handler(int n, siginfo_t* info, void* unused) tid = gettid(); s = socket_abstract_client("android:debuggerd", SOCK_STREAM); - if(s >= 0) { + 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 @@ -147,13 +161,46 @@ void debugger_signal_handler(int n, siginfo_t* info, void* unused) /* if the write failed, there is no point to read on * the file descriptor. */ RETRY_ON_EINTR(ret, read(s, &tid, 1)); + int savedErrno = errno; notify_gdb_of_libraries(); + errno = savedErrno; + } + + 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: + case SIGSTKFLT: + (void) tgkill(getpid(), gettid(), n); + break; + default: // SIGILL, SIGBUS, SIGSEGV + break; + } } void debugger_init() |
