summaryrefslogtreecommitdiffstats
path: root/linker/debugger.c
diff options
context:
space:
mode:
Diffstat (limited to 'linker/debugger.c')
-rw-r--r--linker/debugger.c53
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()