summaryrefslogtreecommitdiffstats
path: root/debuggerd/tombstone.c
diff options
context:
space:
mode:
Diffstat (limited to 'debuggerd/tombstone.c')
-rw-r--r--debuggerd/tombstone.c149
1 files changed, 105 insertions, 44 deletions
diff --git a/debuggerd/tombstone.c b/debuggerd/tombstone.c
index da5f03c..77f6ef1 100644
--- a/debuggerd/tombstone.c
+++ b/debuggerd/tombstone.c
@@ -35,6 +35,9 @@
#include <corkscrew/demangle.h>
#include <corkscrew/backtrace.h>
+#include <sys/socket.h>
+#include <linux/un.h>
+
#include <selinux/android.h>
#include "machine.h"
@@ -47,6 +50,9 @@
#define MAX_TOMBSTONES 10
#define TOMBSTONE_DIR "/data/tombstones"
+/* Must match the path defined in NativeCrashListener.java */
+#define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
+
#define typecheck(x,y) { \
typeof(x) __dummy1; \
typeof(y) __dummy2; \
@@ -157,7 +163,7 @@ static void dump_revision_info(log_t* log)
property_get("ro.revision", revision, "unknown");
- _LOG(log, false, "Revision: '%s'\n", revision);
+ _LOG(log, SCOPE_AT_FAULT, "Revision: '%s'\n", revision);
}
static void dump_build_info(log_t* log)
@@ -166,7 +172,7 @@ static void dump_build_info(log_t* log)
property_get("ro.build.fingerprint", fingerprint, "unknown");
- _LOG(log, false, "Build fingerprint: '%s'\n", fingerprint);
+ _LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
}
static void dump_fault_addr(log_t* log, pid_t tid, int sig)
@@ -174,15 +180,15 @@ static void dump_fault_addr(log_t* log, pid_t tid, int sig)
siginfo_t si;
memset(&si, 0, sizeof(si));
- if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
- _LOG(log, false, "cannot get siginfo: %s\n", strerror(errno));
+ if(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
+ _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
} else if (signal_has_address(sig)) {
- _LOG(log, false, "signal %d (%s), code %d (%s), fault addr %08x\n",
+ _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %08x\n",
sig, get_signame(sig),
si.si_code, get_sigcode(sig, si.si_code),
(uintptr_t) si.si_addr);
} else {
- _LOG(log, false, "signal %d (%s), code %d (%s), fault addr --------\n",
+ _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr --------\n",
sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
}
}
@@ -215,19 +221,20 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, bool at_fault) {
fclose(fp);
}
- _LOG(log, false, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
+ _LOG(log, SCOPE_AT_FAULT, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
threadname ? threadname : "UNKNOWN",
procname ? procname : "UNKNOWN");
} else {
- _LOG(log, true, "pid: %d, tid: %d, name: %s\n", pid, tid,
- threadname ? threadname : "UNKNOWN");
+ _LOG(log, 0, "pid: %d, tid: %d, name: %s\n",
+ pid, tid, threadname ? threadname : "UNKNOWN");
}
}
static void dump_backtrace(const ptrace_context_t* context __attribute((unused)),
log_t* log, pid_t tid __attribute((unused)), bool at_fault,
const backtrace_frame_t* backtrace, size_t frames) {
- _LOG(log, !at_fault, "\nbacktrace:\n");
+ int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
+ _LOG(log, scopeFlags, "\nbacktrace:\n");
backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols);
@@ -235,13 +242,13 @@ static void dump_backtrace(const ptrace_context_t* context __attribute((unused))
char line[MAX_BACKTRACE_LINE_LENGTH];
format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
line, MAX_BACKTRACE_LINE_LENGTH);
- _LOG(log, !at_fault, " %s\n", line);
+ _LOG(log, scopeFlags, " %s\n", line);
}
free_backtrace_symbols(backtrace_symbols, frames);
}
static void dump_stack_segment(const ptrace_context_t* context, log_t* log, pid_t tid,
- bool only_in_tombstone, uintptr_t* sp, size_t words, int label) {
+ int scopeFlags, uintptr_t* sp, size_t words, int label) {
for (size_t i = 0; i < words; i++) {
uint32_t stack_content;
if (!try_get_word_ptrace(tid, *sp, &stack_content)) {
@@ -258,28 +265,28 @@ static void dump_stack_segment(const ptrace_context_t* context, log_t* log, pid_
uint32_t offset = stack_content - (mi->start + symbol->start);
if (!i && label >= 0) {
if (offset) {
- _LOG(log, only_in_tombstone, " #%02d %08x %08x %s (%s+%u)\n",
+ _LOG(log, scopeFlags, " #%02d %08x %08x %s (%s+%u)\n",
label, *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
} else {
- _LOG(log, only_in_tombstone, " #%02d %08x %08x %s (%s)\n",
+ _LOG(log, scopeFlags, " #%02d %08x %08x %s (%s)\n",
label, *sp, stack_content, mi ? mi->name : "", symbol_name);
}
} else {
if (offset) {
- _LOG(log, only_in_tombstone, " %08x %08x %s (%s+%u)\n",
+ _LOG(log, scopeFlags, " %08x %08x %s (%s+%u)\n",
*sp, stack_content, mi ? mi->name : "", symbol_name, offset);
} else {
- _LOG(log, only_in_tombstone, " %08x %08x %s (%s)\n",
+ _LOG(log, scopeFlags, " %08x %08x %s (%s)\n",
*sp, stack_content, mi ? mi->name : "", symbol_name);
}
}
free(demangled_name);
} else {
if (!i && label >= 0) {
- _LOG(log, only_in_tombstone, " #%02d %08x %08x %s\n",
+ _LOG(log, scopeFlags, " #%02d %08x %08x %s\n",
label, *sp, stack_content, mi ? mi->name : "");
} else {
- _LOG(log, only_in_tombstone, " %08x %08x %s\n",
+ _LOG(log, scopeFlags, " %08x %08x %s\n",
*sp, stack_content, mi ? mi->name : "");
}
}
@@ -305,28 +312,28 @@ static void dump_stack(const ptrace_context_t* context, log_t* log, pid_t tid, b
return;
}
- _LOG(log, !at_fault, "\nstack:\n");
+ int scopeFlags = SCOPE_SENSITIVE | (at_fault ? SCOPE_AT_FAULT : 0);
+ _LOG(log, scopeFlags, "\nstack:\n");
// Dump a few words before the first frame.
- bool only_in_tombstone = !at_fault;
uintptr_t sp = backtrace[first].stack_top - STACK_WORDS * sizeof(uint32_t);
- dump_stack_segment(context, log, tid, only_in_tombstone, &sp, STACK_WORDS, -1);
+ dump_stack_segment(context, log, tid, scopeFlags, &sp, STACK_WORDS, -1);
// Dump a few words from all successive frames.
// Only log the first 3 frames, put the rest in the tombstone.
for (size_t i = first; i <= last; i++) {
const backtrace_frame_t* frame = &backtrace[i];
if (sp != frame->stack_top) {
- _LOG(log, only_in_tombstone, " ........ ........\n");
+ _LOG(log, scopeFlags, " ........ ........\n");
sp = frame->stack_top;
}
if (i - first == 3) {
- only_in_tombstone = true;
+ scopeFlags &= (~SCOPE_AT_FAULT);
}
if (i == last) {
- dump_stack_segment(context, log, tid, only_in_tombstone, &sp, STACK_WORDS, i);
+ dump_stack_segment(context, log, tid, scopeFlags, &sp, STACK_WORDS, i);
if (sp < frame->stack_top + frame->stack_size) {
- _LOG(log, only_in_tombstone, " ........ ........\n");
+ _LOG(log, scopeFlags, " ........ ........\n");
}
} else {
size_t words = frame->stack_size / sizeof(uint32_t);
@@ -335,7 +342,7 @@ static void dump_stack(const ptrace_context_t* context, log_t* log, pid_t tid, b
} else if (words > STACK_WORDS) {
words = STACK_WORDS;
}
- dump_stack_segment(context, log, tid, only_in_tombstone, &sp, words, i);
+ dump_stack_segment(context, log, tid, scopeFlags, &sp, words, i);
}
}
}
@@ -350,23 +357,24 @@ static void dump_backtrace_and_stack(const ptrace_context_t* context, log_t* log
}
}
-static void dump_map(log_t* log, map_info_t* m, const char* what) {
+static void dump_map(log_t* log, map_info_t* m, const char* what, int scopeFlags) {
if (m != NULL) {
- _LOG(log, false, " %08x-%08x %c%c%c %s\n", m->start, m->end,
+ _LOG(log, scopeFlags, " %08x-%08x %c%c%c %s\n", m->start, m->end,
m->is_readable ? 'r' : '-',
m->is_writable ? 'w' : '-',
m->is_executable ? 'x' : '-',
m->name);
} else {
- _LOG(log, false, " (no %s)\n", what);
+ _LOG(log, scopeFlags, " (no %s)\n", what);
}
}
-static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t tid) {
+static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault) {
+ int scopeFlags = SCOPE_SENSITIVE | (at_fault ? SCOPE_AT_FAULT : 0);
siginfo_t si;
memset(&si, 0, sizeof(si));
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
- _LOG(log, false, "cannot get siginfo for %d: %s\n",
+ _LOG(log, scopeFlags, "cannot get siginfo for %d: %s\n",
tid, strerror(errno));
return;
}
@@ -380,7 +388,7 @@ static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t
return;
}
- _LOG(log, false, "\nmemory map around fault addr %08x:\n", (int)si.si_addr);
+ _LOG(log, scopeFlags, "\nmemory map around fault addr %08x:\n", (int)si.si_addr);
/*
* Search for a match, or for a hole where the match would be. The list
@@ -408,9 +416,9 @@ static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t
* Show "next" then "match" then "prev" so that the addresses appear in
* ascending order (like /proc/pid/maps).
*/
- dump_map(log, next, "map below");
- dump_map(log, map, "map for address");
- dump_map(log, prev, "map above");
+ dump_map(log, next, "map below", scopeFlags);
+ dump_map(log, map, "map for address", scopeFlags);
+ dump_map(log, prev, "map above", scopeFlags);
}
static void dump_thread(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault,
@@ -421,7 +429,7 @@ static void dump_thread(const ptrace_context_t* context, log_t* log, pid_t tid,
dump_backtrace_and_stack(context, log, tid, at_fault);
if (at_fault) {
dump_memory_and_code(context, log, tid, at_fault);
- dump_nearby_maps(context, log, tid);
+ dump_nearby_maps(context, log, tid, at_fault);
}
}
@@ -458,7 +466,7 @@ static bool dump_sibling_thread_report(const ptrace_context_t* context,
continue;
}
- _LOG(log, true, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
+ _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
dump_thread_info(log, pid, new_tid, false);
dump_thread(context, log, new_tid, false, total_sleep_time_usec);
@@ -511,12 +519,12 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename,
/* non-blocking EOF; we're done */
break;
} else {
- _LOG(log, true, "Error while reading log: %s\n",
+ _LOG(log, 0, "Error while reading log: %s\n",
strerror(errno));
break;
}
} else if (actual == 0) {
- _LOG(log, true, "Got zero bytes while reading log: %s\n",
+ _LOG(log, 0, "Got zero bytes while reading log: %s\n",
strerror(errno));
break;
}
@@ -536,7 +544,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename,
}
if (first) {
- _LOG(log, true, "--------- %slog %s\n",
+ _LOG(log, 0, "--------- %slog %s\n",
tailOnly ? "tail end of " : "", filename);
first = false;
}
@@ -578,7 +586,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename,
shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
shortLogCount++;
} else {
- _LOG(log, true, "%s.%03d %5d %5d %c %-8s: %s\n",
+ _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
prioChar, tag, msg);
}
@@ -598,7 +606,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename,
}
for (i = 0; i < shortLogCount; i++) {
- _LOG(log, true, "%s\n", shortLog[shortLogNext]);
+ _LOG(log, 0, "%s\n", shortLog[shortLogNext]);
shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
}
}
@@ -648,7 +656,7 @@ static void dump_abort_message(log_t* log, pid_t tid, uintptr_t address) {
}
msg[sizeof(msg) - 1] = '\0';
- _LOG(log, false, "Abort message: '%s'\n", msg);
+ _LOG(log, SCOPE_AT_FAULT, "Abort message: '%s'\n", msg);
}
/*
@@ -662,7 +670,19 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a
property_get("ro.debuggable", value, "0");
bool want_logs = (value[0] == '1');
- _LOG(log, false,
+ if (log->amfd >= 0) {
+ /*
+ * Activity Manager protocol: binary 32-bit network-byte-order ints for the
+ * pid and signal number, followed by the raw text of the dump, culminating
+ * in a zero byte that marks end-of-data.
+ */
+ uint32_t datum = htonl(pid);
+ TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
+ datum = htonl(signal);
+ TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
+ }
+
+ _LOG(log, SCOPE_AT_FAULT,
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
dump_build_info(log);
dump_revision_info(log);
@@ -689,6 +709,16 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a
if (want_logs) {
dump_logs(log, pid, false);
}
+
+ /* send EOD to the Activity Manager, then wait for its ack to avoid racing ahead
+ * and killing the target out from under it */
+ if (log->amfd >= 0) {
+ uint8_t eodMarker = 0;
+ TEMP_FAILURE_RETRY( write(log->amfd, &eodMarker, 1) );
+ /* 3 sec timeout reading the ack; we're fine if that happens */
+ TEMP_FAILURE_RETRY( read(log->amfd, &eodMarker, 1) );
+ }
+
return detach_failed;
}
@@ -748,6 +778,35 @@ static char* find_and_open_tombstone(int* fd)
return strdup(path);
}
+static int activity_manager_connect() {
+ int amfd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (amfd >= 0) {
+ struct sockaddr_un address;
+ int err;
+
+ memset(&address, 0, sizeof(address));
+ address.sun_family = AF_UNIX;
+ strncpy(address.sun_path, NCRASH_SOCKET_PATH, sizeof(address.sun_path));
+ err = TEMP_FAILURE_RETRY( connect(amfd, (struct sockaddr*) &address, sizeof(address)) );
+ if (!err) {
+ struct timeval tv;
+ memset(&tv, 0, sizeof(tv));
+ tv.tv_sec = 1; // tight leash
+ err = setsockopt(amfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+ if (!err) {
+ tv.tv_sec = 3; // 3 seconds on handshake read
+ err = setsockopt(amfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+ }
+ }
+ if (err) {
+ close(amfd);
+ amfd = -1;
+ }
+ }
+
+ return amfd;
+}
+
char* engrave_tombstone(pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
bool dump_sibling_threads, bool quiet, bool* detach_failed,
int* total_sleep_time_usec) {
@@ -768,10 +827,12 @@ char* engrave_tombstone(pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_ad
log_t log;
log.tfd = fd;
+ log.amfd = activity_manager_connect();
log.quiet = quiet;
*detach_failed = dump_crash(&log, pid, tid, signal, abort_msg_address, dump_sibling_threads,
total_sleep_time_usec);
+ close(log.amfd);
close(fd);
return path;
}