// If configured to do so, dump memory around *all* registers // for the crashing thread. void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { struct pt_regs regs; if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) { return; } if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) { static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp"; for (int reg = 0; reg < 14; reg++) { // this may not be a valid way to access, but it'll do for now uintptr_t addr = regs.uregs[reg]; // Don't bother if it looks like a small int or ~= null, or if // it's in the kernel area. if (addr < 4096 || addr >= 0xc0000000) { continue; } _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE); } } // explicitly allow upload of code dump logging _LOG(log, scope_flags, "\ncode around pc:\n"); dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc), scope_flags); if (regs.ARM_pc != regs.ARM_lr) { _LOG(log, scope_flags, "\ncode around lr:\n"); dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr), scope_flags); } }
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); // 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 (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); }
// If configured to do so, dump memory around *all* registers // for the crashing thread. void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { pt_regs_mips_t r; if (ptrace(PTRACE_GETREGS, tid, 0, &r)) { return; } if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) { static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra"; for (int reg = 0; reg < 32; reg++) { // skip uninteresting registers if (reg == 0 // $0 || reg == 26 // $k0 || reg == 27 // $k1 || reg == 31 // $ra (done below) ) continue; uintptr_t addr = R(r.regs[reg]); // Don't bother if it looks like a small int or ~= null, or if // it's in the kernel area. if (addr < 4096 || addr >= 0x80000000) { continue; } _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE); } } unsigned int pc = R(r.cp0_epc); unsigned int ra = R(r.regs[31]); _LOG(log, scope_flags, "\ncode around pc:\n"); dump_memory(log, tid, (uintptr_t)pc, scope_flags); if (pc != ra) { _LOG(log, scope_flags, "\ncode around ra:\n"); dump_memory(log, tid, (uintptr_t)ra, scope_flags); } }