Pass si_code through to debuggerd.

Because we re-raise various signals, we corrupt the si_code that debuggerd
sees when it ptraces our siginfo. One possible solution (shown here) is to
pass the original si_code value in the message we send to debuggerd.

Change-Id: I76f9aa2c0442e5cab611d132532409e700383907
diff --git a/linker/debugger.cpp b/linker/debugger.cpp
index a44380c..272c16a 100644
--- a/linker/debugger.cpp
+++ b/linker/debugger.cpp
@@ -64,6 +64,9 @@
 
   // version 2 added:
   uintptr_t abort_msg_address;
+
+  // version 3 added:
+  int32_t original_si_code;
 };
 
 // see man(2) prctl, specifically the section about PR_GET_NAME
@@ -199,11 +202,44 @@
   return result;
 }
 
+static void send_debuggerd_packet(siginfo_t* info) {
+  int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM);
+  if (s == -1) {
+    __libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s",
+                      strerror(errno));
+    return;
+  }
+
+  // debuggerd knows our pid from the credentials on the
+  // local socket but we need to tell it the tid of the crashing thread.
+  // debuggerd will be paranoid and verify that we sent a tid
+  // that's actually in our process.
+  debugger_msg_t msg;
+  msg.action = DEBUGGER_ACTION_CRASH;
+  msg.tid = gettid();
+  msg.abort_msg_address = reinterpret_cast<uintptr_t>(gAbortMessage);
+  msg.original_si_code = (info != NULL) ? info->si_code : 0;
+  int ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
+  if (ret == sizeof(msg)) {
+    char debuggerd_ack;
+    ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1));
+    int saved_errno = errno;
+    notify_gdb_of_libraries();
+    errno = saved_errno;
+  } else {
+    // read or write failed -- broken connection?
+    __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s",
+                      strerror(errno));
+  }
+
+  close(s);
+}
+
 /*
  * Catches fatal signals so we can ask debuggerd to ptrace us before
  * we crash.
  */
-void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {
+static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {
   // It's possible somebody cleared the SA_SIGINFO flag, which would mean
   // our "info" arg holds an undefined value.
   if (!have_siginfo(signal_number)) {
@@ -212,38 +248,7 @@
 
   log_signal_summary(signal_number, info);
 
-  int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM);
-  if (s != -1) {
-    // debuggerd knows our pid from the credentials on the
-    // local socket but we need to tell it the tid of the crashing thread.
-    // debuggerd will be paranoid and verify that we sent a tid
-    // that's actually in our process.
-    debugger_msg_t msg;
-    msg.action = DEBUGGER_ACTION_CRASH;
-    msg.tid = gettid();
-    msg.abort_msg_address = reinterpret_cast<uintptr_t>(gAbortMessage);
-    int ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
-    if (ret == sizeof(msg)) {
-      // If the write failed, there is no point trying to read a response.
-      char debuggerd_ack;
-      ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1));
-      int saved_errno = errno;
-      notify_gdb_of_libraries();
-      errno = saved_errno;
-    }
-
-    if (ret < 0) {
-      // read or write failed -- broken connection?
-      __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s",
-                        strerror(errno));
-    }
-
-    close(s);
-  } else {
-    // socket failed; maybe process ran out of fds?
-    __libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s",
-                      strerror(errno));
-  }
+  send_debuggerd_packet(info);
 
   // Remove our net so we fault for real when we return.
   signal(signal_number, SIG_DFL);
@@ -251,8 +256,9 @@
   // These signals are not re-thrown when we resume.  This means that
   // crashing due to (say) SIGPIPE doesn't work the way you'd expect it
   // to.  We work around this by throwing them manually.  We don't want
-  // to do this for *all* signals because it'll screw up the address for
-  // faults like SIGSEGV.
+  // to do this for *all* signals because it'll screw up the si_addr for
+  // faults like SIGSEGV. It does screw up the si_code, which is why we
+  // passed that to debuggerd above.
   switch (signal_number) {
     case SIGABRT:
     case SIGFPE:
@@ -267,7 +273,7 @@
   }
 }
 
-void debuggerd_init() {
+__LIBC_HIDDEN__ void debuggerd_init() {
   struct sigaction action;
   memset(&action, 0, sizeof(action));
   sigemptyset(&action.sa_mask);