diff options
Diffstat (limited to 'debuggerd')
-rw-r--r-- | debuggerd/Android.mk | 5 | ||||
-rw-r--r-- | debuggerd/arm/machine.c | 37 | ||||
-rw-r--r-- | debuggerd/backtrace.c | 18 | ||||
-rw-r--r-- | debuggerd/backtrace.h | 2 | ||||
-rw-r--r-- | debuggerd/debuggerd.c | 13 | ||||
-rw-r--r-- | debuggerd/mips/machine.c | 39 | ||||
-rw-r--r-- | debuggerd/tombstone.c | 149 | ||||
-rw-r--r-- | debuggerd/utility.c | 44 | ||||
-rw-r--r-- | debuggerd/utility.h | 24 | ||||
-rw-r--r-- | debuggerd/x86/machine.c | 12 |
10 files changed, 231 insertions, 112 deletions
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk index 3fca64f..8621e9c 100644 --- a/debuggerd/Android.mk +++ b/debuggerd/Android.mk @@ -25,6 +25,7 @@ endif # ARCH_ARM_HAVE_VFP_D32 LOCAL_SHARED_LIBRARIES := \ libcutils \ + liblog \ libc \ libcorkscrew \ libselinux @@ -39,7 +40,7 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS += -fstack-protector-all #LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_SHARED_LIBRARIES := libcutils libc +LOCAL_SHARED_LIBRARIES := libcutils liblog libc include $(BUILD_EXECUTABLE) ifeq ($(ARCH_ARM_HAVE_VFP),true) @@ -54,7 +55,7 @@ LOCAL_SRC_FILES := vfp-crasher.c vfp.S LOCAL_MODULE := vfp-crasher LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) LOCAL_MODULE_TAGS := optional -LOCAL_SHARED_LIBRARIES := libcutils libc +LOCAL_SHARED_LIBRARIES := libcutils liblog libc include $(BUILD_EXECUTABLE) endif # ARCH_ARM_HAVE_VFP == true diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c index 160db7b..67e3028 100644 --- a/debuggerd/arm/machine.c +++ b/debuggerd/arm/machine.c @@ -42,7 +42,7 @@ #endif #endif -static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, bool at_fault) { +static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) { char code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */ char ascii_buffer[32]; /* actual 16 + 1 == 17 */ uintptr_t p, end; @@ -102,7 +102,7 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, bool at_fault) { p += 4; } *asc_out = '\0'; - _LOG(log, !at_fault, " %s %s\n", code_buffer, ascii_buffer); + _LOG(log, scopeFlags, " %s %s\n", code_buffer, ascii_buffer); } } @@ -117,6 +117,8 @@ void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)), return; } + int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0; + if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) { static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp"; @@ -132,17 +134,18 @@ void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)), continue; } - _LOG(log, false, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); - dump_memory(log, tid, addr, at_fault); + _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); + dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE); } } - _LOG(log, !at_fault, "\ncode around pc:\n"); - dump_memory(log, tid, (uintptr_t)regs.ARM_pc, at_fault); + /* explicitly allow upload of code dump logging */ + _LOG(log, scopeFlags, "\ncode around pc:\n"); + dump_memory(log, tid, (uintptr_t)regs.ARM_pc, scopeFlags); if (regs.ARM_pc != regs.ARM_lr) { - _LOG(log, !at_fault, "\ncode around lr:\n"); - dump_memory(log, tid, (uintptr_t)regs.ARM_lr, at_fault); + _LOG(log, scopeFlags, "\ncode around lr:\n"); + dump_memory(log, tid, (uintptr_t)regs.ARM_lr, scopeFlags); } } @@ -150,20 +153,20 @@ void dump_registers(const ptrace_context_t* context __attribute((unused)), log_t* log, pid_t tid, bool at_fault) { struct pt_regs r; - bool only_in_tombstone = !at_fault; + int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0; if(ptrace(PTRACE_GETREGS, tid, 0, &r)) { - _LOG(log, only_in_tombstone, "cannot get registers: %s\n", strerror(errno)); + _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno)); return; } - _LOG(log, only_in_tombstone, " r0 %08x r1 %08x r2 %08x r3 %08x\n", + _LOG(log, scopeFlags, " r0 %08x r1 %08x r2 %08x r3 %08x\n", (uint32_t)r.ARM_r0, (uint32_t)r.ARM_r1, (uint32_t)r.ARM_r2, (uint32_t)r.ARM_r3); - _LOG(log, only_in_tombstone, " r4 %08x r5 %08x r6 %08x r7 %08x\n", + _LOG(log, scopeFlags, " r4 %08x r5 %08x r6 %08x r7 %08x\n", (uint32_t)r.ARM_r4, (uint32_t)r.ARM_r5, (uint32_t)r.ARM_r6, (uint32_t)r.ARM_r7); - _LOG(log, only_in_tombstone, " r8 %08x r9 %08x sl %08x fp %08x\n", + _LOG(log, scopeFlags, " r8 %08x r9 %08x sl %08x fp %08x\n", (uint32_t)r.ARM_r8, (uint32_t)r.ARM_r9, (uint32_t)r.ARM_r10, (uint32_t)r.ARM_fp); - _LOG(log, only_in_tombstone, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", + _LOG(log, scopeFlags, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", (uint32_t)r.ARM_ip, (uint32_t)r.ARM_sp, (uint32_t)r.ARM_lr, (uint32_t)r.ARM_pc, (uint32_t)r.ARM_cpsr); @@ -172,14 +175,14 @@ void dump_registers(const ptrace_context_t* context __attribute((unused)), int i; if(ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) { - _LOG(log, only_in_tombstone, "cannot get registers: %s\n", strerror(errno)); + _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno)); return; } for (i = 0; i < NUM_VFP_REGS; i += 2) { - _LOG(log, only_in_tombstone, " d%-2d %016llx d%-2d %016llx\n", + _LOG(log, scopeFlags, " d%-2d %016llx d%-2d %016llx\n", i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]); } - _LOG(log, only_in_tombstone, " scr %08lx\n", vfp_regs.fpscr); + _LOG(log, scopeFlags, " scr %08lx\n", vfp_regs.fpscr); #endif } diff --git a/debuggerd/backtrace.c b/debuggerd/backtrace.c index ba76e7d..f42f24c 100644 --- a/debuggerd/backtrace.c +++ b/debuggerd/backtrace.c @@ -51,15 +51,15 @@ static void dump_process_header(log_t* log, pid_t pid) { localtime_r(&t, &tm); char timestr[64]; strftime(timestr, sizeof(timestr), "%F %T", &tm); - _LOG(log, false, "\n\n----- pid %d at %s -----\n", pid, timestr); + _LOG(log, SCOPE_AT_FAULT, "\n\n----- pid %d at %s -----\n", pid, timestr); if (procname) { - _LOG(log, false, "Cmd line: %s\n", procname); + _LOG(log, SCOPE_AT_FAULT, "Cmd line: %s\n", procname); } } static void dump_process_footer(log_t* log, pid_t pid) { - _LOG(log, false, "\n----- end %d -----\n", pid); + _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid); } static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool attached, @@ -81,10 +81,11 @@ static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool a } } - _LOG(log, false, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid); + _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", + threadname ? threadname : "<unknown>", tid); if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) { - _LOG(log, false, "Could not attach to thread: %s\n", strerror(errno)); + _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno)); return; } @@ -93,7 +94,7 @@ static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool a backtrace_frame_t backtrace[STACK_DEPTH]; ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH); if (frames <= 0) { - _LOG(log, false, "Could not obtain stack trace for thread.\n"); + _LOG(log, SCOPE_AT_FAULT, "Could not obtain stack trace for thread.\n"); } else { backtrace_symbol_t backtrace_symbols[STACK_DEPTH]; get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols); @@ -101,7 +102,7 @@ static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool a char line[MAX_BACKTRACE_LINE_LENGTH]; format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i], line, MAX_BACKTRACE_LINE_LENGTH); - _LOG(log, false, " %s\n", line); + _LOG(log, SCOPE_AT_FAULT, " %s\n", line); } free_backtrace_symbols(backtrace_symbols, frames); } @@ -112,10 +113,11 @@ static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool a } } -void dump_backtrace(int fd, pid_t pid, pid_t tid, bool* detach_failed, +void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, int* total_sleep_time_usec) { log_t log; log.tfd = fd; + log.amfd = amfd; log.quiet = true; ptrace_context_t* context = load_ptrace_context(tid); diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h index ec7d20f..c5c786a 100644 --- a/debuggerd/backtrace.h +++ b/debuggerd/backtrace.h @@ -25,7 +25,7 @@ /* Dumps a backtrace using a format similar to what Dalvik uses so that the result * can be intermixed in a bug report. */ -void dump_backtrace(int fd, pid_t pid, pid_t tid, bool* detach_failed, +void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, int* total_sleep_time_usec); #endif // _DEBUGGERD_BACKTRACE_H diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c index 99e6f13..da2e9b0 100644 --- a/debuggerd/debuggerd.c +++ b/debuggerd/debuggerd.c @@ -203,7 +203,7 @@ static int read_request(int fd, debugger_request_t* out_request) { pollfds[0].revents = 0; status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000)); if (status != 1) { - LOG("timed out reading tid\n"); + LOG("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid); return -1; } @@ -211,13 +211,15 @@ static int read_request(int fd, debugger_request_t* out_request) { memset(&msg, 0, sizeof(msg)); status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg))); if (status < 0) { - LOG("read failure? %s\n", strerror(errno)); + LOG("read failure? %s (pid=%d uid=%d)\n", + strerror(errno), cr.pid, cr.uid); return -1; } if (status == sizeof(debugger_msg_t)) { XLOG("crash request of size %d abort_msg_address=%#08x\n", status, msg.abort_msg_address); } else { - LOG("invalid crash request of size %d\n", status); + LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", + status, cr.pid, cr.uid); return -1; } @@ -250,7 +252,7 @@ static int read_request(int fd, debugger_request_t* out_request) { return -1; } } else { - /* No one else is not allowed to dump arbitrary processes. */ + /* No one else is allowed to dump arbitrary processes. */ return -1; } return 0; @@ -318,7 +320,8 @@ static void handle_request(int fd) { &total_sleep_time_usec); } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) { XLOG("stopped -- dumping to fd\n"); - dump_backtrace(fd, request.pid, request.tid, &detach_failed, + dump_backtrace(fd, -1, + request.pid, request.tid, &detach_failed, &total_sleep_time_usec); } else { XLOG("stopped -- continuing\n"); diff --git a/debuggerd/mips/machine.c b/debuggerd/mips/machine.c index dba1711..65fdf02 100644 --- a/debuggerd/mips/machine.c +++ b/debuggerd/mips/machine.c @@ -36,7 +36,7 @@ #define R(x) ((unsigned int)(x)) -static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, bool at_fault) { +static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) { char code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */ char ascii_buffer[32]; /* actual 16 + 1 == 17 */ uintptr_t p, end; @@ -92,7 +92,7 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, bool at_fault) { p += 4; } *asc_out = '\0'; - _LOG(log, !at_fault, " %s %s\n", code_buffer, ascii_buffer); + _LOG(log, scopeFlags, " %s %s\n", code_buffer, ascii_buffer); } } @@ -107,6 +107,7 @@ void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)), return; } + int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0; if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) { static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra"; @@ -129,20 +130,20 @@ void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)), continue; } - _LOG(log, false, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); - dump_memory(log, tid, addr, at_fault); + _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); + dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE); } } unsigned int pc = R(r.cp0_epc); unsigned int ra = R(r.regs[31]); - _LOG(log, !at_fault, "\ncode around pc:\n"); - dump_memory(log, tid, (uintptr_t)pc, at_fault); + _LOG(log, scopeFlags, "\ncode around pc:\n"); + dump_memory(log, tid, (uintptr_t)pc, scopeFlags); if (pc != ra) { - _LOG(log, !at_fault, "\ncode around ra:\n"); - dump_memory(log, tid, (uintptr_t)ra, at_fault); + _LOG(log, scopeFlags, "\ncode around ra:\n"); + dump_memory(log, tid, (uintptr_t)ra, scopeFlags); } } @@ -150,29 +151,29 @@ void dump_registers(const ptrace_context_t* context __attribute((unused)), log_t* log, pid_t tid, bool at_fault) { pt_regs_mips_t r; - bool only_in_tombstone = !at_fault; + int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0; if(ptrace(PTRACE_GETREGS, tid, 0, &r)) { - _LOG(log, only_in_tombstone, "cannot get registers: %s\n", strerror(errno)); + _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno)); return; } - _LOG(log, only_in_tombstone, " zr %08x at %08x v0 %08x v1 %08x\n", + _LOG(log, scopeFlags, " zr %08x at %08x v0 %08x v1 %08x\n", R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3])); - _LOG(log, only_in_tombstone, " a0 %08x a1 %08x a2 %08x a3 %08x\n", + _LOG(log, scopeFlags, " a0 %08x a1 %08x a2 %08x a3 %08x\n", R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7])); - _LOG(log, only_in_tombstone, " t0 %08x t1 %08x t2 %08x t3 %08x\n", + _LOG(log, scopeFlags, " t0 %08x t1 %08x t2 %08x t3 %08x\n", R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11])); - _LOG(log, only_in_tombstone, " t4 %08x t5 %08x t6 %08x t7 %08x\n", + _LOG(log, scopeFlags, " t4 %08x t5 %08x t6 %08x t7 %08x\n", R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15])); - _LOG(log, only_in_tombstone, " s0 %08x s1 %08x s2 %08x s3 %08x\n", + _LOG(log, scopeFlags, " s0 %08x s1 %08x s2 %08x s3 %08x\n", R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19])); - _LOG(log, only_in_tombstone, " s4 %08x s5 %08x s6 %08x s7 %08x\n", + _LOG(log, scopeFlags, " s4 %08x s5 %08x s6 %08x s7 %08x\n", R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23])); - _LOG(log, only_in_tombstone, " t8 %08x t9 %08x k0 %08x k1 %08x\n", + _LOG(log, scopeFlags, " t8 %08x t9 %08x k0 %08x k1 %08x\n", R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27])); - _LOG(log, only_in_tombstone, " gp %08x sp %08x s8 %08x ra %08x\n", + _LOG(log, scopeFlags, " gp %08x sp %08x s8 %08x ra %08x\n", R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31])); - _LOG(log, only_in_tombstone, " hi %08x lo %08x bva %08x epc %08x\n", + _LOG(log, scopeFlags, " hi %08x lo %08x bva %08x epc %08x\n", R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc)); } 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; } diff --git a/debuggerd/utility.c b/debuggerd/utility.c index aabaf74..9bf3c18 100644 --- a/debuggerd/utility.c +++ b/debuggerd/utility.c @@ -25,27 +25,63 @@ #include <cutils/logd.h> #include <sys/ptrace.h> #include <sys/wait.h> +#include <arpa/inet.h> +#include <assert.h> #include "utility.h" const int sleep_time_usec = 50000; /* 0.05 seconds */ const int max_total_sleep_usec = 10000000; /* 10 seconds */ -void _LOG(log_t* log, bool in_tombstone_only, const char *fmt, ...) { +static int write_to_am(int fd, const char* buf, int len) { + int to_write = len; + while (to_write > 0) { + int written = TEMP_FAILURE_RETRY( write(fd, buf + len - to_write, to_write) ); + if (written < 0) { + /* hard failure */ + LOG("AM write failure (%d / %s)\n", errno, strerror(errno)); + return -1; + } + to_write -= written; + } + return len; +} + +void _LOG(log_t* log, int scopeFlags, const char *fmt, ...) { char buf[512]; + bool want_tfd_write; + bool want_log_write; + bool want_amfd_write; + int len = 0; va_list ap; va_start(ap, fmt); - if (log && log->tfd >= 0) { - int len; + // where is the information going to go? + want_tfd_write = log && log->tfd >= 0; + want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet); + want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0; + + // if we're going to need the literal string, generate it once here + if (want_tfd_write || want_amfd_write) { vsnprintf(buf, sizeof(buf), fmt, ap); len = strlen(buf); + } + + if (want_tfd_write) { write(log->tfd, buf, len); } - if (!in_tombstone_only && (!log || !log->quiet)) { + if (want_log_write) { + // whatever goes to logcat also goes to the Activity Manager __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap); + if (want_amfd_write && len > 0) { + int written = write_to_am(log->amfd, buf, len); + if (written <= 0) { + // timeout or other failure on write; stop informing the activity manager + log->amfd = -1; + } + } } va_end(ap); } diff --git a/debuggerd/utility.h b/debuggerd/utility.h index 136f46d..1f006ed 100644 --- a/debuggerd/utility.h +++ b/debuggerd/utility.h @@ -24,26 +24,38 @@ typedef struct { /* tombstone file descriptor */ int tfd; - /* if true, does not log anything to the Android logcat */ + /* Activity Manager socket file descriptor */ + int amfd; + /* if true, does not log anything to the Android logcat or Activity Manager */ bool quiet; } log_t; -/* Log information onto the tombstone. */ -void _LOG(log_t* log, bool in_tombstone_only, const char *fmt, ...) +/* Log information onto the tombstone. scopeFlags is a bitmask of the flags defined + * here. */ +void _LOG(log_t* log, int scopeFlags, const char *fmt, ...) __attribute__ ((format(printf, 3, 4))); -#define LOG(fmt...) _LOG(NULL, 0, fmt) +/* The message pertains specifically to the faulting thread / process */ +#define SCOPE_AT_FAULT (1 << 0) +/* The message contains sensitive information such as RAM contents */ +#define SCOPE_SENSITIVE (1 << 1) + +#define IS_AT_FAULT(x) (((x) & SCOPE_AT_FAULT) != 0) +#define IS_SENSITIVE(x) (((x) & SCOPE_SENSITIVE) != 0) + +/* Further helpful macros */ +#define LOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt) /* Set to 1 for normal debug traces */ #if 0 -#define XLOG(fmt...) _LOG(NULL, 0, fmt) +#define XLOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt) #else #define XLOG(fmt...) do {} while(0) #endif /* Set to 1 for chatty debug traces. Includes all resolved dynamic symbols */ #if 0 -#define XLOG2(fmt...) _LOG(NULL, 0, fmt) +#define XLOG2(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt) #else #define XLOG2(fmt...) do {} while(0) #endif diff --git a/debuggerd/x86/machine.c b/debuggerd/x86/machine.c index 01da5fe..af79092 100644 --- a/debuggerd/x86/machine.c +++ b/debuggerd/x86/machine.c @@ -38,21 +38,21 @@ void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)), void dump_registers(const ptrace_context_t* context __attribute((unused)), log_t* log, pid_t tid, bool at_fault) { struct pt_regs_x86 r; - bool only_in_tombstone = !at_fault; + int scopeFlags = (at_fault ? SCOPE_AT_FAULT : 0); if(ptrace(PTRACE_GETREGS, tid, 0, &r)) { - _LOG(log, only_in_tombstone, "cannot get registers: %s\n", strerror(errno)); + _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno)); return; } //if there is no stack, no print just like arm if(!r.ebp) return; - _LOG(log, only_in_tombstone, " eax %08x ebx %08x ecx %08x edx %08x\n", + _LOG(log, scopeFlags, " eax %08x ebx %08x ecx %08x edx %08x\n", r.eax, r.ebx, r.ecx, r.edx); - _LOG(log, only_in_tombstone, " esi %08x edi %08x\n", + _LOG(log, scopeFlags, " esi %08x edi %08x\n", r.esi, r.edi); - _LOG(log, only_in_tombstone, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n", + _LOG(log, scopeFlags, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n", r.xcs, r.xds, r.xes, r.xfs, r.xss); - _LOG(log, only_in_tombstone, " eip %08x ebp %08x esp %08x flags %08x\n", + _LOG(log, scopeFlags, " eip %08x ebp %08x esp %08x flags %08x\n", r.eip, r.ebp, r.esp, r.eflags); } |