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
diff --git a/linker/debugger.c b/linker/debugger.c
index abb383c..648dc78 100644
--- a/linker/debugger.c
+++ b/linker/debugger.c
@@ -87,13 +87,49 @@
     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 @@
     }
 
     /* 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 4d00bd9..0c68a0b 100644
--- a/linker/linker_format.c
+++ b/linker/linker_format.c
@@ -427,18 +427,20 @@
 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 @@
             bytelen = sizeof(ptrdiff_t);
             c = format[nn++];
             break;
-        case 'p':
-            bytelen = sizeof(void*);
-            c = format[nn++];
         default:
             ;
         }
@@ -543,7 +542,7 @@
             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 @@
     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 @@
     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;
 }