Make abort messages available to debuggerd.

This adds __libc_fatal, cleans up the internal logging code a bit more,
and switches suitable callers over to __libc_fatal. In addition to logging,
__libc_fatal stashes the message somewhere that the debuggerd signal handler
can find it before calling abort.

In the debuggerd signal handler, we pass this address to debuggerd so that
it can come back with ptrace to read the message and present it to the user.

Bug: 8531731

(cherry picked from commit 0d787c1fa18c6a1f29ef9840e28a68cf077be1de)

Change-Id: I5daeeaa36c1fc23f7f437d73a19808d9d558dd4d
diff --git a/libc/bionic/__stack_chk_fail.cpp b/libc/bionic/__stack_chk_fail.cpp
index d5031ac..8b9ed5e 100644
--- a/libc/bionic/__stack_chk_fail.cpp
+++ b/libc/bionic/__stack_chk_fail.cpp
@@ -32,6 +32,5 @@
 #include "libc_logging.h"
 
 void __stack_chk_fail() {
-  __libc_format_log(ANDROID_LOG_FATAL, "libc", "stack corruption detected");
-  abort();
+  __libc_fatal("stack corruption detected");
 }
diff --git a/libc/bionic/assert.cpp b/libc/bionic/assert.cpp
index 6f221a5..84024c7 100644
--- a/libc/bionic/assert.cpp
+++ b/libc/bionic/assert.cpp
@@ -28,27 +28,16 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/types.h>
 #include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
+
 #include "libc_logging.h"
 
-// We log to stderr for the benefit of "adb shell" users, and the log for the benefit
-// of regular app developers who want to see their asserts.
-
 void __assert(const char* file, int line, const char* failed_expression) {
-  const char* fmt = "%s:%d: assertion \"%s\" failed\n";
-  __libc_format_log(ANDROID_LOG_FATAL, "libc", fmt, file, line, failed_expression);
-  fprintf(stderr, fmt, file, line, failed_expression);
-  abort();
+  __libc_fatal("%s:%d: assertion \"%s\" failed", file, line, failed_expression);
   /* NOTREACHED */
 }
 
 void __assert2(const char* file, int line, const char* function, const char* failed_expression) {
-  const char* fmt = "%s:%d: %s: assertion \"%s\" failed\n";
-  __libc_format_log(ANDROID_LOG_FATAL, "libc", fmt, file, line, function, failed_expression);
-  fprintf(stderr, fmt, file, line, function, failed_expression);
-  abort();
+  __libc_fatal("%s:%d: %s: assertion \"%s\" failed", file, line, function, failed_expression);
   /* NOTREACHED */
 }
diff --git a/libc/bionic/dlmalloc.c b/libc/bionic/dlmalloc.c
index cf09aac..51c62a7 100644
--- a/libc/bionic/dlmalloc.c
+++ b/libc/bionic/dlmalloc.c
@@ -16,15 +16,7 @@
 
 #include "dlmalloc.h"
 
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <linux/ashmem.h>
-
-#include <private/libc_logging.h>
+#include "private/libc_logging.h"
 
 // Send dlmalloc errors to the log.
 static void __bionic_heap_corruption_error(const char* function);
@@ -37,15 +29,12 @@
 #include "../upstream-dlmalloc/malloc.c"
 
 static void __bionic_heap_corruption_error(const char* function) {
-  __libc_format_log(ANDROID_LOG_FATAL, "libc", "@@@ ABORTING: heap corruption detected by %s",
-                    function);
-  abort();
+  __libc_fatal("@@@ ABORTING: heap corruption detected by %s", function);
 }
 
 static void __bionic_heap_usage_error(const char* function, void* address) {
-  __libc_format_log(ANDROID_LOG_FATAL, "libc",
-                    "@@@ ABORTING: invalid address or address of corrupt block %p passed to %s",
-                    address, function);
+  __libc_fatal("@@@ ABORTING: invalid address or address of corrupt block %p passed to %s",
+               address, function);
   // So that we can get a memory dump around the specific address.
   *((int**) 0xdeadbaad) = (int*) address;
 }
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 33ec1db..1fc490e 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -45,6 +45,7 @@
 #include "private/KernelArgumentBlock.h"
 #include "pthread_internal.h"
 
+extern "C" abort_msg_t** __abort_message_ptr;
 extern "C" unsigned __get_sp(void);
 extern "C" int __system_properties_init(void);
 
