* commit 'f8db4afb703e0005eca7207bfdcc989c6cf66f1a': Use the si_code value bionic passes us.
This commit is contained in:
commit
29941ec817
6 changed files with 67 additions and 43 deletions
|
|
@ -126,7 +126,7 @@ static int do_action(const char* arg)
|
||||||
return ctest();
|
return ctest();
|
||||||
} else if (!strcmp(arg, "exit")) {
|
} else if (!strcmp(arg, "exit")) {
|
||||||
exit(1);
|
exit(1);
|
||||||
} else if (!strcmp(arg, "crash")) {
|
} else if (!strcmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
|
||||||
return crash(42);
|
return crash(42);
|
||||||
} else if (!strcmp(arg, "abort")) {
|
} else if (!strcmp(arg, "abort")) {
|
||||||
maybe_abort();
|
maybe_abort();
|
||||||
|
|
@ -138,23 +138,32 @@ static int do_action(const char* arg)
|
||||||
LOG_ALWAYS_FATAL("hello %s", "world");
|
LOG_ALWAYS_FATAL("hello %s", "world");
|
||||||
} else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
|
} else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
|
||||||
LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
|
LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
|
||||||
|
} else if (!strcmp(arg, "SIGPIPE")) {
|
||||||
|
int pipe_fds[2];
|
||||||
|
pipe(pipe_fds);
|
||||||
|
close(pipe_fds[0]);
|
||||||
|
write(pipe_fds[1], "oops", 4);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
} else if (!strcmp(arg, "heap-usage")) {
|
} else if (!strcmp(arg, "heap-usage")) {
|
||||||
abuse_heap();
|
abuse_heap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "%s OP\n", __progname);
|
fprintf(stderr, "%s OP\n", __progname);
|
||||||
fprintf(stderr, "where OP is:\n");
|
fprintf(stderr, "where OP is:\n");
|
||||||
fprintf(stderr, " smash-stack overwrite a stack-guard canary\n");
|
fprintf(stderr, " smash-stack overwrite a stack-guard canary\n");
|
||||||
fprintf(stderr, " stack-overflow recurse until the stack overflows\n");
|
fprintf(stderr, " stack-overflow recurse until the stack overflows\n");
|
||||||
fprintf(stderr, " heap-corruption cause a libc abort by corrupting the heap\n");
|
fprintf(stderr, " heap-corruption cause a libc abort by corrupting the heap\n");
|
||||||
fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n");
|
fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n");
|
||||||
fprintf(stderr, " nostack crash with a NULL stack pointer\n");
|
fprintf(stderr, " nostack crash with a NULL stack pointer\n");
|
||||||
fprintf(stderr, " ctest (obsoleted by thread-crash?)\n");
|
fprintf(stderr, " ctest (obsoleted by thread-crash?)\n");
|
||||||
fprintf(stderr, " exit call exit(1)\n");
|
fprintf(stderr, " exit call exit(1)\n");
|
||||||
fprintf(stderr, " crash cause a SIGSEGV\n");
|
fprintf(stderr, " abort call abort()\n");
|
||||||
fprintf(stderr, " abort call abort()\n");
|
fprintf(stderr, " assert call assert() without a function\n");
|
||||||
fprintf(stderr, " assert call assert() without a function\n");
|
fprintf(stderr, " assert2 call assert() with a function\n");
|
||||||
fprintf(stderr, " assert2 call assert() with a function\n");
|
fprintf(stderr, " LOG_ALWAYS_FATAL call LOG_ALWAYS_FATAL\n");
|
||||||
|
fprintf(stderr, " LOG_ALWAYS_FATAL_IF call LOG_ALWAYS_FATAL\n");
|
||||||
|
fprintf(stderr, " SIGPIPE cause a SIGPIPE\n");
|
||||||
|
fprintf(stderr, " SIGSEGV cause a SIGSEGV (synonym: crash)\n");
|
||||||
fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
|
fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
|
||||||
fprintf(stderr, "on the process' main thread.\n");
|
fprintf(stderr, "on the process' main thread.\n");
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ struct debugger_request_t {
|
||||||
pid_t pid, tid;
|
pid_t pid, tid;
|
||||||
uid_t uid, gid;
|
uid_t uid, gid;
|
||||||
uintptr_t abort_msg_address;
|
uintptr_t abort_msg_address;
|
||||||
|
int32_t original_si_code;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int write_string(const char* file, const char* string) {
|
static int write_string(const char* file, const char* string) {
|
||||||
|
|
@ -218,6 +219,7 @@ static int read_request(int fd, debugger_request_t* out_request) {
|
||||||
out_request->uid = cr.uid;
|
out_request->uid = cr.uid;
|
||||||
out_request->gid = cr.gid;
|
out_request->gid = cr.gid;
|
||||||
out_request->abort_msg_address = msg.abort_msg_address;
|
out_request->abort_msg_address = msg.abort_msg_address;
|
||||||
|
out_request->original_si_code = msg.original_si_code;
|
||||||
|
|
||||||
if (msg.action == DEBUGGER_ACTION_CRASH) {
|
if (msg.action == DEBUGGER_ACTION_CRASH) {
|
||||||
// Ensure that the tid reported by the crashing process is valid.
|
// Ensure that the tid reported by the crashing process is valid.
|
||||||
|
|
@ -302,9 +304,10 @@ static void handle_request(int fd) {
|
||||||
case SIGSTOP:
|
case SIGSTOP:
|
||||||
if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
|
if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
|
||||||
XLOG("stopped -- dumping to tombstone\n");
|
XLOG("stopped -- dumping to tombstone\n");
|
||||||
tombstone_path = engrave_tombstone(
|
tombstone_path = engrave_tombstone(request.pid, request.tid,
|
||||||
request.pid, request.tid, signal, request.abort_msg_address, true, true,
|
signal, request.original_si_code,
|
||||||
&detach_failed, &total_sleep_time_usec);
|
request.abort_msg_address, true, true,
|
||||||
|
&detach_failed, &total_sleep_time_usec);
|
||||||
} else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
|
} else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
|
||||||
XLOG("stopped -- dumping to fd\n");
|
XLOG("stopped -- dumping to fd\n");
|
||||||
dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed,
|
dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed,
|
||||||
|
|
@ -336,9 +339,10 @@ static void handle_request(int fd) {
|
||||||
kill(request.pid, SIGSTOP);
|
kill(request.pid, SIGSTOP);
|
||||||
// don't dump sibling threads when attaching to GDB because it
|
// don't dump sibling threads when attaching to GDB because it
|
||||||
// makes the process less reliable, apparently...
|
// makes the process less reliable, apparently...
|
||||||
tombstone_path = engrave_tombstone(
|
tombstone_path = engrave_tombstone(request.pid, request.tid,
|
||||||
request.pid, request.tid, signal, request.abort_msg_address, !attach_gdb,
|
signal, request.original_si_code,
|
||||||
false, &detach_failed, &total_sleep_time_usec);
|
request.abort_msg_address, !attach_gdb, false,
|
||||||
|
&detach_failed, &total_sleep_time_usec);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
// Must match the path defined in NativeCrashListener.java
|
// Must match the path defined in NativeCrashListener.java
|
||||||
#define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
|
#define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
|
||||||
|
|
||||||
static bool signal_has_address(int sig) {
|
static bool signal_has_si_addr(int sig) {
|
||||||
switch (sig) {
|
switch (sig) {
|
||||||
case SIGILL:
|
case SIGILL:
|
||||||
case SIGFPE:
|
case SIGFPE:
|
||||||
|
|
@ -75,7 +75,7 @@ static const char* get_signame(int sig) {
|
||||||
case SIGFPE: return "SIGFPE";
|
case SIGFPE: return "SIGFPE";
|
||||||
case SIGSEGV: return "SIGSEGV";
|
case SIGSEGV: return "SIGSEGV";
|
||||||
case SIGPIPE: return "SIGPIPE";
|
case SIGPIPE: return "SIGPIPE";
|
||||||
#ifdef SIGSTKFLT
|
#if defined(SIGSTKFLT)
|
||||||
case SIGSTKFLT: return "SIGSTKFLT";
|
case SIGSTKFLT: return "SIGSTKFLT";
|
||||||
#endif
|
#endif
|
||||||
case SIGSTOP: return "SIGSTOP";
|
case SIGSTOP: return "SIGSTOP";
|
||||||
|
|
@ -171,20 +171,26 @@ static void dump_build_info(log_t* log) {
|
||||||
_LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
|
_LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_fault_addr(log_t* log, pid_t tid, int sig) {
|
static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) {
|
||||||
siginfo_t si;
|
siginfo_t si;
|
||||||
|
|
||||||
memset(&si, 0, sizeof(si));
|
memset(&si, 0, sizeof(si));
|
||||||
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
|
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
|
||||||
_LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
|
_LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
|
||||||
} else if (signal_has_address(sig)) {
|
return;
|
||||||
_LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %" PRIPTR "\n",
|
|
||||||
sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code),
|
|
||||||
reinterpret_cast<uintptr_t>(si.si_addr));
|
|
||||||
} else {
|
|
||||||
_LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr --------\n",
|
|
||||||
sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bionic has to re-raise some signals, which overwrites the si_code with SI_TKILL.
|
||||||
|
si.si_code = si_code;
|
||||||
|
|
||||||
|
char addr_desc[32]; // ", fault addr 0x1234"
|
||||||
|
if (signal_has_si_addr(signal)) {
|
||||||
|
snprintf(addr_desc, sizeof(addr_desc), "%p", si.si_addr);
|
||||||
|
} else {
|
||||||
|
snprintf(addr_desc, sizeof(addr_desc), "--------");
|
||||||
|
}
|
||||||
|
|
||||||
|
_LOG(log, SCOPE_AT_FAULT, "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, int scope_flags) {
|
||||||
|
|
@ -349,7 +355,7 @@ static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid, int scope
|
||||||
_LOG(log, scope_flags, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
|
_LOG(log, scope_flags, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!signal_has_address(si.si_signo)) {
|
if (!signal_has_si_addr(si.si_signo)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -588,8 +594,9 @@ static void dump_abort_message(Backtrace* backtrace, log_t* log, uintptr_t addre
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dumps all information about the specified pid to the tombstone.
|
// Dumps all information about the specified pid to the tombstone.
|
||||||
static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
|
static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code,
|
||||||
bool dump_sibling_threads, int* total_sleep_time_usec) {
|
uintptr_t abort_msg_address, bool dump_sibling_threads,
|
||||||
|
int* total_sleep_time_usec) {
|
||||||
// don't copy log messages to tombstone unless this is a dev device
|
// don't copy log messages to tombstone unless this is a dev device
|
||||||
char value[PROPERTY_VALUE_MAX];
|
char value[PROPERTY_VALUE_MAX];
|
||||||
property_get("ro.debuggable", value, "0");
|
property_get("ro.debuggable", value, "0");
|
||||||
|
|
@ -611,7 +618,7 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a
|
||||||
dump_revision_info(log);
|
dump_revision_info(log);
|
||||||
dump_thread_info(log, pid, tid, SCOPE_AT_FAULT);
|
dump_thread_info(log, pid, tid, SCOPE_AT_FAULT);
|
||||||
if (signal) {
|
if (signal) {
|
||||||
dump_fault_addr(log, tid, signal);
|
dump_signal_info(log, tid, signal, si_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
|
UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
|
||||||
|
|
@ -725,9 +732,9 @@ static int activity_manager_connect() {
|
||||||
return amfd;
|
return amfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* engrave_tombstone(
|
char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
|
||||||
pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address, bool dump_sibling_threads,
|
uintptr_t abort_msg_address, bool dump_sibling_threads, bool quiet,
|
||||||
bool quiet, bool* detach_failed, int* total_sleep_time_usec) {
|
bool* detach_failed, int* total_sleep_time_usec) {
|
||||||
if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
|
if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
|
||||||
LOG("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
|
LOG("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
@ -752,8 +759,8 @@ char* engrave_tombstone(
|
||||||
log.tfd = fd;
|
log.tfd = fd;
|
||||||
log.amfd = activity_manager_connect();
|
log.amfd = activity_manager_connect();
|
||||||
log.quiet = quiet;
|
log.quiet = quiet;
|
||||||
*detach_failed = dump_crash(
|
*detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address,
|
||||||
&log, pid, tid, signal, abort_msg_address, dump_sibling_threads, total_sleep_time_usec);
|
dump_sibling_threads, total_sleep_time_usec);
|
||||||
|
|
||||||
close(log.amfd);
|
close(log.amfd);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,9 @@
|
||||||
|
|
||||||
/* Creates a tombstone file and writes the crash dump to it.
|
/* Creates a tombstone file and writes the crash dump to it.
|
||||||
* Returns the path of the tombstone, which must be freed using free(). */
|
* Returns the path of the tombstone, which must be freed using free(). */
|
||||||
char* engrave_tombstone(pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
|
char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
|
||||||
bool dump_sibling_threads, bool quiet, bool* detach_failed, int* total_sleep_time_usec);
|
uintptr_t abort_msg_address,
|
||||||
|
bool dump_sibling_threads, bool quiet,
|
||||||
|
bool* detach_failed, int* total_sleep_time_usec);
|
||||||
|
|
||||||
#endif // _DEBUGGERD_TOMBSTONE_H
|
#endif // _DEBUGGERD_TOMBSTONE_H
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ typedef struct {
|
||||||
debugger_action_t action;
|
debugger_action_t action;
|
||||||
pid_t tid;
|
pid_t tid;
|
||||||
uintptr_t abort_msg_address;
|
uintptr_t abort_msg_address;
|
||||||
|
int32_t original_si_code;
|
||||||
} debugger_msg_t;
|
} debugger_msg_t;
|
||||||
|
|
||||||
/* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
|
/* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <cutils/debugger.h>
|
#include <cutils/debugger.h>
|
||||||
|
|
@ -28,9 +29,9 @@ int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen) {
|
||||||
}
|
}
|
||||||
|
|
||||||
debugger_msg_t msg;
|
debugger_msg_t msg;
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
msg.tid = tid;
|
msg.tid = tid;
|
||||||
msg.action = DEBUGGER_ACTION_DUMP_TOMBSTONE;
|
msg.action = DEBUGGER_ACTION_DUMP_TOMBSTONE;
|
||||||
msg.abort_msg_address = 0;
|
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
|
if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
|
||||||
|
|
@ -62,9 +63,9 @@ int dump_backtrace_to_file(pid_t tid, int fd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
debugger_msg_t msg;
|
debugger_msg_t msg;
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
msg.tid = tid;
|
msg.tid = tid;
|
||||||
msg.action = DEBUGGER_ACTION_DUMP_BACKTRACE;
|
msg.action = DEBUGGER_ACTION_DUMP_BACKTRACE;
|
||||||
msg.abort_msg_address = 0;
|
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
|
if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue