Changing how debuggerd filters log messages to different locations.
The system by which debuggerd filters its output to different locations is now based on an enum called logtype with easy to understand categories for log messages (like THREAD, MEMORY, etc.) instead of the old, fairly esoteric scope_flags variable. Now much of the output that previously went to logcat does not show up on the screen, but all output can be found in the tombstone file. In addition, the tombstone's location is now printed so it can be located easily. Bug: 15341747 Change-Id: Ia2f2051d1dfdea934d0e6ed220f24345e35ba6a2
This commit is contained in:
parent
59d16c9e91
commit
62ba489ba0
|
@ -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…
Reference in New Issue