@@ -96,6 +97,7 @@
   errno = 0;
   __libc_auxv = args.auxv;
   __progname = args.argv[0] ? args.argv[0] : "<unknown>";
+  __abort_message_ptr = args.abort_message_ptr;
 
   // AT_RANDOM is a pointer to 16 bytes of randomness on the stack.
   __stack_chk_guard = *reinterpret_cast<uintptr_t*>(getauxval(AT_RANDOM));
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
index 755dc81..8de1192 100644
--- a/libc/bionic/libc_logging.cpp
+++ b/libc/bionic/libc_logging.cpp
@@ -31,228 +31,96 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <pthread.h>
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-
-/*** Generic output sink
- ***/
-
-struct Out {
-  void *opaque;
-  void (*send)(void *opaque, const char *data, int len);
-};
-
-static void out_send(Out *o, const char *data, size_t len) {
-    o->send(o->opaque, data, (int)len);
-}
-
-static void
-out_send_repeat(Out *o, char ch, int count)
-{
-    char pad[8];
-    const int padSize = (int)sizeof(pad);
-
-    memset(pad, ch, sizeof(pad));
-    while (count > 0) {
-        int avail = count;
-        if (avail > padSize) {
-            avail = padSize;
-        }
-        o->send(o->opaque, pad, avail);
-        count -= avail;
-    }
-}
-
-/* forward declaration */
-static void out_vformat(Out* o, const char* format, va_list args);
-
-/*** Bounded buffer output
- ***/
-
-struct BufOut {
-  Out out[1];
-  char *buffer;
-  char *pos;
-  char *end;
-  int total;
-};
-
-static void buf_out_send(void *opaque, const char *data, int len) {
-    BufOut *bo = reinterpret_cast<BufOut*>(opaque);
-
-    if (len < 0) {
-        len = strlen(data);
-    }
-
-    bo->total += len;
-
-    while (len > 0) {
-        int avail = bo->end - bo->pos;
-        if (avail == 0)
-            break;
-        if (avail > len)
-            avail = len;
-        memcpy(bo->pos, data, avail);
-        bo->pos += avail;
-        bo->pos[0] = '\0';
-        len -= avail;
-    }
-}
-
-static Out*
-buf_out_init(BufOut *bo, char *buffer, size_t size)
-{
-    if (size == 0)
-        return NULL;
-
-    bo->out->opaque = bo;
-    bo->out->send   = buf_out_send;
-    bo->buffer      = buffer;
-    bo->end         = buffer + size - 1;
-    bo->pos         = bo->buffer;
-    bo->pos[0]      = '\0';
-    bo->total       = 0;
-
-    return bo->out;
-}
-
-static int
-buf_out_length(BufOut *bo)
-{
-    return bo->total;
-}
-
-static int
-vformat_buffer(char *buff, size_t buf_size, const char *format, va_list args)
-{
-    BufOut bo;
-    Out *out;
-
-    out = buf_out_init(&bo, buff, buf_size);
-    if (out == NULL)
-        return 0;
-
-    out_vformat(out, format, args);
-
-    return buf_out_length(&bo);
-}
-
-int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
-  va_list args;
-  va_start(args, format);
-  int result = vformat_buffer(buffer, buffer_size, format, args);
-  va_end(args);
-  return result;
-}
-
-
-/*** File descriptor output
- ***/
-
-struct FdOut {
-  Out out[1];
-  int fd;
-  int total;
-};
-
-static void
-fd_out_send(void *opaque, const char *data, int len)
-{
-    FdOut *fdo = reinterpret_cast<FdOut*>(opaque);
-
-    if (len < 0)
-        len = strlen(data);
-
-    while (len > 0) {
-        int ret = write(fdo->fd, data, len);
-        if (ret < 0) {
-            if (errno == EINTR)
-                continue;
-            break;
-        }
-        data += ret;
-        len -= ret;
-        fdo->total += ret;
-    }
-}
-
-static Out*
-fd_out_init(FdOut *fdo, int  fd)
-{
-    fdo->out->opaque = fdo;
-    fdo->out->send = fd_out_send;
-    fdo->fd = fd;
-    fdo->total = 0;
-
-    return fdo->out;
-}
-
-static int
-fd_out_length(FdOut *fdo)
-{
-    return fdo->total;
-}
-
-
-int __libc_format_fd(int fd, const char* format, ...) {
-  FdOut fdo;
-  Out* out = fd_out_init(&fdo, fd);
-  if (out == NULL) {
-    return 0;
-  }
-
-  va_list args;
-  va_start(args, format);
-  out_vformat(out, format, args);
-  va_end(args);
-
-  return fd_out_length(&fdo);
-}
-
-/*** Log output
- ***/
-
-#include <unistd.h>
-#include <fcntl.h>
+#include <sys/mman.h>
 #include <sys/uio.h>
+#include <unistd.h>
 
+static pthread_mutex_t gAbortMsgLock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t gLogInitializationLock = PTHREAD_MUTEX_INITIALIZER;
 
-int __libc_format_log_va_list(int priority, const char* tag, const char* fmt, va_list args) {
-  char buf[1024];
-  int buf_strlen = vformat_buffer(buf, sizeof(buf), fmt, args);
+__LIBC_HIDDEN__ abort_msg_t** __abort_message_ptr; // Accessible to __libc_init_common.
 
-  static int main_log_fd = -1;
-  if (main_log_fd == -1) {
-    ScopedPthreadMutexLocker locker(&gLogInitializationLock);
-    main_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/main", O_CLOEXEC | O_WRONLY));
-    if (main_log_fd == -1) {
-      return -1;
+// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java.
+enum AndroidEventLogType {
+  EVENT_TYPE_INT      = 0,
+  EVENT_TYPE_LONG     = 1,
+  EVENT_TYPE_STRING   = 2,
+  EVENT_TYPE_LIST     = 3,
+};
+
+struct BufferOutputStream {
+ public:
+  BufferOutputStream(char* buffer, size_t size) : total(0) {
+    buffer_ = buffer;
+    end_ = buffer + size - 1;
+    pos_ = buffer_;
+    pos_[0] = '\0';
+  }
+
+  ~BufferOutputStream() {
+  }
+
+  void Send(const char* data, int len) {
+    if (len < 0) {
+      len = strlen(data);
+    }
+
+    while (len > 0) {
+      int avail = end_ - pos_;
+      if (avail == 0) {
+        break;
+      }
+      if (avail > len) {
+        avail = len;
+      }
+      memcpy(pos_, data, avail);
+      pos_ += avail;
+      pos_[0] = '\0';
+      len -= avail;
+      total += avail;
     }
   }
 
-  struct iovec vec[3];
-  vec[0].iov_base = &priority;
-  vec[0].iov_len = 1;
-  vec[1].iov_base = const_cast<char*>(tag);
-  vec[1].iov_len = strlen(tag) + 1;
-  vec[2].iov_base = const_cast<char*>(buf);
-  vec[2].iov_len = buf_strlen + 1;
+  int total;
 
-  return TEMP_FAILURE_RETRY(writev(main_log_fd, vec, 3));
-}
+ private:
+  char* buffer_;
+  char* pos_;
+  char* end_;
+};
 
-int __libc_format_log(int priority, const char* tag, const char* format, ...) {
-  va_list args;
-  va_start(args, format);
-  int result = __libc_format_log_va_list(priority, tag, format, args);
-  va_end(args);
-  return result;
-}
+struct FdOutputStream {
+ public:
+  FdOutputStream(int fd) : total(0), fd_(fd) {
+  }
+
+  void Send(const char* data, int len) {
+    if (len < 0) {
+      len = strlen(data);
+    }
+
+    while (len > 0) {
+      int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
+      if (rc == -1) {
+        break;
+      }
+      data += rc;
+      len -= rc;
+      total += rc;
+    }
+  }
+
+  int total;
+
+ private:
+  int fd_;
+};
 
 /*** formatted output implementation
  ***/
@@ -263,9 +131,7 @@
  *
  * NOTE: Does *not* handle a sign prefix.
  */
-static unsigned
-parse_decimal(const char *format, int *ppos)
-{
+static unsigned parse_decimal(const char *format, int *ppos) {
     const char* p = format + *ppos;
     unsigned result = 0;
 
@@ -273,8 +139,9 @@
         int ch = *p;
         unsigned d = (unsigned)(ch - '0');
 
-        if (d >= 10U)
+        if (d >= 10U) {
             break;
+        }
 
         result = result*10 + d;
         p++;
@@ -341,10 +208,25 @@
   format_unsigned(buf, buf_size, value, base, caps);
 }
 
+template <typename Out>
+static void SendRepeat(Out& o, char ch, int count) {
+  char pad[8];
+  memset(pad, ch, sizeof(pad));
+
+  const int pad_size = static_cast<int>(sizeof(pad));
+  while (count > 0) {
+    int avail = count;
+    if (avail > pad_size) {
+      avail = pad_size;
+    }
+    o.Send(pad, avail);
+    count -= avail;
+  }
+}
+
 /* Perform formatted output to an output target 'o' */
-static void
-out_vformat(Out *o, const char *format, va_list args)
-{
+template <typename Out>
+static void out_vformat(Out& o, const char* format, va_list args) {
     int nn = 0;
 
     for (;;) {
@@ -371,7 +253,7 @@
         } while (1);
 
         if (mm > nn) {
-            out_send(o, format+nn, mm-nn);
+            o.Send(format+nn, mm-nn);
             nn = mm;
         }
 
@@ -387,7 +269,7 @@
             c = format[nn++];
             if (c == '\0') {  /* single trailing '%' ? */
                 c = '%';
-                out_send(o, &c, 1);
+                o.Send(&c, 1);
                 return;
             }
             else if (c == '0') {
@@ -508,28 +390,74 @@
 
         if (slen < width && !padLeft) {
             char padChar = padZero ? '0' : ' ';
-            out_send_repeat(o, padChar, width - slen);
+            SendRepeat(o, padChar, width - slen);
         }
 
-        out_send(o, str, slen);
+        o.Send(str, slen);
 
         if (slen < width && padLeft) {
             char padChar = padZero ? '0' : ' ';
-            out_send_repeat(o, padChar, width - slen);
+            SendRepeat(o, padChar, width - slen);
         }
     }
 }
 
-// must be kept in sync with frameworks/base/core/java/android/util/EventLog.java
-enum AndroidEventLogType {
-  EVENT_TYPE_INT      = 0,
-  EVENT_TYPE_LONG     = 1,
-  EVENT_TYPE_STRING   = 2,
-  EVENT_TYPE_LIST     = 3,
-};
+int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
+  BufferOutputStream os(buffer, buffer_size);
+  va_list args;
+  va_start(args, format);
+  out_vformat(os, format, args);
+  va_end(args);
+  return os.total;
+}
+
+int __libc_format_fd(int fd, const char* format, ...) {
+  FdOutputStream os(fd);
+  va_list args;
+  va_start(args, format);
+  out_vformat(os, format, args);
+  va_end(args);
+  return os.total;
+}
+
+static int __libc_write_log(int priority, const char* tag, const char* msg) {
+  static int main_log_fd = -1;
+  if (main_log_fd == -1) {
+    ScopedPthreadMutexLocker locker(&gLogInitializationLock);
+    main_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/main", O_CLOEXEC | O_WRONLY));
+    if (main_log_fd == -1) {
+      return -1;
+    }
+  }
+
+  iovec vec[3];
+  vec[0].iov_base = &priority;
+  vec[0].iov_len = 1;
+  vec[1].iov_base = const_cast<char*>(tag);
+  vec[1].iov_len = strlen(tag) + 1;
+  vec[2].iov_base = const_cast<char*>(msg);
+  vec[2].iov_len = strlen(msg) + 1;
+
+  return TEMP_FAILURE_RETRY(writev(main_log_fd, vec, 3));
+}
+
+int __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
+  char buffer[1024];
+  BufferOutputStream os(buffer, sizeof(buffer));
+  out_vformat(os, format, args);
+  return __libc_write_log(priority, tag, buffer);
+}
+
+int __libc_format_log(int priority, const char* tag, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  int result = __libc_format_log_va_list(priority, tag, format, args);
+  va_end(args);
+  return result;
+}
 
 static int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) {
-  struct iovec vec[3];
+  iovec vec[3];
   vec[0].iov_base = &tag;
   vec[0].iov_len = sizeof(tag);
   vec[1].iov_base = &type;
@@ -554,9 +482,45 @@
 }
 
 void __fortify_chk_fail(const char *msg, uint32_t tag) {
-  __libc_format_log(ANDROID_LOG_FATAL, "libc", "FORTIFY_SOURCE: %s. Calling abort().\n", msg);
   if (tag != 0) {
     __libc_android_log_event_uid(tag);
   }
+  __libc_fatal("FORTIFY_SOURCE: %s. Calling abort().", msg);
+}
+
+void __libc_fatal(const char* format, ...) {
+  char msg[1024];
+  BufferOutputStream os(msg, sizeof(msg));
+  va_list args;
+  va_start(args, format);
+  out_vformat(os, format, args);
+  va_end(args);
+
+  // TODO: log to stderr for the benefit of "adb shell" users.
+
+  // Log to the log for the benefit of regular app developers (whose stdout and stderr are closed).
+  __libc_write_log(ANDROID_LOG_FATAL, "libc", msg);
+
+  __libc_set_abort_message(msg);
+
   abort();
 }
+
+void __libc_set_abort_message(const char* msg) {
+  size_t size = sizeof(abort_msg_t) + strlen(msg) + 1;
+  void* map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
+  if (map == MAP_FAILED) {
+    return;
+  }
+
+  if (__abort_message_ptr != NULL) {
+    ScopedPthreadMutexLocker locker(&gAbortMsgLock);
+    if (*__abort_message_ptr != NULL) {
+      munmap(*__abort_message_ptr, (*__abort_message_ptr)->size);
+    }
+    abort_msg_t* new_abort_message = reinterpret_cast<abort_msg_t*>(map);
+    new_abort_message->size = size;
+    strcpy(new_abort_message->msg, msg);
+    *__abort_message_ptr = new_abort_message;
+  }
+}
diff --git a/libc/bionic/malloc_debug_qemu.cpp b/libc/bionic/malloc_debug_qemu.cpp
index 08225c1..34ddb87 100644
--- a/libc/bionic/malloc_debug_qemu.cpp
+++ b/libc/bionic/malloc_debug_qemu.cpp
@@ -600,7 +600,7 @@
         error_log("Unable to open /dev/qemu_trace");
         return -1;
     } else {
-        qtrace = mmap(0, PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+        qtrace = mmap(NULL, PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
         close(fd);
 
         if (qtrace == MAP_FAILED) {
diff --git a/libc/bionic/system_properties.c b/libc/bionic/system_properties.c
index c9cf2f7..0587430 100644
--- a/libc/bionic/system_properties.c
+++ b/libc/bionic/system_properties.c
@@ -106,7 +106,7 @@
         goto cleanup;
     }
 
-    prop_area *pa = mmap(0, fd_stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
+    prop_area *pa = mmap(NULL, fd_stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
 
     if (pa == MAP_FAILED) {
         goto cleanup;
@@ -150,7 +150,7 @@
     while(count--) {
         unsigned entry = *toc++;
         if(TOC_NAME_LEN(entry) != len) continue;
-        
+
         pi = TOC_TO_INFO(pa, entry);
         if(memcmp(name, pi->name, len)) continue;
 
@@ -163,7 +163,7 @@
 int __system_property_read(const prop_info *pi, char *name, char *value)
 {
     unsigned serial, len;
-    
+
     for(;;) {
         serial = pi->serial;
         while(SERIAL_DIRTY(serial)) {
diff --git a/libc/private/KernelArgumentBlock.h b/libc/private/KernelArgumentBlock.h
index d777267..14eca06 100644
--- a/libc/private/KernelArgumentBlock.h
+++ b/libc/private/KernelArgumentBlock.h
@@ -21,6 +21,8 @@
 #include <stdint.h>
 #include <sys/auxv.h>
 
+struct abort_msg_t;
+
 // When the kernel starts the dynamic linker, it passes a pointer to a block
 // of memory containing argc, the argv array, the environment variable array,
 // and the array of ELF aux vectors. This class breaks that block up into its
@@ -67,6 +69,8 @@
   char** envp;
   Elf32_auxv_t* auxv;
 
+  abort_msg_t** abort_message_ptr;
+
  private:
   // Disallow copy and assignment.
   KernelArgumentBlock(const KernelArgumentBlock&);
diff --git a/libc/private/libc_logging.h b/libc/private/libc_logging.h
index 4c9dc21..281bad3 100644
--- a/libc/private/libc_logging.h
+++ b/libc/private/libc_logging.h
@@ -67,6 +67,20 @@
   ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
 };
 
+struct abort_msg_t {
+  size_t size;
+  char msg[0];
+};
+
+__LIBC_HIDDEN__ void __libc_set_abort_message(const char* msg);
+
+//
+// Formats a message to the log (priority 'fatal'), then aborts.
+//
+
+__LIBC_HIDDEN__ __noreturn void __libc_fatal(const char* format, ...)
+    __attribute__((__format__(printf, 1, 2)));
+
 //
 // Formatting routines for the C library's internal debugging.
 // Unlike the usual alternatives, these don't allocate.
diff --git a/linker/debugger.cpp b/linker/debugger.cpp
index 6fddb1c..a7c0591 100644
--- a/linker/debugger.cpp
+++ b/linker/debugger.cpp
@@ -52,8 +52,12 @@
 
 /* message sent over the socket */
 struct debugger_msg_t {
-    debugger_action_t action;
-    pid_t tid;
+  // version 1 included:
+  debugger_action_t action;
+  pid_t tid;
+
+  // version 2 added:
+  uintptr_t abort_msg_address;
 };
 
 // see man(2) prctl, specifically the section about PR_GET_NAME
@@ -154,14 +158,14 @@
     sigemptyset(&newact.sa_mask);
 
     if (sigaction(signum, &newact, &oldact) < 0) {
-      __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed testing for SA_SIGINFO: %s",
+      __libc_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s",
                         strerror(errno));
-      return 0;
+      return false;
     }
     bool ret = (oldact.sa_flags & SA_SIGINFO) != 0;
 
     if (sigaction(signum, &oldact, NULL) == -1) {
-      __libc_format_log(ANDROID_LOG_FATAL, "libc", "Restore failed in test for SA_SIGINFO: %s",
+      __libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s",
                         strerror(errno));
     }
     return ret;
@@ -186,19 +190,17 @@
     int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM);
 
     if (s >= 0) {
-        /* debugger knows our pid from the credentials on the
-         * local socket but we need to tell it our tid.  It
-         * is paranoid and will verify that we are giving a tid
-         * that's actually in our process
-         */
-        int  ret;
+        // 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 = tid;
-        ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
+        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 to read on
-             * the file descriptor. */
+            // if the write failed, there is no point trying to read a response.
             ret = TEMP_FAILURE_RETRY(read(s, &tid, 1));
             int saved_errno = errno;
             notify_gdb_of_libraries();
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 3afd314..47c45eb 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -105,6 +105,8 @@
 
 __LIBC_HIDDEN__ int gLdDebugVerbosity;
 
+__LIBC_HIDDEN__ abort_msg_t* gAbortMessage = NULL; // For debuggerd.
+
 enum RelocationKind {
     kRelocAbsolute = 0,
     kRelocRelative,
@@ -171,8 +173,7 @@
  */
 extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
 
-static r_debug _r_debug = {1, NULL, &rtld_db_dlactivity,
-                                  RT_CONSISTENT, 0};
+static r_debug _r_debug = {1, NULL, &rtld_db_dlactivity, RT_CONSISTENT, 0};
 static link_map_t* r_debug_tail = 0;
 
 static pthread_mutex_t gDebugMutex = PTHREAD_MUTEX_INITIALIZER;
@@ -1815,8 +1816,8 @@
 
   Elf32_Addr linker_addr = args.getauxval(AT_BASE);
 
-  Elf32_Ehdr *elf_hdr = (Elf32_Ehdr*) linker_addr;
-  Elf32_Phdr *phdr = (Elf32_Phdr*)((unsigned char*) linker_addr + elf_hdr->e_phoff);
+  Elf32_Ehdr* elf_hdr = (Elf32_Ehdr*) linker_addr;
+  Elf32_Phdr* phdr = (Elf32_Phdr*)((unsigned char*) linker_addr + elf_hdr->e_phoff);
 
   soinfo linker_so;
   memset(&linker_so, 0, sizeof(soinfo));
@@ -1841,6 +1842,7 @@
 
   // We have successfully fixed our own relocations. It's safe to run
   // the main part of the linker now.
+  args.abort_message_ptr = &gAbortMessage;
   Elf32_Addr start_address = __linker_init_post_relocation(args, linker_addr);
 
   set_soinfo_pool_protection(PROT_READ);
diff --git a/linker/linker.h b/linker/linker.h
index 6196bec..61d623a 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -186,6 +186,7 @@
 Elf32_Sym* dlsym_handle_lookup(soinfo* si, const char* name);
 
 void debuggerd_init();
+extern "C" abort_msg_t* gAbortMessage;
 extern "C" void notify_gdb_of_libraries();
 
 char* linker_get_error_buffer();