Uploaded native crash dumps do not include memory contents

Also fixed the LOG() macro to actually write to the log again, tracking
the change in _LOG() argument semantics.

Bug 8322568

Change-Id: I79330c85c26d3ffb734315b6d0f2c0bb80bd234a
This commit is contained in:
Christopher Tate 2013-04-02 14:00:27 -07:00
parent e5f8a692e4
commit 7716aef138
7 changed files with 114 additions and 98 deletions

View file

@ -42,7 +42,7 @@
#endif #endif
#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 code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */
char ascii_buffer[32]; /* actual 16 + 1 == 17 */ char ascii_buffer[32]; /* actual 16 + 1 == 17 */
uintptr_t p, end; 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; p += 4;
} }
*asc_out = '\0'; *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; return;
} }
int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) { if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) {
static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp"; static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
@ -132,17 +134,18 @@ void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)),
continue; continue;
} }
_LOG(log, false, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]); _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
dump_memory(log, tid, addr, at_fault); dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE);
} }
} }
_LOG(log, !at_fault, "\ncode around pc:\n"); /* explicitly allow upload of code dump logging */
dump_memory(log, tid, (uintptr_t)regs.ARM_pc, at_fault); _LOG(log, scopeFlags, "\ncode around pc:\n");
dump_memory(log, tid, (uintptr_t)regs.ARM_pc, scopeFlags);
if (regs.ARM_pc != regs.ARM_lr) { if (regs.ARM_pc != regs.ARM_lr) {
_LOG(log, !at_fault, "\ncode around lr:\n"); _LOG(log, scopeFlags, "\ncode around lr:\n");
dump_memory(log, tid, (uintptr_t)regs.ARM_lr, at_fault); 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) log_t* log, pid_t tid, bool at_fault)
{ {
struct pt_regs r; 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)) { 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; 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); (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); (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); (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_ip, (uint32_t)r.ARM_sp, (uint32_t)r.ARM_lr,
(uint32_t)r.ARM_pc, (uint32_t)r.ARM_cpsr); (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; int i;
if(ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) { 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; return;
} }
for (i = 0; i < NUM_VFP_REGS; i += 2) { 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]); 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 #endif
} }

View file

@ -51,15 +51,15 @@ static void dump_process_header(log_t* log, pid_t pid) {
localtime_r(&t, &tm); localtime_r(&t, &tm);
char timestr[64]; char timestr[64];
strftime(timestr, sizeof(timestr), "%F %T", &tm); 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) { 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) { 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, 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) { 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; 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]; backtrace_frame_t backtrace[STACK_DEPTH];
ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH); ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH);
if (frames <= 0) { 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 { } else {
backtrace_symbol_t backtrace_symbols[STACK_DEPTH]; backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols); 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]; char line[MAX_BACKTRACE_LINE_LENGTH];
format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i], format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
line, MAX_BACKTRACE_LINE_LENGTH); 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); free_backtrace_symbols(backtrace_symbols, frames);
} }

View file

@ -36,7 +36,7 @@
#define R(x) ((unsigned int)(x)) #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 code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */
char ascii_buffer[32]; /* actual 16 + 1 == 17 */ char ascii_buffer[32]; /* actual 16 + 1 == 17 */
uintptr_t p, end; 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; p += 4;
} }
*asc_out = '\0'; *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; return;
} }
int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) { if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) {
static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra"; static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
@ -129,20 +130,20 @@ void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)),
continue; continue;
} }
_LOG(log, false, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]); _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
dump_memory(log, tid, addr, at_fault); dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE);
} }
} }
unsigned int pc = R(r.cp0_epc); unsigned int pc = R(r.cp0_epc);
unsigned int ra = R(r.regs[31]); unsigned int ra = R(r.regs[31]);
_LOG(log, !at_fault, "\ncode around pc:\n"); _LOG(log, scopeFlags, "\ncode around pc:\n");
dump_memory(log, tid, (uintptr_t)pc, at_fault); dump_memory(log, tid, (uintptr_t)pc, scopeFlags);
if (pc != ra) { if (pc != ra) {
_LOG(log, !at_fault, "\ncode around ra:\n"); _LOG(log, scopeFlags, "\ncode around ra:\n");
dump_memory(log, tid, (uintptr_t)ra, at_fault); 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) log_t* log, pid_t tid, bool at_fault)
{ {
pt_regs_mips_t r; 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)) { 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; 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])); 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])); 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])); 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])); 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])); 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])); 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])); 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])); 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)); R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
} }

View file

@ -163,7 +163,7 @@ static void dump_revision_info(log_t* log)
property_get("ro.revision", revision, "unknown"); 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) static void dump_build_info(log_t* log)
@ -172,7 +172,7 @@ static void dump_build_info(log_t* log)
property_get("ro.build.fingerprint", fingerprint, "unknown"); 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) static void dump_fault_addr(log_t* log, pid_t tid, int sig)
@ -180,15 +180,15 @@ static void dump_fault_addr(log_t* log, pid_t tid, int sig)
siginfo_t si; siginfo_t si;
memset(&si, 0, sizeof(si)); memset(&si, 0, sizeof(si));
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){ if(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
_LOG(log, false, "cannot get siginfo: %s\n", strerror(errno)); _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
} else if (signal_has_address(sig)) { } 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), sig, get_signame(sig),
si.si_code, get_sigcode(sig, si.si_code), si.si_code, get_sigcode(sig, si.si_code),
(uintptr_t) si.si_addr); (uintptr_t) si.si_addr);
} else { } 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)); sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
} }
} }
@ -221,19 +221,20 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, bool at_fault) {
fclose(fp); 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", threadname ? threadname : "UNKNOWN",
procname ? procname : "UNKNOWN"); procname ? procname : "UNKNOWN");
} else { } else {
_LOG(log, true, "pid: %d, tid: %d, name: %s\n", pid, tid, _LOG(log, 0, "pid: %d, tid: %d, name: %s\n",
threadname ? threadname : "UNKNOWN"); pid, tid, threadname ? threadname : "UNKNOWN");
} }
} }
static void dump_backtrace(const ptrace_context_t* context __attribute((unused)), static void dump_backtrace(const ptrace_context_t* context __attribute((unused)),
log_t* log, pid_t tid __attribute((unused)), bool at_fault, log_t* log, pid_t tid __attribute((unused)), bool at_fault,
const backtrace_frame_t* backtrace, size_t frames) { 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]; backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols); get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols);
@ -241,13 +242,13 @@ static void dump_backtrace(const ptrace_context_t* context __attribute((unused))
char line[MAX_BACKTRACE_LINE_LENGTH]; char line[MAX_BACKTRACE_LINE_LENGTH];
format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i], format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
line, MAX_BACKTRACE_LINE_LENGTH); line, MAX_BACKTRACE_LINE_LENGTH);
_LOG(log, !at_fault, " %s\n", line); _LOG(log, scopeFlags, " %s\n", line);
} }
free_backtrace_symbols(backtrace_symbols, frames); free_backtrace_symbols(backtrace_symbols, frames);
} }
static void dump_stack_segment(const ptrace_context_t* context, log_t* log, pid_t tid, 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++) { for (size_t i = 0; i < words; i++) {
uint32_t stack_content; uint32_t stack_content;
if (!try_get_word_ptrace(tid, *sp, &stack_content)) { if (!try_get_word_ptrace(tid, *sp, &stack_content)) {
@ -264,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); uint32_t offset = stack_content - (mi->start + symbol->start);
if (!i && label >= 0) { if (!i && label >= 0) {
if (offset) { 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); label, *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
} else { } 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); label, *sp, stack_content, mi ? mi->name : "", symbol_name);
} }
} else { } else {
if (offset) { 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); *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
} else { } 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); *sp, stack_content, mi ? mi->name : "", symbol_name);
} }
} }
free(demangled_name); free(demangled_name);
} else { } else {
if (!i && label >= 0) { 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 : ""); label, *sp, stack_content, mi ? mi->name : "");
} else { } else {
_LOG(log, only_in_tombstone, " %08x %08x %s\n", _LOG(log, scopeFlags, " %08x %08x %s\n",
*sp, stack_content, mi ? mi->name : ""); *sp, stack_content, mi ? mi->name : "");
} }
} }
@ -311,28 +312,28 @@ static void dump_stack(const ptrace_context_t* context, log_t* log, pid_t tid, b
return; 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. // 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); 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. // Dump a few words from all successive frames.
// Only log the first 3 frames, put the rest in the tombstone. // Only log the first 3 frames, put the rest in the tombstone.
for (size_t i = first; i <= last; i++) { for (size_t i = first; i <= last; i++) {
const backtrace_frame_t* frame = &backtrace[i]; const backtrace_frame_t* frame = &backtrace[i];
if (sp != frame->stack_top) { if (sp != frame->stack_top) {
_LOG(log, only_in_tombstone, " ........ ........\n"); _LOG(log, scopeFlags, " ........ ........\n");
sp = frame->stack_top; sp = frame->stack_top;
} }
if (i - first == 3) { if (i - first == 3) {
only_in_tombstone = true; scopeFlags &= (~SCOPE_AT_FAULT);
} }
if (i == last) { 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) { if (sp < frame->stack_top + frame->stack_size) {
_LOG(log, only_in_tombstone, " ........ ........\n"); _LOG(log, scopeFlags, " ........ ........\n");
} }
} else { } else {
size_t words = frame->stack_size / sizeof(uint32_t); size_t words = frame->stack_size / sizeof(uint32_t);
@ -341,7 +342,7 @@ static void dump_stack(const ptrace_context_t* context, log_t* log, pid_t tid, b
} else if (words > STACK_WORDS) { } else if (words > STACK_WORDS) {
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);
} }
} }
} }
@ -358,13 +359,13 @@ 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) {
if (m != NULL) { if (m != NULL) {
_LOG(log, false, " %08x-%08x %c%c%c %s\n", m->start, m->end, _LOG(log, SCOPE_SENSITIVE, " %08x-%08x %c%c%c %s\n", m->start, m->end,
m->is_readable ? 'r' : '-', m->is_readable ? 'r' : '-',
m->is_writable ? 'w' : '-', m->is_writable ? 'w' : '-',
m->is_executable ? 'x' : '-', m->is_executable ? 'x' : '-',
m->name); m->name);
} else { } else {
_LOG(log, false, " (no %s)\n", what); _LOG(log, SCOPE_SENSITIVE, " (no %s)\n", what);
} }
} }
@ -372,7 +373,7 @@ static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t
siginfo_t si; siginfo_t si;
memset(&si, 0, sizeof(si)); memset(&si, 0, sizeof(si));
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) { if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
_LOG(log, false, "cannot get siginfo for %d: %s\n", _LOG(log, SCOPE_SENSITIVE, "cannot get siginfo for %d: %s\n",
tid, strerror(errno)); tid, strerror(errno));
return; return;
} }
@ -386,7 +387,7 @@ static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t
return; return;
} }
_LOG(log, false, "\nmemory map around fault addr %08x:\n", (int)si.si_addr); _LOG(log, SCOPE_SENSITIVE, "\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 * Search for a match, or for a hole where the match would be. The list
@ -464,7 +465,7 @@ static bool dump_sibling_thread_report(const ptrace_context_t* context,
continue; continue;
} }
_LOG(log, true, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
dump_thread_info(log, pid, new_tid, false); dump_thread_info(log, pid, new_tid, false);
dump_thread(context, log, new_tid, false, total_sleep_time_usec); dump_thread(context, log, new_tid, false, total_sleep_time_usec);
@ -517,12 +518,12 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename,
/* non-blocking EOF; we're done */ /* non-blocking EOF; we're done */
break; break;
} else { } else {
_LOG(log, true, "Error while reading log: %s\n", _LOG(log, 0, "Error while reading log: %s\n",
strerror(errno)); strerror(errno));
break; break;
} }
} else if (actual == 0) { } 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)); strerror(errno));
break; break;
} }
@ -542,7 +543,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename,
} }
if (first) { if (first) {
_LOG(log, true, "--------- %slog %s\n", _LOG(log, 0, "--------- %slog %s\n",
tailOnly ? "tail end of " : "", filename); tailOnly ? "tail end of " : "", filename);
first = false; first = false;
} }
@ -584,7 +585,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename,
shortLogNext = (shortLogNext + 1) % kShortLogMaxLines; shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
shortLogCount++; shortLogCount++;
} else { } 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, timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
prioChar, tag, msg); prioChar, tag, msg);
} }
@ -604,7 +605,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename,
} }
for (i = 0; i < shortLogCount; i++) { for (i = 0; i < shortLogCount; i++) {
_LOG(log, true, "%s\n", shortLog[shortLogNext]); _LOG(log, 0, "%s\n", shortLog[shortLogNext]);
shortLogNext = (shortLogNext + 1) % kShortLogMaxLines; shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
} }
} }
@ -654,7 +655,7 @@ static void dump_abort_message(log_t* log, pid_t tid, uintptr_t address) {
} }
msg[sizeof(msg) - 1] = '\0'; msg[sizeof(msg) - 1] = '\0';
_LOG(log, false, "Abort message: '%s'\n", msg); _LOG(log, SCOPE_AT_FAULT, "Abort message: '%s'\n", msg);
} }
/* /*
@ -680,7 +681,7 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a
TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) ); TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
} }
_LOG(log, false, _LOG(log, SCOPE_AT_FAULT,
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
dump_build_info(log); dump_build_info(log);
dump_revision_info(log); dump_revision_info(log);

View file

@ -39,6 +39,7 @@ static int write_to_am(int fd, const char* buf, int len) {
int written = TEMP_FAILURE_RETRY( write(fd, buf + len - to_write, to_write) ); int written = TEMP_FAILURE_RETRY( write(fd, buf + len - to_write, to_write) );
if (written < 0) { if (written < 0) {
/* hard failure */ /* hard failure */
LOG("AM write failure (%d / %s)\n", errno, strerror(errno));
return -1; return -1;
} }
to_write -= written; to_write -= written;
@ -46,20 +47,20 @@ static int write_to_am(int fd, const char* buf, int len) {
return len; return len;
} }
void _LOG(log_t* log, bool in_tombstone_only, const char *fmt, ...) { void _LOG(log_t* log, int scopeFlags, const char *fmt, ...) {
char buf[512]; char buf[512];
bool want_tfd_write; bool want_tfd_write;
bool want_log_write; bool want_log_write;
bool want_amfd_write; bool want_amfd_write;
int len; int len = 0;
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
// where is the information going to go? // where is the information going to go?
want_tfd_write = log && log->tfd >= 0; // write to the tombstone fd? want_tfd_write = log && log->tfd >= 0;
want_log_write = !in_tombstone_only && (!log || !log->quiet); want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
want_amfd_write = log && log->amfd >= 0; // only used when want_log_write is true 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 we're going to need the literal string, generate it once here
if (want_tfd_write || want_amfd_write) { if (want_tfd_write || want_amfd_write) {
@ -78,7 +79,6 @@ void _LOG(log_t* log, bool in_tombstone_only, const char *fmt, ...) {
int written = write_to_am(log->amfd, buf, len); int written = write_to_am(log->amfd, buf, len);
if (written <= 0) { if (written <= 0) {
// timeout or other failure on write; stop informing the activity manager // timeout or other failure on write; stop informing the activity manager
LOG("AM write failure, giving up\n");
log->amfd = -1; log->amfd = -1;
} }
} }

View file

@ -30,22 +30,32 @@ typedef struct {
bool quiet; bool quiet;
} log_t; } log_t;
/* Log information onto the tombstone. */ /* Log information onto the tombstone. scopeFlags is a bitmask of the flags defined
void _LOG(log_t* log, bool in_tombstone_only, const char *fmt, ...) * here. */
void _LOG(log_t* log, int scopeFlags, const char *fmt, ...)
__attribute__ ((format(printf, 3, 4))); __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 */ /* Set to 1 for normal debug traces */
#if 0 #if 0
#define XLOG(fmt...) _LOG(NULL, 0, fmt) #define XLOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
#else #else
#define XLOG(fmt...) do {} while(0) #define XLOG(fmt...) do {} while(0)
#endif #endif
/* Set to 1 for chatty debug traces. Includes all resolved dynamic symbols */ /* Set to 1 for chatty debug traces. Includes all resolved dynamic symbols */
#if 0 #if 0
#define XLOG2(fmt...) _LOG(NULL, 0, fmt) #define XLOG2(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
#else #else
#define XLOG2(fmt...) do {} while(0) #define XLOG2(fmt...) do {} while(0)
#endif #endif

View file

@ -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)), void dump_registers(const ptrace_context_t* context __attribute((unused)),
log_t* log, pid_t tid, bool at_fault) { log_t* log, pid_t tid, bool at_fault) {
struct pt_regs_x86 r; 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)) { 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; return;
} }
//if there is no stack, no print just like arm //if there is no stack, no print just like arm
if(!r.ebp) if(!r.ebp)
return; 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); 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); 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); 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); r.eip, r.ebp, r.esp, r.eflags);
} }