From ec92af8fe5d28c74f3505932135b1b8f3fbaad00 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Fri, 29 Jul 2011 12:46:34 -0700 Subject: [PATCH] Log signal info at time of receipt When a fatal signal is received, we now write a message to the log that looks like this: F/libc ( 1540): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1) This is useful for debugging fatal signals that turn out not to be fatal. This also changes the signal reset from SIG_IGN to SIG_DFL, so that future non-fatal fatal signals are fatal. The code that blocked SIGUSR1 to avoid being interrupted by the GC has been removed. Also, fix minor issues in format_buffer(). Bug 5035703 Change-Id: I8940af47297b5dcf3cf33537e3483ca5334ed565 --- linker/debugger.c | 64 ++++++++++++++++++++++++++++++++++-------- linker/linker_format.c | 32 +++++++++++---------- 2 files changed, 70 insertions(+), 26 deletions(-) diff --git a/linker/debugger.c b/linker/debugger.c index abb383c49..648dc78f4 100644 --- a/linker/debugger.c +++ b/linker/debugger.c @@ -87,13 +87,49 @@ static int socket_abstract_client(const char *name, int type) return s; } -void debugger_signal_handler(int n) +#include "linker_format.h" +#include <../libc/private/logd.h> + +/* + * Writes a summary of the signal to the log file. + * + * We could be here as a result of native heap corruption, or while a + * mutex is being held, so we don't want to use any libc functions that + * could allocate memory or hold a lock. + */ +static void logSignalSummary(int signum, const siginfo_t* info) +{ + char buffer[128]; + + char* signame; + switch (signum) { + case SIGILL: signame = "SIGILL"; break; + case SIGABRT: signame = "SIGABRT"; break; + case SIGBUS: signame = "SIGBUS"; break; + case SIGFPE: signame = "SIGFPE"; break; + case SIGSEGV: signame = "SIGSEGV"; break; + case SIGSTKFLT: signame = "SIGSTKFLT"; break; + case SIGPIPE: signame = "SIGPIPE"; break; + default: signame = "???"; break; + } + + format_buffer(buffer, sizeof(buffer), + "Fatal signal %d (%s) at 0x%08x (code=%d)", + signum, signame, info->si_addr, info->si_code); + + __libc_android_log_write(ANDROID_LOG_FATAL, "libc", buffer); +} + +/* + * Catches fatal signals so we can ask debuggerd to ptrace us before + * we crash. + */ +void debugger_signal_handler(int n, siginfo_t* info, void* unused) { unsigned tid; int s; - /* avoid picking up GC interrupts */ - signal(SIGUSR1, SIG_IGN); + logSignalSummary(n, info); tid = gettid(); s = socket_abstract_client("android:debuggerd", SOCK_STREAM); @@ -117,16 +153,22 @@ void debugger_signal_handler(int n) } /* remove our net so we fault for real when we return */ - signal(n, SIG_IGN); + signal(n, SIG_DFL); } void debugger_init() { - signal(SIGILL, debugger_signal_handler); - signal(SIGABRT, debugger_signal_handler); - signal(SIGBUS, debugger_signal_handler); - signal(SIGFPE, debugger_signal_handler); - signal(SIGSEGV, debugger_signal_handler); - signal(SIGSTKFLT, debugger_signal_handler); - signal(SIGPIPE, debugger_signal_handler); + struct sigaction act; + memset(&act, 0, sizeof(act)); + act.sa_sigaction = debugger_signal_handler; + act.sa_flags = SA_RESTART | SA_SIGINFO; + sigemptyset(&act.sa_mask); + + sigaction(SIGILL, &act, NULL); + sigaction(SIGABRT, &act, NULL); + sigaction(SIGBUS, &act, NULL); + sigaction(SIGFPE, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGSTKFLT, &act, NULL); + sigaction(SIGPIPE, &act, NULL); } diff --git a/linker/linker_format.c b/linker/linker_format.c index 4d00bd96e..0c68a0bf3 100644 --- a/linker/linker_format.c +++ b/linker/linker_format.c @@ -427,18 +427,20 @@ format_hex(char *buffer, size_t buffsize, uint64_t value, int isCap) static void out_vformat(Out *o, const char *format, va_list args) { - int nn = 0, mm; - int padZero = 0; - int padLeft = 0; - char sign = '\0'; - int width = -1; - int prec = -1; - size_t bytelen = sizeof(int); - const char* str; - int slen; - char buffer[32]; /* temporary buffer used to format numbers */ + int nn = 0; for (;;) { + int mm; + int padZero = 0; + int padLeft = 0; + char sign = '\0'; + int width = -1; + int prec = -1; + size_t bytelen = sizeof(int); + const char* str; + int slen; + char buffer[32]; /* temporary buffer used to format numbers */ + char c; /* first, find all characters that are not 0 or '%' */ @@ -525,9 +527,6 @@ out_vformat(Out *o, const char *format, va_list args) bytelen = sizeof(ptrdiff_t); c = format[nn++]; break; - case 'p': - bytelen = sizeof(void*); - c = format[nn++]; default: ; } @@ -543,7 +542,7 @@ out_vformat(Out *o, const char *format, va_list args) buffer[1] = '\0'; str = buffer; } else if (c == 'p') { - uint64_t value = (uint64_t)(ptrdiff_t) va_arg(args, void*); + uint64_t value = (uintptr_t) va_arg(args, void*); buffer[0] = '0'; buffer[1] = 'x'; format_hex(buffer + 2, sizeof buffer-2, value, 0); @@ -684,7 +683,7 @@ int main(void) utest_expect("-8123", "%d", -8123); utest_expect("16", "%hd", 0x7fff0010); utest_expect("16", "%hhd", 0x7fffff10); - utest_expect("68719476736", "%lld", 0x1000000000); + utest_expect("68719476736", "%lld", 0x1000000000LL); utest_expect("70000", "%ld", 70000); utest_expect("0xb0001234", "%p", (void*)0xb0001234); utest_expect("12ab", "%x", 0x12ab); @@ -697,6 +696,9 @@ int main(void) utest_expect("1234 ", "%-8d", 1234); utest_expect("abcdef ", "%-11s", "abcdef"); utest_expect("something:1234", "%s:%d", "something", 1234); + utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5); + utest_expect("5,0x0", "%d,%p", 5, NULL); + utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8); return gFails != 0; }