Make libc signal handler output more like debuggerd.
This has been annoying me for a while, because it's often quite misleading. Today, for example, I saw: Fatal signal 13 (SIGPIPE) at 0x6573 (code=0), thread 25971 (top) where the apparent address is actually the pid of the signal source (in this case the kernel on behalf of the thread itself). This patch isn't as fancy as strace, but it at least means we never say anything misleading. We could decode the si_code field like strace and debuggerd, but I'm reluctant to do that without some way to share the code between at least bionic and debuggerd. Examples after: Fatal signal 13 (SIGPIPE), code 0 in tid 9157 (top) Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 9142 (crasher64) Fatal signal 6 (SIGABRT), code -6 in tid 9132 (crasher64) (Note that the code still shows as 0 for SIGPIPE in the signal handler itself but as -6 (SI_TKILL) in debuggerd; this is actually correct --- debuggerd is showing the re-raised signal sent at the end of the signal handler that initially showed the correct code 0.) Change-Id: I71cad4ab61f422a4f6687a60ac770371790278e0
This commit is contained in:
parent
9b22c21cee
commit
17e6a98b48
@ -29,6 +29,7 @@
|
||||
#include "linker.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -78,12 +79,11 @@ static int socket_abstract_client(const char* name, int type) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This is used for abstract socket namespace, we need
|
||||
* an initial '\0' at the start of the Unix socket path.
|
||||
*
|
||||
* Note: The path in this case is *not* supposed to be
|
||||
* '\0'-terminated. ("man 7 unix" for the gory details.)
|
||||
*/
|
||||
// This is used for abstract socket namespace, we need
|
||||
// an initial '\0' at the start of the Unix socket path.
|
||||
//
|
||||
// Note: The path in this case is *not* supposed to be
|
||||
// '\0'-terminated. ("man 7 unix" for the gory details.)
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_LOCAL;
|
||||
addr.sun_path[0] = 0;
|
||||
@ -115,18 +115,36 @@ static int socket_abstract_client(const char* name, int type) {
|
||||
* could allocate memory or hold a lock.
|
||||
*/
|
||||
static void log_signal_summary(int signum, const siginfo_t* info) {
|
||||
const char* signal_name;
|
||||
const char* signal_name = "???";
|
||||
bool has_address = false;
|
||||
switch (signum) {
|
||||
case SIGILL: signal_name = "SIGILL"; break;
|
||||
case SIGABRT: signal_name = "SIGABRT"; break;
|
||||
case SIGBUS: signal_name = "SIGBUS"; break;
|
||||
case SIGFPE: signal_name = "SIGFPE"; break;
|
||||
case SIGSEGV: signal_name = "SIGSEGV"; break;
|
||||
case SIGILL:
|
||||
signal_name = "SIGILL";
|
||||
has_address = true;
|
||||
break;
|
||||
case SIGABRT:
|
||||
signal_name = "SIGABRT";
|
||||
break;
|
||||
case SIGBUS:
|
||||
signal_name = "SIGBUS";
|
||||
has_address = true;
|
||||
break;
|
||||
case SIGFPE:
|
||||
signal_name = "SIGFPE";
|
||||
has_address = true;
|
||||
break;
|
||||
case SIGSEGV:
|
||||
signal_name = "SIGSEGV";
|
||||
has_address = true;
|
||||
break;
|
||||
#if defined(SIGSTKFLT)
|
||||
case SIGSTKFLT: signal_name = "SIGSTKFLT"; break;
|
||||
case SIGSTKFLT:
|
||||
signal_name = "SIGSTKFLT";
|
||||
break;
|
||||
#endif
|
||||
case SIGPIPE: signal_name = "SIGPIPE"; break;
|
||||
default: signal_name = "???"; break;
|
||||
case SIGPIPE:
|
||||
signal_name = "SIGPIPE";
|
||||
break;
|
||||
}
|
||||
|
||||
char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination
|
||||
@ -139,17 +157,22 @@ static void log_signal_summary(int signum, const siginfo_t* info) {
|
||||
}
|
||||
|
||||
// "info" will be NULL if the siginfo_t information was not available.
|
||||
// Many signals don't have an address or a code.
|
||||
char code_desc[32]; // ", code -6"
|
||||
char addr_desc[32]; // ", fault addr 0x1234"
|
||||
addr_desc[0] = code_desc[0] = 0;
|
||||
if (info != NULL) {
|
||||
__libc_format_log(ANDROID_LOG_FATAL, "libc",
|
||||
"Fatal signal %d (%s) at %p (code=%d), thread %d (%s)",
|
||||
signum, signal_name, info->si_addr, info->si_code,
|
||||
gettid(), thread_name);
|
||||
} else {
|
||||
__libc_format_log(ANDROID_LOG_FATAL, "libc",
|
||||
"Fatal signal %d (%s), thread %d (%s)",
|
||||
signum, signal_name, gettid(), thread_name);
|
||||
// For a rethrown signal, this si_code will be right and the one debuggerd shows will
|
||||
// always be SI_TKILL.
|
||||
snprintf(code_desc, sizeof(code_desc), ", code %d", info->si_code);
|
||||
if (has_address) {
|
||||
snprintf(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
|
||||
}
|
||||
}
|
||||
__libc_format_log(ANDROID_LOG_FATAL, "libc",
|
||||
"Fatal signal %d (%s)%s%s in tid %d (%s)",
|
||||
signum, signal_name, code_desc, addr_desc, gettid(), thread_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the handler for signal "signum" has SA_SIGINFO set.
|
||||
|
Loading…
x
Reference in New Issue
Block a user