am e3c2e761: am 46a97883: Merge "Changing how debuggerd filters log messages to different locations."
* commit 'e3c2e761ffb9de62dd277673a6c9a486362cef8b': Changing how debuggerd filters log messages to different locations.
This commit is contained in:
commit
96021e03d6
12 changed files with 263 additions and 261 deletions
|
|
@ -40,57 +40,55 @@
|
|||
|
||||
// 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) {
|
||||
void dump_memory_and_code(log_t* log, pid_t tid) {
|
||||
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";
|
||||
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];
|
||||
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);
|
||||
// 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, logtype::MEMORY, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
|
||||
dump_memory(log, tid, addr);
|
||||
}
|
||||
|
||||
// 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);
|
||||
_LOG(log, logtype::MEMORY, "\ncode around pc:\n");
|
||||
dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc));
|
||||
|
||||
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);
|
||||
_LOG(log, logtype::MEMORY, "\ncode around lr:\n");
|
||||
dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr));
|
||||
}
|
||||
}
|
||||
|
||||
void dump_registers(log_t* log, pid_t tid, int scope_flags) {
|
||||
void dump_registers(log_t* log, pid_t tid) {
|
||||
struct pt_regs r;
|
||||
if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
|
||||
_LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
|
||||
_LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
_LOG(log, scope_flags, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
|
||||
static_cast<uint32_t>(r.ARM_r0), static_cast<uint32_t>(r.ARM_r1),
|
||||
static_cast<uint32_t>(r.ARM_r2), static_cast<uint32_t>(r.ARM_r3));
|
||||
_LOG(log, scope_flags, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
|
||||
static_cast<uint32_t>(r.ARM_r4), static_cast<uint32_t>(r.ARM_r5),
|
||||
static_cast<uint32_t>(r.ARM_r6), static_cast<uint32_t>(r.ARM_r7));
|
||||
_LOG(log, scope_flags, " r8 %08x r9 %08x sl %08x fp %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " r8 %08x r9 %08x sl %08x fp %08x\n",
|
||||
static_cast<uint32_t>(r.ARM_r8), static_cast<uint32_t>(r.ARM_r9),
|
||||
static_cast<uint32_t>(r.ARM_r10), static_cast<uint32_t>(r.ARM_fp));
|
||||
_LOG(log, scope_flags, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
|
||||
static_cast<uint32_t>(r.ARM_ip), static_cast<uint32_t>(r.ARM_sp),
|
||||
static_cast<uint32_t>(r.ARM_lr), static_cast<uint32_t>(r.ARM_pc),
|
||||
static_cast<uint32_t>(r.ARM_cpsr));
|
||||
|
|
@ -100,14 +98,14 @@ void dump_registers(log_t* log, pid_t tid, int scope_flags) {
|
|||
int i;
|
||||
|
||||
if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
|
||||
_LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
|
||||
_LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_VFP_REGS; i += 2) {
|
||||
_LOG(log, scope_flags, " d%-2d %016llx d%-2d %016llx\n",
|
||||
_LOG(log, logtype::REGISTERS, " d%-2d %016llx d%-2d %016llx\n",
|
||||
i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
|
||||
}
|
||||
_LOG(log, scope_flags, " scr %08lx\n", vfp_regs.fpscr);
|
||||
_LOG(log, logtype::REGISTERS, " scr %08lx\n", vfp_regs.fpscr);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,68 +37,66 @@
|
|||
* 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) {
|
||||
void dump_memory_and_code(log_t* log, pid_t tid) {
|
||||
struct user_pt_regs regs;
|
||||
struct iovec io;
|
||||
io.iov_base = ®s;
|
||||
io.iov_len = sizeof(regs);
|
||||
|
||||
if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) {
|
||||
_LOG(log, scope_flags, "%s: ptrace failed to get registers: %s\n",
|
||||
LOG_ERROR("%s: ptrace failed to get registers: %s\n",
|
||||
__func__, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
|
||||
for (int reg = 0; reg < 31; reg++) {
|
||||
uintptr_t addr = regs.regs[reg];
|
||||
for (int reg = 0; reg < 31; reg++) {
|
||||
uintptr_t addr = regs.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 >= (1UL<<63)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near x%d:\n", reg);
|
||||
dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
|
||||
/*
|
||||
* Don't bother if it looks like a small int or ~= null, or if
|
||||
* it's in the kernel area.
|
||||
*/
|
||||
if (addr < 4096 || addr >= (1UL<<63)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_LOG(log, logtype::MEMORY, "\nmemory near x%d:\n", reg);
|
||||
dump_memory(log, tid, addr);
|
||||
}
|
||||
|
||||
_LOG(log, scope_flags, "\ncode around pc:\n");
|
||||
dump_memory(log, tid, (uintptr_t)regs.pc, scope_flags);
|
||||
_LOG(log, logtype::MEMORY, "\ncode around pc:\n");
|
||||
dump_memory(log, tid, (uintptr_t)regs.pc);
|
||||
|
||||
if (regs.pc != regs.sp) {
|
||||
_LOG(log, scope_flags, "\ncode around sp:\n");
|
||||
dump_memory(log, tid, (uintptr_t)regs.sp, scope_flags);
|
||||
_LOG(log, logtype::MEMORY, "\ncode around sp:\n");
|
||||
dump_memory(log, tid, (uintptr_t)regs.sp);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_registers(log_t* log, pid_t tid, int scope_flags)
|
||||
{
|
||||
void dump_registers(log_t* log, pid_t tid) {
|
||||
struct user_pt_regs r;
|
||||
struct iovec io;
|
||||
io.iov_base = &r;
|
||||
io.iov_len = sizeof(r);
|
||||
|
||||
if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
|
||||
_LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno));
|
||||
LOG_ERROR("ptrace error: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 28; i += 4) {
|
||||
_LOG(log, scope_flags, " x%-2d %016lx x%-2d %016lx x%-2d %016lx x%-2d %016lx\n",
|
||||
_LOG(log, logtype::REGISTERS,
|
||||
" x%-2d %016lx x%-2d %016lx x%-2d %016lx x%-2d %016lx\n",
|
||||
i, (uint64_t)r.regs[i],
|
||||
i+1, (uint64_t)r.regs[i+1],
|
||||
i+2, (uint64_t)r.regs[i+2],
|
||||
i+3, (uint64_t)r.regs[i+3]);
|
||||
}
|
||||
|
||||
_LOG(log, scope_flags, " x28 %016lx x29 %016lx x30 %016lx\n",
|
||||
_LOG(log, logtype::REGISTERS, " x28 %016lx x29 %016lx x30 %016lx\n",
|
||||
(uint64_t)r.regs[28], (uint64_t)r.regs[29], (uint64_t)r.regs[30]);
|
||||
|
||||
_LOG(log, scope_flags, " sp %016lx pc %016lx\n",
|
||||
_LOG(log, logtype::REGISTERS, " sp %016lx pc %016lx\n",
|
||||
(uint64_t)r.sp, (uint64_t)r.pc);
|
||||
|
||||
|
||||
|
|
@ -107,12 +105,12 @@ void dump_registers(log_t* log, pid_t tid, int scope_flags)
|
|||
io.iov_len = sizeof(f);
|
||||
|
||||
if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) {
|
||||
_LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno));
|
||||
LOG_ERROR("ptrace error: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; i += 4) {
|
||||
_LOG(log, scope_flags, " v%-2d %016lx v%-2d %016lx v%-2d %016lx v%-2d %016lx\n",
|
||||
_LOG(log, logtype::REGISTERS, " v%-2d %016lx v%-2d %016lx v%-2d %016lx v%-2d %016lx\n",
|
||||
i, (uint64_t)f.vregs[i],
|
||||
i+1, (uint64_t)f.vregs[i+1],
|
||||
i+2, (uint64_t)f.vregs[i+2],
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <UniquePtr.h>
|
||||
|
||||
#include "backtrace.h"
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
static void dump_process_header(log_t* log, pid_t pid) {
|
||||
|
|
@ -49,15 +50,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, SCOPE_AT_FAULT, "\n\n----- pid %d at %s -----\n", pid, timestr);
|
||||
_LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
|
||||
|
||||
if (procname) {
|
||||
_LOG(log, SCOPE_AT_FAULT, "Cmd line: %s\n", procname);
|
||||
_LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname);
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_process_footer(log_t* log, pid_t pid) {
|
||||
_LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
|
||||
_LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
|
||||
}
|
||||
|
||||
static void dump_thread(
|
||||
|
|
@ -79,10 +80,10 @@ static void dump_thread(
|
|||
}
|
||||
}
|
||||
|
||||
_LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
|
||||
_LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
|
||||
|
||||
if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
|
||||
_LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno));
|
||||
_LOG(log, logtype::BACKTRACE, "Could not attach to thread: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -90,11 +91,11 @@ static void dump_thread(
|
|||
|
||||
UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
|
||||
if (backtrace->Unwind(0)) {
|
||||
dump_backtrace_to_log(backtrace.get(), log, SCOPE_AT_FAULT, " ");
|
||||
dump_backtrace_to_log(backtrace.get(), log, " ");
|
||||
}
|
||||
|
||||
if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
|
||||
LOG("ptrace detach from %d failed: %s\n", tid, strerror(errno));
|
||||
LOG_ERROR("ptrace detach from %d failed: %s\n", tid, strerror(errno));
|
||||
*detach_failed = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -133,9 +134,8 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
|
|||
dump_process_footer(&log, pid);
|
||||
}
|
||||
|
||||
void dump_backtrace_to_log(Backtrace* backtrace, log_t* log,
|
||||
int scope_flags, const char* prefix) {
|
||||
void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix) {
|
||||
for (size_t i = 0; i < backtrace->NumFrames(); i++) {
|
||||
_LOG(log, scope_flags, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
|
||||
_LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
|
|||
int* total_sleep_time_usec);
|
||||
|
||||
/* Dumps the backtrace in the backtrace data structure to the log. */
|
||||
void dump_backtrace_to_log(Backtrace* backtrace, log_t* log,
|
||||
int scope_flags, const char* prefix);
|
||||
void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix);
|
||||
|
||||
#endif // _DEBUGGERD_BACKTRACE_H
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include <log/logd.h>
|
||||
#include <log/logger.h>
|
||||
|
||||
#include <cutils/sockets.h>
|
||||
|
|
@ -62,7 +61,7 @@ static void wait_for_user_action(pid_t pid) {
|
|||
char exe[PATH_MAX];
|
||||
int count;
|
||||
if ((count = readlink(path, exe, sizeof(exe) - 1)) == -1) {
|
||||
LOG("readlink('%s') failed: %s", path, strerror(errno));
|
||||
LOG_ERROR("readlink('%s') failed: %s", path, strerror(errno));
|
||||
strlcpy(exe, "unknown", sizeof(exe));
|
||||
} else {
|
||||
exe[count] = '\0';
|
||||
|
|
@ -79,7 +78,7 @@ static void wait_for_user_action(pid_t pid) {
|
|||
}
|
||||
|
||||
// Explain how to attach the debugger.
|
||||
LOG( "********************************************************\n"
|
||||
LOG_ERROR( "********************************************************\n"
|
||||
"* Process %d has been suspended while crashing.\n"
|
||||
"* To attach gdbserver for a gdb connection on port 5039\n"
|
||||
"* and start gdbclient:\n"
|
||||
|
|
@ -104,7 +103,7 @@ static void wait_for_user_action(pid_t pid) {
|
|||
uninit_getevent();
|
||||
}
|
||||
|
||||
LOG("debuggerd resuming process %d", pid);
|
||||
LOG_ERROR("debuggerd resuming process %d", pid);
|
||||
}
|
||||
|
||||
static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* out_gid) {
|
||||
|
|
@ -140,7 +139,7 @@ static int read_request(int fd, debugger_request_t* out_request) {
|
|||
socklen_t len = sizeof(cr);
|
||||
int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
|
||||
if (status != 0) {
|
||||
LOG("cannot get credentials\n");
|
||||
LOG_ERROR("cannot get credentials\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +152,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 (from pid=%d uid=%d)\n", cr.pid, cr.uid);
|
||||
LOG_ERROR("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -161,14 +160,14 @@ 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 (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
|
||||
LOG_ERROR("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=0x%" PRIPTR "\n",
|
||||
status, msg.abort_msg_address);
|
||||
} else {
|
||||
LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
|
||||
LOG_ERROR("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +185,7 @@ static int read_request(int fd, debugger_request_t* out_request) {
|
|||
struct stat s;
|
||||
snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
|
||||
if (stat(buf, &s)) {
|
||||
LOG("tid %d does not exist in pid %d. ignoring debug request\n",
|
||||
LOG_ERROR("tid %d does not exist in pid %d. ignoring debug request\n",
|
||||
out_request->tid, out_request->pid);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -197,7 +196,7 @@ static int read_request(int fd, debugger_request_t* out_request) {
|
|||
status = get_process_info(out_request->tid, &out_request->pid,
|
||||
&out_request->uid, &out_request->gid);
|
||||
if (status < 0) {
|
||||
LOG("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
|
||||
LOG_ERROR("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -238,12 +237,12 @@ static void handle_request(int fd) {
|
|||
// See details in bionic/libc/linker/debugger.c, in function
|
||||
// debugger_signal_handler().
|
||||
if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
|
||||
LOG("ptrace attach failed: %s\n", strerror(errno));
|
||||
LOG_ERROR("ptrace attach failed: %s\n", strerror(errno));
|
||||
} else {
|
||||
bool detach_failed = false;
|
||||
bool attach_gdb = should_attach_gdb(&request);
|
||||
if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
|
||||
LOG("failed responding to client: %s\n", strerror(errno));
|
||||
LOG_ERROR("failed responding to client: %s\n", strerror(errno));
|
||||
} else {
|
||||
char* tombstone_path = NULL;
|
||||
|
||||
|
|
@ -275,7 +274,7 @@ static void handle_request(int fd) {
|
|||
XLOG("stopped -- continuing\n");
|
||||
status = ptrace(PTRACE_CONT, request.tid, 0, 0);
|
||||
if (status) {
|
||||
LOG("ptrace continue failed: %s\n", strerror(errno));
|
||||
LOG_ERROR("ptrace continue failed: %s\n", strerror(errno));
|
||||
}
|
||||
continue; // loop again
|
||||
}
|
||||
|
|
@ -307,7 +306,7 @@ static void handle_request(int fd) {
|
|||
|
||||
default:
|
||||
XLOG("stopped -- unexpected signal\n");
|
||||
LOG("process stopped due to unexpected signal %d\n", signal);
|
||||
LOG_ERROR("process stopped due to unexpected signal %d\n", signal);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
@ -330,7 +329,7 @@ static void handle_request(int fd) {
|
|||
|
||||
// detach so we can attach gdbserver
|
||||
if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
|
||||
LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
|
||||
LOG_ERROR("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
|
||||
detach_failed = true;
|
||||
}
|
||||
|
||||
|
|
@ -342,7 +341,7 @@ static void handle_request(int fd) {
|
|||
} else {
|
||||
// just detach
|
||||
if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
|
||||
LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
|
||||
LOG_ERROR("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
|
||||
detach_failed = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -354,7 +353,7 @@ static void handle_request(int fd) {
|
|||
// actual parent won't receive a death notification via wait(2). At this point
|
||||
// there's not much we can do about that.
|
||||
if (detach_failed) {
|
||||
LOG("debuggerd committing suicide to free the zombie!\n");
|
||||
LOG_ERROR("debuggerd committing suicide to free the zombie!\n");
|
||||
kill(getpid(), SIGKILL);
|
||||
}
|
||||
}
|
||||
|
|
@ -400,7 +399,7 @@ static int do_server() {
|
|||
return 1;
|
||||
fcntl(s, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
LOG("debuggerd: " __DATE__ " " __TIME__ "\n");
|
||||
LOG_ERROR("debuggerd: " __DATE__ " " __TIME__ "\n");
|
||||
|
||||
for (;;) {
|
||||
sockaddr addr;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "utility.h"
|
||||
|
||||
void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags);
|
||||
void dump_registers(log_t* log, pid_t tid, int scope_flags);
|
||||
void dump_memory_and_code(log_t* log, pid_t tid);
|
||||
void dump_registers(log_t* log, pid_t tid);
|
||||
|
||||
#endif // _DEBUGGERD_MACHINE_H
|
||||
|
|
|
|||
|
|
@ -27,9 +27,6 @@
|
|||
#include "../utility.h"
|
||||
#include "../machine.h"
|
||||
|
||||
// enable to dump memory pointed to by every register
|
||||
#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
|
||||
|
||||
#define R(x) (static_cast<unsigned int>(x))
|
||||
|
||||
// The MIPS uapi ptrace.h has the wrong definition for pt_regs. PTRACE_GETREGS
|
||||
|
|
@ -46,72 +43,70 @@ struct pt_regs_mips_t {
|
|||
|
||||
// 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) {
|
||||
void dump_memory_and_code(log_t* log, pid_t tid) {
|
||||
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";
|
||||
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;
|
||||
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]);
|
||||
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);
|
||||
// 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, logtype::MEMORY, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
|
||||
dump_memory(log, tid, addr);
|
||||
}
|
||||
|
||||
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);
|
||||
_LOG(log, logtype::MEMORY, "\ncode around pc:\n");
|
||||
dump_memory(log, tid, (uintptr_t)pc);
|
||||
|
||||
if (pc != ra) {
|
||||
_LOG(log, scope_flags, "\ncode around ra:\n");
|
||||
dump_memory(log, tid, (uintptr_t)ra, scope_flags);
|
||||
_LOG(log, logtype::MEMORY, "\ncode around ra:\n");
|
||||
dump_memory(log, tid, (uintptr_t)ra);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_registers(log_t* log, pid_t tid, int scope_flags) {
|
||||
void dump_registers(log_t* log, pid_t tid) {
|
||||
pt_regs_mips_t r;
|
||||
if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
|
||||
_LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
|
||||
LOG_ERROR("cannot get registers: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
_LOG(log, scope_flags, " zr %08x at %08x v0 %08x v1 %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " 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, scope_flags, " a0 %08x a1 %08x a2 %08x a3 %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " 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, scope_flags, " t0 %08x t1 %08x t2 %08x t3 %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " 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, scope_flags, " t4 %08x t5 %08x t6 %08x t7 %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " 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, scope_flags, " s0 %08x s1 %08x s2 %08x s3 %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " 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, scope_flags, " s4 %08x s5 %08x s6 %08x s7 %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " 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, scope_flags, " t8 %08x t9 %08x k0 %08x k1 %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " 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, scope_flags, " gp %08x sp %08x s8 %08x ra %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " 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, scope_flags, " hi %08x lo %08x bva %08x epc %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " hi %08x lo %08x bva %08x epc %08x\n",
|
||||
R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "DEBUG"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -179,16 +181,16 @@ static void dump_header_info(log_t* log) {
|
|||
property_get("ro.build.fingerprint", fingerprint, "unknown");
|
||||
property_get("ro.revision", revision, "unknown");
|
||||
|
||||
_LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
|
||||
_LOG(log, SCOPE_AT_FAULT, "Revision: '%s'\n", revision);
|
||||
_LOG(log, SCOPE_AT_FAULT, "ABI: '%s'\n", ABI_STRING);
|
||||
_LOG(log, logtype::HEADER, "Build fingerprint: '%s'\n", fingerprint);
|
||||
_LOG(log, logtype::HEADER, "Revision: '%s'\n", revision);
|
||||
_LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
|
||||
}
|
||||
|
||||
static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) {
|
||||
siginfo_t si;
|
||||
memset(&si, 0, sizeof(si));
|
||||
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
|
||||
_LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
|
||||
_LOG(log, logtype::HEADER, "cannot get siginfo: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -202,11 +204,11 @@ static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) {
|
|||
snprintf(addr_desc, sizeof(addr_desc), "--------");
|
||||
}
|
||||
|
||||
_LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %s\n",
|
||||
_LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n",
|
||||
signal, get_signame(signal), si.si_code, get_sigcode(signal, si.si_code), addr_desc);
|
||||
}
|
||||
|
||||
static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) {
|
||||
static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
|
||||
char path[64];
|
||||
char threadnamebuf[1024];
|
||||
char* threadname = NULL;
|
||||
|
|
@ -224,25 +226,21 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags)
|
|||
}
|
||||
}
|
||||
|
||||
if (IS_AT_FAULT(scope_flags)) {
|
||||
char procnamebuf[1024];
|
||||
char* procname = NULL;
|
||||
char procnamebuf[1024];
|
||||
char* procname = NULL;
|
||||
|
||||
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
|
||||
if ((fp = fopen(path, "r"))) {
|
||||
procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
_LOG(log, SCOPE_AT_FAULT, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
|
||||
threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
|
||||
} else {
|
||||
_LOG(log, 0, "pid: %d, tid: %d, name: %s\n", pid, tid, threadname ? threadname : "UNKNOWN");
|
||||
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
|
||||
if ((fp = fopen(path, "r"))) {
|
||||
procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
_LOG(log, logtype::THREAD, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
|
||||
threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
|
||||
}
|
||||
|
||||
static void dump_stack_segment(
|
||||
Backtrace* backtrace, log_t* log, int scope_flags, uintptr_t* sp, size_t words, int label) {
|
||||
Backtrace* backtrace, log_t* log, uintptr_t* sp, size_t words, int label) {
|
||||
for (size_t i = 0; i < words; i++) {
|
||||
word_t stack_content;
|
||||
if (!backtrace->ReadWord(*sp, &stack_content)) {
|
||||
|
|
@ -261,27 +259,27 @@ static void dump_stack_segment(
|
|||
if (!func_name.empty()) {
|
||||
if (!i && label >= 0) {
|
||||
if (offset) {
|
||||
_LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
|
||||
_LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
|
||||
label, *sp, stack_content, map_name, func_name.c_str(), offset);
|
||||
} else {
|
||||
_LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s)\n",
|
||||
_LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s (%s)\n",
|
||||
label, *sp, stack_content, map_name, func_name.c_str());
|
||||
}
|
||||
} else {
|
||||
if (offset) {
|
||||
_LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
|
||||
_LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
|
||||
*sp, stack_content, map_name, func_name.c_str(), offset);
|
||||
} else {
|
||||
_LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s)\n",
|
||||
_LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s (%s)\n",
|
||||
*sp, stack_content, map_name, func_name.c_str());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!i && label >= 0) {
|
||||
_LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s\n",
|
||||
_LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s\n",
|
||||
label, *sp, stack_content, map_name);
|
||||
} else {
|
||||
_LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s\n",
|
||||
_LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s\n",
|
||||
*sp, stack_content, map_name);
|
||||
}
|
||||
}
|
||||
|
|
@ -290,7 +288,7 @@ static void dump_stack_segment(
|
|||
}
|
||||
}
|
||||
|
||||
static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
|
||||
static void dump_stack(Backtrace* backtrace, log_t* log) {
|
||||
size_t first = 0, last;
|
||||
for (size_t i = 0; i < backtrace->NumFrames(); i++) {
|
||||
const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
|
||||
|
|
@ -306,27 +304,22 @@ static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
|
|||
}
|
||||
first--;
|
||||
|
||||
scope_flags |= SCOPE_SENSITIVE;
|
||||
|
||||
// Dump a few words before the first frame.
|
||||
word_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(word_t);
|
||||
dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1);
|
||||
dump_stack_segment(backtrace, log, &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_data_t* frame = backtrace->GetFrame(i);
|
||||
if (sp != frame->sp) {
|
||||
_LOG(log, scope_flags, " ........ ........\n");
|
||||
_LOG(log, logtype::STACK, " ........ ........\n");
|
||||
sp = frame->sp;
|
||||
}
|
||||
if (i - first == 3) {
|
||||
scope_flags &= (~SCOPE_AT_FAULT);
|
||||
}
|
||||
if (i == last) {
|
||||
dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, i);
|
||||
dump_stack_segment(backtrace, log, &sp, STACK_WORDS, i);
|
||||
if (sp < frame->sp + frame->stack_size) {
|
||||
_LOG(log, scope_flags, " ........ ........\n");
|
||||
_LOG(log, logtype::STACK, " ........ ........\n");
|
||||
}
|
||||
} else {
|
||||
size_t words = frame->stack_size / sizeof(word_t);
|
||||
|
|
@ -335,37 +328,36 @@ static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
|
|||
} else if (words > STACK_WORDS) {
|
||||
words = STACK_WORDS;
|
||||
}
|
||||
dump_stack_segment(backtrace, log, scope_flags, &sp, words, i);
|
||||
dump_stack_segment(backtrace, log, &sp, words, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
|
||||
static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) {
|
||||
if (backtrace->NumFrames()) {
|
||||
_LOG(log, scope_flags, "\nbacktrace:\n");
|
||||
dump_backtrace_to_log(backtrace, log, scope_flags, " ");
|
||||
_LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
|
||||
dump_backtrace_to_log(backtrace, log, " ");
|
||||
|
||||
_LOG(log, scope_flags, "\nstack:\n");
|
||||
dump_stack(backtrace, log, scope_flags);
|
||||
_LOG(log, logtype::STACK, "\nstack:\n");
|
||||
dump_stack(backtrace, log);
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_map(log_t* log, const backtrace_map_t* map, const char* what, int scope_flags) {
|
||||
static void dump_map(log_t* log, const backtrace_map_t* map, const char* what) {
|
||||
if (map != NULL) {
|
||||
_LOG(log, scope_flags, " %" PRIPTR "-%" PRIPTR " %c%c%c %s\n", map->start, map->end,
|
||||
_LOG(log, logtype::MAPS, " %" PRIPTR "-%" PRIPTR " %c%c%c %s\n", map->start, map->end,
|
||||
(map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-',
|
||||
(map->flags & PROT_EXEC) ? 'x' : '-', map->name.c_str());
|
||||
} else {
|
||||
_LOG(log, scope_flags, " (no %s)\n", what);
|
||||
_LOG(log, logtype::MAPS, " (no %s)\n", what);
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid, int scope_flags) {
|
||||
scope_flags |= SCOPE_SENSITIVE;
|
||||
static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid) {
|
||||
siginfo_t si;
|
||||
memset(&si, 0, sizeof(si));
|
||||
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
|
||||
_LOG(log, scope_flags, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
|
||||
_LOG(log, logtype::MAPS, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (!signal_has_si_addr(si.si_signo)) {
|
||||
|
|
@ -378,7 +370,7 @@ static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid, int scope
|
|||
return;
|
||||
}
|
||||
|
||||
_LOG(log, scope_flags, "\nmemory map around fault addr %" PRIPTR ":\n",
|
||||
_LOG(log, logtype::MAPS, "\nmemory map around fault addr %" PRIPTR ":\n",
|
||||
reinterpret_cast<uintptr_t>(si.si_addr));
|
||||
|
||||
// Search for a match, or for a hole where the match would be. The list
|
||||
|
|
@ -400,27 +392,28 @@ static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid, int scope
|
|||
}
|
||||
|
||||
// Show the map address in ascending order (like /proc/pid/maps).
|
||||
dump_map(log, prev_map, "map below", scope_flags);
|
||||
dump_map(log, cur_map, "map for address", scope_flags);
|
||||
dump_map(log, next_map, "map above", scope_flags);
|
||||
dump_map(log, prev_map, "map below");
|
||||
dump_map(log, cur_map, "map for address");
|
||||
dump_map(log, next_map, "map above");
|
||||
}
|
||||
|
||||
static void dump_thread(
|
||||
Backtrace* backtrace, log_t* log, int scope_flags, int* total_sleep_time_usec) {
|
||||
Backtrace* backtrace, log_t* log, int* total_sleep_time_usec) {
|
||||
|
||||
wait_for_stop(backtrace->Tid(), total_sleep_time_usec);
|
||||
|
||||
dump_registers(log, backtrace->Tid(), scope_flags);
|
||||
dump_backtrace_and_stack(backtrace, log, scope_flags);
|
||||
if (IS_AT_FAULT(scope_flags)) {
|
||||
dump_memory_and_code(log, backtrace->Tid(), scope_flags);
|
||||
dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid(), scope_flags);
|
||||
}
|
||||
dump_registers(log, backtrace->Tid());
|
||||
dump_backtrace_and_stack(backtrace, log);
|
||||
|
||||
dump_memory_and_code(log, backtrace->Tid());
|
||||
dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid());
|
||||
}
|
||||
|
||||
// Return true if some thread is not detached cleanly
|
||||
static bool dump_sibling_thread_report(
|
||||
log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec, BacktraceMap* map) {
|
||||
char task_path[64];
|
||||
|
||||
snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
|
||||
|
||||
DIR* d = opendir(task_path);
|
||||
|
|
@ -447,19 +440,24 @@ static bool dump_sibling_thread_report(
|
|||
|
||||
// Skip this thread if cannot ptrace it
|
||||
if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) {
|
||||
LOG_ERROR("ptrace attach to %d failed: %s\n", new_tid, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
_LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
|
||||
dump_thread_info(log, pid, new_tid, 0);
|
||||
_LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
|
||||
dump_thread_info(log, pid, new_tid);
|
||||
|
||||
log->current_tid = new_tid;
|
||||
|
||||
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
|
||||
if (backtrace->Unwind(0)) {
|
||||
dump_thread(backtrace.get(), log, 0, total_sleep_time_usec);
|
||||
dump_thread(backtrace.get(), log, total_sleep_time_usec);
|
||||
}
|
||||
|
||||
log->current_tid = log->crashed_tid;
|
||||
|
||||
if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
|
||||
LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
|
||||
LOG_ERROR("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
|
||||
detach_failed = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -500,12 +498,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, 0, "Error while reading log: %s\n",
|
||||
LOG_ERROR("Error while reading log: %s\n",
|
||||
strerror(-actual));
|
||||
break;
|
||||
}
|
||||
} else if (actual == 0) {
|
||||
_LOG(log, 0, "Got zero bytes while reading log: %s\n",
|
||||
LOG_ERROR("Got zero bytes while reading log: %s\n",
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
|
@ -522,7 +520,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename,
|
|||
}
|
||||
|
||||
if (first) {
|
||||
_LOG(log, 0, "--------- %slog %s\n",
|
||||
_LOG(log, logtype::HEADER, "--------- %slog %s\n",
|
||||
tail ? "tail end of " : "", filename);
|
||||
first = false;
|
||||
}
|
||||
|
|
@ -552,7 +550,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename,
|
|||
AndroidLogEntry e;
|
||||
char buf[512];
|
||||
android_log_processBinaryLogBuffer(entry, &e, g_eventTagMap, buf, sizeof(buf));
|
||||
_LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
|
||||
_LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
|
||||
timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
|
||||
'I', e.tag, e.message);
|
||||
continue;
|
||||
|
|
@ -579,7 +577,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename,
|
|||
++nl;
|
||||
}
|
||||
|
||||
_LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
|
||||
_LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
|
||||
timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
|
||||
prioChar, tag, msg);
|
||||
|
||||
|
|
@ -619,7 +617,7 @@ static void dump_abort_message(Backtrace* backtrace, log_t* log, uintptr_t addre
|
|||
}
|
||||
msg[sizeof(msg) - 1] = '\0';
|
||||
|
||||
_LOG(log, SCOPE_AT_FAULT, "Abort message: '%s'\n", msg);
|
||||
_LOG(log, logtype::HEADER, "Abort message: '%s'\n", msg);
|
||||
}
|
||||
|
||||
// Dumps all information about the specified pid to the tombstone.
|
||||
|
|
@ -641,10 +639,11 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code
|
|||
TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
|
||||
}
|
||||
|
||||
_LOG(log, SCOPE_AT_FAULT,
|
||||
_LOG(log, logtype::HEADER,
|
||||
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
|
||||
dump_header_info(log);
|
||||
dump_thread_info(log, pid, tid, SCOPE_AT_FAULT);
|
||||
dump_thread_info(log, pid, tid);
|
||||
|
||||
if (signal) {
|
||||
dump_signal_info(log, tid, signal, si_code);
|
||||
}
|
||||
|
|
@ -653,7 +652,7 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code
|
|||
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
|
||||
if (backtrace->Unwind(0)) {
|
||||
dump_abort_message(backtrace.get(), log, abort_msg_address);
|
||||
dump_thread(backtrace.get(), log, SCOPE_AT_FAULT, total_sleep_time_usec);
|
||||
dump_thread(backtrace.get(), log, total_sleep_time_usec);
|
||||
}
|
||||
|
||||
if (want_logs) {
|
||||
|
|
@ -715,7 +714,7 @@ static char* find_and_open_tombstone(int* fd) {
|
|||
}
|
||||
|
||||
if (oldest < 0) {
|
||||
LOG("Failed to find a valid tombstone, default to using tombstone 0.\n");
|
||||
LOG_ERROR("Failed to find a valid tombstone, default to using tombstone 0.\n");
|
||||
oldest = 0;
|
||||
}
|
||||
|
||||
|
|
@ -723,7 +722,7 @@ static char* find_and_open_tombstone(int* fd) {
|
|||
snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
|
||||
*fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||
if (*fd < 0) {
|
||||
LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno));
|
||||
LOG_ERROR("failed to open tombstone file '%s': %s\n", path, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
fchown(*fd, AID_SYSTEM, AID_SYSTEM);
|
||||
|
|
@ -763,12 +762,17 @@ static int activity_manager_connect() {
|
|||
char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
|
||||
uintptr_t abort_msg_address, bool dump_sibling_threads, bool quiet,
|
||||
bool* detach_failed, int* total_sleep_time_usec) {
|
||||
|
||||
log_t log;
|
||||
log.current_tid = tid;
|
||||
log.crashed_tid = tid;
|
||||
|
||||
if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
|
||||
LOG("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
|
||||
LOG_ERROR("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
|
||||
}
|
||||
|
||||
if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) {
|
||||
LOG("failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
|
||||
LOG_ERROR("failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
|
||||
}
|
||||
|
||||
int fd = -1;
|
||||
|
|
@ -776,16 +780,15 @@ char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
|
|||
if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == 0) {
|
||||
path = find_and_open_tombstone(&fd);
|
||||
} else {
|
||||
LOG("Failed to restore security context, not writing tombstone.\n");
|
||||
LOG_ERROR("Failed to restore security context, not writing tombstone.\n");
|
||||
}
|
||||
|
||||
if (fd < 0 && quiet) {
|
||||
LOG("Skipping tombstone write, nothing to do.\n");
|
||||
LOG_ERROR("Skipping tombstone write, nothing to do.\n");
|
||||
*detach_failed = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_t log;
|
||||
log.tfd = fd;
|
||||
// Preserve amfd since it can be modified through the calls below without
|
||||
// being closed.
|
||||
|
|
@ -795,6 +798,8 @@ char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
|
|||
*detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address,
|
||||
dump_sibling_threads, total_sleep_time_usec);
|
||||
|
||||
ALOGI("\nTombstone written to: %s\n", path);
|
||||
|
||||
// Either of these file descriptors can be -1, any error is ignored.
|
||||
close(amfd);
|
||||
close(fd);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "DEBUG"
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
|
@ -25,7 +27,6 @@
|
|||
|
||||
#include <backtrace/Backtrace.h>
|
||||
#include <log/log.h>
|
||||
#include <log/logd.h>
|
||||
|
||||
const int sleep_time_usec = 50000; // 0.05 seconds
|
||||
const int max_total_sleep_usec = 10000000; // 10 seconds
|
||||
|
|
@ -36,7 +37,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));
|
||||
if (written < 0) {
|
||||
// hard failure
|
||||
LOG("AM write failure (%d / %s)\n", errno, strerror(errno));
|
||||
LOG_ERROR("AM write failure (%d / %s)\n", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
to_write -= written;
|
||||
|
|
@ -44,10 +45,22 @@ static int write_to_am(int fd, const char* buf, int len) {
|
|||
return len;
|
||||
}
|
||||
|
||||
void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) {
|
||||
bool want_tfd_write = log && log->tfd >= 0;
|
||||
bool want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
|
||||
bool want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0;
|
||||
// Whitelist output desired in the logcat output.
|
||||
bool is_allowed_in_logcat(enum logtype ltype) {
|
||||
if ((ltype == ERROR)
|
||||
|| (ltype == HEADER)
|
||||
|| (ltype == REGISTERS)
|
||||
|| (ltype == BACKTRACE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
|
||||
bool write_to_tombstone = log && log->tfd;
|
||||
bool write_to_logcat = (!log || !log->quiet) && is_allowed_in_logcat(ltype)
|
||||
&& (log && log->crashed_tid == log->current_tid);
|
||||
bool write_to_activitymanager = log && log->amfd >= 0 && is_allowed_in_logcat(ltype);
|
||||
|
||||
char buf[512];
|
||||
va_list ap;
|
||||
|
|
@ -60,13 +73,13 @@ void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (want_tfd_write) {
|
||||
if (write_to_tombstone) {
|
||||
TEMP_FAILURE_RETRY(write(log->tfd, buf, len));
|
||||
}
|
||||
|
||||
if (want_log_write) {
|
||||
__android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, "DEBUG", buf);
|
||||
if (want_amfd_write) {
|
||||
if (write_to_logcat) {
|
||||
__android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, LOG_TAG, buf);
|
||||
if (write_to_activitymanager) {
|
||||
int written = write_to_am(log->amfd, buf, len);
|
||||
if (written <= 0) {
|
||||
// timeout or other failure on write; stop informing the activity manager
|
||||
|
|
@ -83,20 +96,20 @@ int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
|
|||
if (n < 0) {
|
||||
if (errno == EAGAIN)
|
||||
continue;
|
||||
LOG("waitpid failed: %s\n", strerror(errno));
|
||||
LOG_ERROR("waitpid failed: %s\n", strerror(errno));
|
||||
return -1;
|
||||
} else if (n > 0) {
|
||||
XLOG("waitpid: n=%d status=%08x\n", n, status);
|
||||
if (WIFSTOPPED(status)) {
|
||||
return WSTOPSIG(status);
|
||||
} else {
|
||||
LOG("unexpected waitpid response: n=%d, status=%08x\n", n, status);
|
||||
LOG_ERROR("unexpected waitpid response: n=%d, status=%08x\n", n, status);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (*total_sleep_time_usec > max_total_sleep_usec) {
|
||||
LOG("timed out waiting for tid=%d to die\n", tid);
|
||||
LOG_ERROR("timed out waiting for tid=%d to die\n", tid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +124,7 @@ void wait_for_stop(pid_t tid, int* total_sleep_time_usec) {
|
|||
siginfo_t si;
|
||||
while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) < 0 && errno == ESRCH) {
|
||||
if (*total_sleep_time_usec > max_total_sleep_usec) {
|
||||
LOG("timed out waiting for tid=%d to stop\n", tid);
|
||||
LOG_ERROR("timed out waiting for tid=%d to stop\n", tid);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +139,7 @@ void wait_for_stop(pid_t tid, int* total_sleep_time_usec) {
|
|||
#define DUMP_MEMORY_AS_ASCII 0
|
||||
#endif
|
||||
|
||||
void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
|
||||
void dump_memory(log_t* log, pid_t tid, uintptr_t addr) {
|
||||
char code_buffer[64];
|
||||
char ascii_buffer[32];
|
||||
uintptr_t p, end;
|
||||
|
|
@ -190,6 +203,6 @@ void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
|
|||
p += sizeof(long);
|
||||
}
|
||||
*asc_out = '\0';
|
||||
_LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer);
|
||||
_LOG(log, logtype::MEMORY, " %s %s\n", code_buffer, ascii_buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,41 +28,36 @@ typedef struct {
|
|||
int amfd;
|
||||
/* if true, does not log anything to the Android logcat or Activity Manager */
|
||||
bool quiet;
|
||||
// The tid of the thread that crashed.
|
||||
pid_t crashed_tid;
|
||||
// The tid of the thread we are currently working with.
|
||||
pid_t current_tid;
|
||||
} log_t;
|
||||
|
||||
/* Log information onto the tombstone. scopeFlags is a bitmask of the flags defined
|
||||
* here. */
|
||||
void _LOG(log_t* log, int scopeFlags, const char *fmt, ...)
|
||||
// List of types of logs to simplify the logging decision in _LOG
|
||||
enum logtype {
|
||||
ERROR,
|
||||
HEADER,
|
||||
THREAD,
|
||||
REGISTERS,
|
||||
BACKTRACE,
|
||||
MAPS,
|
||||
MEMORY,
|
||||
STACK,
|
||||
LOGS
|
||||
};
|
||||
|
||||
/* Log information onto the tombstone. */
|
||||
void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 3, 4)));
|
||||
|
||||
/* 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, SCOPE_AT_FAULT, fmt)
|
||||
#else
|
||||
#define LOG_ERROR(fmt...) _LOG(NULL, logtype::ERROR, fmt)
|
||||
#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, SCOPE_AT_FAULT, fmt)
|
||||
#else
|
||||
#define XLOG2(fmt...) do {} while(0)
|
||||
#endif
|
||||
|
||||
int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
|
||||
void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
|
||||
|
||||
void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags);
|
||||
void dump_memory(log_t* log, pid_t tid, uintptr_t addr);
|
||||
|
||||
#endif // _DEBUGGERD_UTILITY_H
|
||||
|
|
|
|||
|
|
@ -25,21 +25,21 @@
|
|||
#include "../utility.h"
|
||||
#include "../machine.h"
|
||||
|
||||
void dump_memory_and_code(log_t*, pid_t, int) {
|
||||
void dump_memory_and_code(log_t*, pid_t) {
|
||||
}
|
||||
|
||||
void dump_registers(log_t* log, pid_t tid, int scope_flags) {
|
||||
void dump_registers(log_t* log, pid_t tid) {
|
||||
struct pt_regs r;
|
||||
if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
|
||||
_LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
|
||||
LOG_ERROR("cannot get registers: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
_LOG(log, scope_flags, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
|
||||
_LOG(log, logtype::REGISTERS, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
|
||||
r.eax, r.ebx, r.ecx, r.edx);
|
||||
_LOG(log, scope_flags, " esi %08lx edi %08lx\n",
|
||||
_LOG(log, logtype::REGISTERS, " esi %08lx edi %08lx\n",
|
||||
r.esi, r.edi);
|
||||
_LOG(log, scope_flags, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n",
|
||||
_LOG(log, logtype::REGISTERS, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n",
|
||||
r.xcs, r.xds, r.xes, r.xfs, r.xss);
|
||||
_LOG(log, scope_flags, " eip %08lx ebp %08lx esp %08lx flags %08lx\n",
|
||||
_LOG(log, logtype::REGISTERS, " eip %08lx ebp %08lx esp %08lx flags %08lx\n",
|
||||
r.eip, r.ebp, r.esp, r.eflags);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,25 +27,25 @@
|
|||
#include "../utility.h"
|
||||
#include "../machine.h"
|
||||
|
||||
void dump_memory_and_code(log_t*, pid_t, int) {
|
||||
void dump_memory_and_code(log_t*, pid_t) {
|
||||
}
|
||||
|
||||
void dump_registers(log_t* log, pid_t tid, int scope_flags) {
|
||||
void dump_registers(log_t* log, pid_t tid) {
|
||||
struct user_regs_struct r;
|
||||
if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
|
||||
_LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
|
||||
LOG_ERROR("cannot get registers: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
_LOG(log, scope_flags, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
|
||||
_LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
|
||||
r.rax, r.rbx, r.rcx, r.rdx);
|
||||
_LOG(log, scope_flags, " rsi %016lx rdi %016lx\n",
|
||||
_LOG(log, logtype::REGISTERS, " rsi %016lx rdi %016lx\n",
|
||||
r.rsi, r.rdi);
|
||||
_LOG(log, scope_flags, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
|
||||
_LOG(log, logtype::REGISTERS, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
|
||||
r.r8, r.r9, r.r10, r.r11);
|
||||
_LOG(log, scope_flags, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
|
||||
_LOG(log, logtype::REGISTERS, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
|
||||
r.r12, r.r13, r.r14, r.r15);
|
||||
_LOG(log, scope_flags, " cs %016lx ss %016lx\n",
|
||||
_LOG(log, logtype::REGISTERS, " cs %016lx ss %016lx\n",
|
||||
r.cs, r.ss);
|
||||
_LOG(log, scope_flags, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
|
||||
_LOG(log, logtype::REGISTERS, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
|
||||
r.rip, r.rbp, r.rsp, r.eflags);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue