merge in jb-mr2-release history after reset to jb-mr2-dev
diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c
index 160db7b..67e3028 100644
--- a/debuggerd/arm/machine.c
+++ b/debuggerd/arm/machine.c
@@ -42,7 +42,7 @@
 #endif
 #endif
 
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, bool at_fault) {
+static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) {
     char code_buffer[64];       /* actual 8+1+((8+1)*4) + 1 == 45 */
     char ascii_buffer[32];      /* actual 16 + 1 == 17 */
     uintptr_t p, end;
@@ -102,7 +102,7 @@
             p += 4;
         }
         *asc_out = '\0';
-        _LOG(log, !at_fault, "    %s %s\n", code_buffer, ascii_buffer);
+        _LOG(log, scopeFlags, "    %s %s\n", code_buffer, ascii_buffer);
     }
 }
 
@@ -117,6 +117,8 @@
         return;
     }
 
+    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
+
     if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) {
         static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
 
@@ -132,17 +134,18 @@
                 continue;
             }
 
-            _LOG(log, false, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
-            dump_memory(log, tid, addr, at_fault);
+            _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
+            dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE);
         }
     }
 
-    _LOG(log, !at_fault, "\ncode around pc:\n");
-    dump_memory(log, tid, (uintptr_t)regs.ARM_pc, at_fault);
+    /* explicitly allow upload of code dump logging */
+    _LOG(log, scopeFlags, "\ncode around pc:\n");
+    dump_memory(log, tid, (uintptr_t)regs.ARM_pc, scopeFlags);
 
     if (regs.ARM_pc != regs.ARM_lr) {
-        _LOG(log, !at_fault, "\ncode around lr:\n");
-        dump_memory(log, tid, (uintptr_t)regs.ARM_lr, at_fault);
+        _LOG(log, scopeFlags, "\ncode around lr:\n");
+        dump_memory(log, tid, (uintptr_t)regs.ARM_lr, scopeFlags);
     }
 }
 
@@ -150,20 +153,20 @@
         log_t* log, pid_t tid, bool at_fault)
 {
     struct pt_regs r;
-    bool only_in_tombstone = !at_fault;
+    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
 
     if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-        _LOG(log, only_in_tombstone, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
         return;
     }
 
-    _LOG(log, only_in_tombstone, "    r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
+    _LOG(log, scopeFlags, "    r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
             (uint32_t)r.ARM_r0, (uint32_t)r.ARM_r1, (uint32_t)r.ARM_r2, (uint32_t)r.ARM_r3);
-    _LOG(log, only_in_tombstone, "    r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
+    _LOG(log, scopeFlags, "    r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
             (uint32_t)r.ARM_r4, (uint32_t)r.ARM_r5, (uint32_t)r.ARM_r6, (uint32_t)r.ARM_r7);
-    _LOG(log, only_in_tombstone, "    r8 %08x  r9 %08x  sl %08x  fp %08x\n",
+    _LOG(log, scopeFlags, "    r8 %08x  r9 %08x  sl %08x  fp %08x\n",
             (uint32_t)r.ARM_r8, (uint32_t)r.ARM_r9, (uint32_t)r.ARM_r10, (uint32_t)r.ARM_fp);
-    _LOG(log, only_in_tombstone, "    ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
+    _LOG(log, scopeFlags, "    ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
             (uint32_t)r.ARM_ip, (uint32_t)r.ARM_sp, (uint32_t)r.ARM_lr,
             (uint32_t)r.ARM_pc, (uint32_t)r.ARM_cpsr);
 
@@ -172,14 +175,14 @@
     int i;
 
     if(ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
-        _LOG(log, only_in_tombstone, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
         return;
     }
 
     for (i = 0; i < NUM_VFP_REGS; i += 2) {
-        _LOG(log, only_in_tombstone, "    d%-2d %016llx  d%-2d %016llx\n",
+        _LOG(log, scopeFlags, "    d%-2d %016llx  d%-2d %016llx\n",
                 i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
     }
-    _LOG(log, only_in_tombstone, "    scr %08lx\n", vfp_regs.fpscr);
+    _LOG(log, scopeFlags, "    scr %08lx\n", vfp_regs.fpscr);
 #endif
 }
diff --git a/debuggerd/backtrace.c b/debuggerd/backtrace.c
index 08f8836..f42f24c 100644
--- a/debuggerd/backtrace.c
+++ b/debuggerd/backtrace.c
@@ -51,15 +51,15 @@
     localtime_r(&t, &tm);
     char timestr[64];
     strftime(timestr, sizeof(timestr), "%F %T", &tm);
-    _LOG(log, false, "\n\n----- pid %d at %s -----\n", pid, timestr);
+    _LOG(log, SCOPE_AT_FAULT, "\n\n----- pid %d at %s -----\n", pid, timestr);
 
     if (procname) {
-        _LOG(log, false, "Cmd line: %s\n", procname);
+        _LOG(log, SCOPE_AT_FAULT, "Cmd line: %s\n", procname);
     }
 }
 
 static void dump_process_footer(log_t* log, pid_t pid) {
-    _LOG(log, false, "\n----- end %d -----\n", pid);
+    _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
 }
 
 static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool attached,
@@ -81,10 +81,11 @@
         }
     }
 
-    _LOG(log, false, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
+    _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n",
+            threadname ? threadname : "<unknown>", tid);
 
     if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
-        _LOG(log, false, "Could not attach to thread: %s\n", strerror(errno));
+        _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno));
         return;
     }
 
@@ -93,7 +94,7 @@
     backtrace_frame_t backtrace[STACK_DEPTH];
     ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH);
     if (frames <= 0) {
-        _LOG(log, false, "Could not obtain stack trace for thread.\n");
+        _LOG(log, SCOPE_AT_FAULT, "Could not obtain stack trace for thread.\n");
     } else {
         backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
         get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols);
@@ -101,7 +102,7 @@
             char line[MAX_BACKTRACE_LINE_LENGTH];
             format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
                     line, MAX_BACKTRACE_LINE_LENGTH);
-            _LOG(log, false, "  %s\n", line);
+            _LOG(log, SCOPE_AT_FAULT, "  %s\n", line);
         }
         free_backtrace_symbols(backtrace_symbols, frames);
     }
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index 2736f30..da2e9b0 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -52,6 +52,7 @@
     debugger_action_t action;
     pid_t pid, tid;
     uid_t uid, gid;
+    uintptr_t abort_msg_address;
 } debugger_request_t;
 
 static int
@@ -207,13 +208,16 @@
     }
 
     debugger_msg_t msg;
+    memset(&msg, 0, sizeof(msg));
     status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
     if (status < 0) {
         LOG("read failure? %s (pid=%d uid=%d)\n",
             strerror(errno), cr.pid, cr.uid);
         return -1;
     }
-    if (status != sizeof(msg)) {
+    if (status == sizeof(debugger_msg_t)) {
+        XLOG("crash request of size %d abort_msg_address=%#08x\n", status, msg.abort_msg_address);
+    } else {
         LOG("invalid crash request of size %d (from pid=%d uid=%d)\n",
             status, cr.pid, cr.uid);
         return -1;
@@ -224,6 +228,7 @@
     out_request->pid = cr.pid;
     out_request->uid = cr.uid;
     out_request->gid = cr.gid;
+    out_request->abort_msg_address = msg.abort_msg_address;
 
     if (msg.action == DEBUGGER_ACTION_CRASH) {
         /* Ensure that the tid reported by the crashing process is valid. */
@@ -267,6 +272,7 @@
     XLOG("handle_request(%d)\n", fd);
 
     debugger_request_t request;
+    memset(&request, 0, sizeof(request));
     int status = read_request(fd, &request);
     if (!status) {
         XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
@@ -310,7 +316,7 @@
                         if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
                             XLOG("stopped -- dumping to tombstone\n");
                             tombstone_path = engrave_tombstone(request.pid, request.tid,
-                                    signal, true, true, &detach_failed,
+                                    signal, request.abort_msg_address, true, true, &detach_failed,
                                     &total_sleep_time_usec);
                         } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
                             XLOG("stopped -- dumping to fd\n");
@@ -348,8 +354,8 @@
                         /* don't dump sibling threads when attaching to GDB because it
                          * makes the process less reliable, apparently... */
                         tombstone_path = engrave_tombstone(request.pid, request.tid,
-                                signal, !attach_gdb, false, &detach_failed,
-                                &total_sleep_time_usec);
+                                signal, request.abort_msg_address, !attach_gdb, false,
+                                &detach_failed, &total_sleep_time_usec);
                         break;
                     }
 
diff --git a/debuggerd/mips/machine.c b/debuggerd/mips/machine.c
index dba1711..65fdf02 100644
--- a/debuggerd/mips/machine.c
+++ b/debuggerd/mips/machine.c
@@ -36,7 +36,7 @@
 
 #define R(x) ((unsigned int)(x))
 
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, bool at_fault) {
+static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) {
     char code_buffer[64];       /* actual 8+1+((8+1)*4) + 1 == 45 */
     char ascii_buffer[32];      /* actual 16 + 1 == 17 */
     uintptr_t p, end;
@@ -92,7 +92,7 @@
             p += 4;
         }
         *asc_out = '\0';
-        _LOG(log, !at_fault, "    %s %s\n", code_buffer, ascii_buffer);
+        _LOG(log, scopeFlags, "    %s %s\n", code_buffer, ascii_buffer);
     }
 }
 
@@ -107,6 +107,7 @@
         return;
     }
 
+    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
     if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) {
         static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
 
@@ -129,20 +130,20 @@
                 continue;
             }
 
-            _LOG(log, false, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
-            dump_memory(log, tid, addr, at_fault);
+            _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
+            dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE);
         }
     }
 
     unsigned int pc = R(r.cp0_epc);
     unsigned int ra = R(r.regs[31]);
 
-    _LOG(log, !at_fault, "\ncode around pc:\n");
-    dump_memory(log, tid, (uintptr_t)pc, at_fault);
+    _LOG(log, scopeFlags, "\ncode around pc:\n");
+    dump_memory(log, tid, (uintptr_t)pc, scopeFlags);
 
     if (pc != ra) {
-        _LOG(log, !at_fault, "\ncode around ra:\n");
-        dump_memory(log, tid, (uintptr_t)ra, at_fault);
+        _LOG(log, scopeFlags, "\ncode around ra:\n");
+        dump_memory(log, tid, (uintptr_t)ra, scopeFlags);
     }
 }
 
@@ -150,29 +151,29 @@
         log_t* log, pid_t tid, bool at_fault)
 {
     pt_regs_mips_t r;
-    bool only_in_tombstone = !at_fault;
+    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
 
     if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-        _LOG(log, only_in_tombstone, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
         return;
     }
 
-    _LOG(log, only_in_tombstone, " zr %08x  at %08x  v0 %08x  v1 %08x\n",
+    _LOG(log, scopeFlags, " zr %08x  at %08x  v0 %08x  v1 %08x\n",
      R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
-    _LOG(log, only_in_tombstone, " a0 %08x  a1 %08x  a2 %08x  a3 %08x\n",
+    _LOG(log, scopeFlags, " a0 %08x  a1 %08x  a2 %08x  a3 %08x\n",
      R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
-    _LOG(log, only_in_tombstone, " t0 %08x  t1 %08x  t2 %08x  t3 %08x\n",
+    _LOG(log, scopeFlags, " t0 %08x  t1 %08x  t2 %08x  t3 %08x\n",
      R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
-    _LOG(log, only_in_tombstone, " t4 %08x  t5 %08x  t6 %08x  t7 %08x\n",
+    _LOG(log, scopeFlags, " t4 %08x  t5 %08x  t6 %08x  t7 %08x\n",
      R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
-    _LOG(log, only_in_tombstone, " s0 %08x  s1 %08x  s2 %08x  s3 %08x\n",
+    _LOG(log, scopeFlags, " s0 %08x  s1 %08x  s2 %08x  s3 %08x\n",
      R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
-    _LOG(log, only_in_tombstone, " s4 %08x  s5 %08x  s6 %08x  s7 %08x\n",
+    _LOG(log, scopeFlags, " s4 %08x  s5 %08x  s6 %08x  s7 %08x\n",
      R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
-    _LOG(log, only_in_tombstone, " t8 %08x  t9 %08x  k0 %08x  k1 %08x\n",
+    _LOG(log, scopeFlags, " t8 %08x  t9 %08x  k0 %08x  k1 %08x\n",
      R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
-    _LOG(log, only_in_tombstone, " gp %08x  sp %08x  s8 %08x  ra %08x\n",
+    _LOG(log, scopeFlags, " gp %08x  sp %08x  s8 %08x  ra %08x\n",
      R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
-    _LOG(log, only_in_tombstone, " hi %08x  lo %08x bva %08x epc %08x\n",
+    _LOG(log, scopeFlags, " hi %08x  lo %08x bva %08x epc %08x\n",
      R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
 }
diff --git a/debuggerd/tombstone.c b/debuggerd/tombstone.c
index 7c9cb6c..7146120 100644
--- a/debuggerd/tombstone.c
+++ b/debuggerd/tombstone.c
@@ -163,7 +163,7 @@
 
     property_get("ro.revision", revision, "unknown");
 
-    _LOG(log, false, "Revision: '%s'\n", revision);
+    _LOG(log, SCOPE_AT_FAULT, "Revision: '%s'\n", revision);
 }
 
 static void dump_build_info(log_t* log)
@@ -172,7 +172,7 @@
 
     property_get("ro.build.fingerprint", fingerprint, "unknown");
 
-    _LOG(log, false, "Build fingerprint: '%s'\n", fingerprint);
+    _LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
 }
 
 static void dump_fault_addr(log_t* log, pid_t tid, int sig)
@@ -181,14 +181,14 @@
 
     memset(&si, 0, sizeof(si));
     if(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
-        _LOG(log, false, "cannot get siginfo: %s\n", strerror(errno));
+        _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
     } else if (signal_has_address(sig)) {
-        _LOG(log, false, "signal %d (%s), code %d (%s), fault addr %08x\n",
+        _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %08x\n",
              sig, get_signame(sig),
              si.si_code, get_sigcode(sig, si.si_code),
              (uintptr_t) si.si_addr);
     } else {
-        _LOG(log, false, "signal %d (%s), code %d (%s), fault addr --------\n",
+        _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr --------\n",
              sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
     }
 }
@@ -221,19 +221,20 @@
             fclose(fp);
         }
 
-        _LOG(log, false, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", pid, tid,
+        _LOG(log, SCOPE_AT_FAULT, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", pid, tid,
                 threadname ? threadname : "UNKNOWN",
                 procname ? procname : "UNKNOWN");
     } else {
-        _LOG(log, true, "pid: %d, tid: %d, name: %s\n", pid, tid,
-                threadname ? threadname : "UNKNOWN");
+        _LOG(log, 0, "pid: %d, tid: %d, name: %s\n",
+                pid, tid, threadname ? threadname : "UNKNOWN");
     }
 }
 
 static void dump_backtrace(const ptrace_context_t* context __attribute((unused)),
         log_t* log, pid_t tid __attribute((unused)), bool at_fault,
         const backtrace_frame_t* backtrace, size_t frames) {
-    _LOG(log, !at_fault, "\nbacktrace:\n");
+    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
+    _LOG(log, scopeFlags, "\nbacktrace:\n");
 
     backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
     get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols);
@@ -241,13 +242,13 @@
         char line[MAX_BACKTRACE_LINE_LENGTH];
         format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
                 line, MAX_BACKTRACE_LINE_LENGTH);
-        _LOG(log, !at_fault, "    %s\n", line);
+        _LOG(log, scopeFlags, "    %s\n", line);
     }
     free_backtrace_symbols(backtrace_symbols, frames);
 }
 
 static void dump_stack_segment(const ptrace_context_t* context, log_t* log, pid_t tid,
-        bool only_in_tombstone, uintptr_t* sp, size_t words, int label) {
+        int scopeFlags, uintptr_t* sp, size_t words, int label) {
     for (size_t i = 0; i < words; i++) {
         uint32_t stack_content;
         if (!try_get_word_ptrace(tid, *sp, &stack_content)) {
@@ -264,28 +265,28 @@
             uint32_t offset = stack_content - (mi->start + symbol->start);
             if (!i && label >= 0) {
                 if (offset) {
-                    _LOG(log, only_in_tombstone, "    #%02d  %08x  %08x  %s (%s+%u)\n",
+                    _LOG(log, scopeFlags, "    #%02d  %08x  %08x  %s (%s+%u)\n",
                             label, *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
                 } else {
-                    _LOG(log, only_in_tombstone, "    #%02d  %08x  %08x  %s (%s)\n",
+                    _LOG(log, scopeFlags, "    #%02d  %08x  %08x  %s (%s)\n",
                             label, *sp, stack_content, mi ? mi->name : "", symbol_name);
                 }
             } else {
                 if (offset) {
-                    _LOG(log, only_in_tombstone, "         %08x  %08x  %s (%s+%u)\n",
+                    _LOG(log, scopeFlags, "         %08x  %08x  %s (%s+%u)\n",
                             *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
                 } else {
-                    _LOG(log, only_in_tombstone, "         %08x  %08x  %s (%s)\n",
+                    _LOG(log, scopeFlags, "         %08x  %08x  %s (%s)\n",
                             *sp, stack_content, mi ? mi->name : "", symbol_name);
                 }
             }
             free(demangled_name);
         } else {
             if (!i && label >= 0) {
-                _LOG(log, only_in_tombstone, "    #%02d  %08x  %08x  %s\n",
+                _LOG(log, scopeFlags, "    #%02d  %08x  %08x  %s\n",
                         label, *sp, stack_content, mi ? mi->name : "");
             } else {
-                _LOG(log, only_in_tombstone, "         %08x  %08x  %s\n",
+                _LOG(log, scopeFlags, "         %08x  %08x  %s\n",
                         *sp, stack_content, mi ? mi->name : "");
             }
         }
@@ -311,28 +312,28 @@
         return;
     }
 
-    _LOG(log, !at_fault, "\nstack:\n");
+    int scopeFlags = SCOPE_SENSITIVE | (at_fault ? SCOPE_AT_FAULT : 0);
+    _LOG(log, scopeFlags, "\nstack:\n");
 
     // Dump a few words before the first frame.
-    bool only_in_tombstone = !at_fault;
     uintptr_t sp = backtrace[first].stack_top - STACK_WORDS * sizeof(uint32_t);
-    dump_stack_segment(context, log, tid, only_in_tombstone, &sp, STACK_WORDS, -1);
+    dump_stack_segment(context, log, tid, scopeFlags, &sp, STACK_WORDS, -1);
 
     // Dump a few words from all successive frames.
     // Only log the first 3 frames, put the rest in the tombstone.
     for (size_t i = first; i <= last; i++) {
         const backtrace_frame_t* frame = &backtrace[i];
         if (sp != frame->stack_top) {
-            _LOG(log, only_in_tombstone, "         ........  ........\n");
+            _LOG(log, scopeFlags, "         ........  ........\n");
             sp = frame->stack_top;
         }
         if (i - first == 3) {
-            only_in_tombstone = true;
+            scopeFlags &= (~SCOPE_AT_FAULT);
         }
         if (i == last) {
-            dump_stack_segment(context, log, tid, only_in_tombstone, &sp, STACK_WORDS, i);
+            dump_stack_segment(context, log, tid, scopeFlags, &sp, STACK_WORDS, i);
             if (sp < frame->stack_top + frame->stack_size) {
-                _LOG(log, only_in_tombstone, "         ........  ........\n");
+                _LOG(log, scopeFlags, "         ........  ........\n");
             }
         } else {
             size_t words = frame->stack_size / sizeof(uint32_t);
@@ -341,7 +342,7 @@
             } else if (words > STACK_WORDS) {
                 words = STACK_WORDS;
             }
-            dump_stack_segment(context, log, tid, only_in_tombstone, &sp, words, i);
+            dump_stack_segment(context, log, tid, scopeFlags, &sp, words, i);
         }
     }
 }
@@ -358,13 +359,13 @@
 
 static void dump_map(log_t* log, map_info_t* m, const char* what) {
     if (m != NULL) {
-        _LOG(log, false, "    %08x-%08x %c%c%c %s\n", m->start, m->end,
+        _LOG(log, SCOPE_SENSITIVE, "    %08x-%08x %c%c%c %s\n", m->start, m->end,
              m->is_readable ? 'r' : '-',
              m->is_writable ? 'w' : '-',
              m->is_executable ? 'x' : '-',
              m->name);
     } else {
-        _LOG(log, false, "    (no %s)\n", what);
+        _LOG(log, SCOPE_SENSITIVE, "    (no %s)\n", what);
     }
 }
 
@@ -372,7 +373,7 @@
     siginfo_t si;
     memset(&si, 0, sizeof(si));
     if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
-        _LOG(log, false, "cannot get siginfo for %d: %s\n",
+        _LOG(log, SCOPE_SENSITIVE, "cannot get siginfo for %d: %s\n",
                 tid, strerror(errno));
         return;
     }
@@ -386,7 +387,7 @@
         return;
     }
 
-    _LOG(log, false, "\nmemory map around fault addr %08x:\n", (int)si.si_addr);
+    _LOG(log, SCOPE_SENSITIVE, "\nmemory map around fault addr %08x:\n", (int)si.si_addr);
 
     /*
      * Search for a match, or for a hole where the match would be.  The list
@@ -464,7 +465,7 @@
             continue;
         }
 
-        _LOG(log, true, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
+        _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
         dump_thread_info(log, pid, new_tid, false);
         dump_thread(context, log, new_tid, false, total_sleep_time_usec);
 
@@ -517,12 +518,12 @@
                 /* non-blocking EOF; we're done */
                 break;
             } else {
-                _LOG(log, true, "Error while reading log: %s\n",
+                _LOG(log, 0, "Error while reading log: %s\n",
                     strerror(errno));
                 break;
             }
         } else if (actual == 0) {
-            _LOG(log, true, "Got zero bytes while reading log: %s\n",
+            _LOG(log, 0, "Got zero bytes while reading log: %s\n",
                 strerror(errno));
             break;
         }
@@ -542,7 +543,7 @@
         }
 
         if (first) {
-            _LOG(log, true, "--------- %slog %s\n",
+            _LOG(log, 0, "--------- %slog %s\n",
                 tailOnly ? "tail end of " : "", filename);
             first = false;
         }
@@ -584,7 +585,7 @@
             shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
             shortLogCount++;
         } else {
-            _LOG(log, true, "%s.%03d %5d %5d %c %-8s: %s\n",
+            _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
                 timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
                 prioChar, tag, msg);
         }
@@ -604,7 +605,7 @@
         }
 
         for (i = 0; i < shortLogCount; i++) {
-            _LOG(log, true, "%s\n", shortLog[shortLogNext]);
+            _LOG(log, 0, "%s\n", shortLog[shortLogNext]);
             shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
         }
     }
@@ -622,11 +623,46 @@
     dump_log_file(log, pid, "/dev/log/main", tailOnly);
 }
 
+static void dump_abort_message(log_t* log, pid_t tid, uintptr_t address) {
+  if (address == 0) {
+    return;
+  }
+
+  address += sizeof(size_t); // Skip the buffer length.
+
+  char msg[512];
+  memset(msg, 0, sizeof(msg));
+  char* p = &msg[0];
+  while (p < &msg[sizeof(msg)]) {
+    uint32_t data;
+    if (!try_get_word_ptrace(tid, address, &data)) {
+      break;
+    }
+    address += sizeof(uint32_t);
+
+    if ((*p++ = (data >>  0) & 0xff) == 0) {
+      break;
+    }
+    if ((*p++ = (data >>  8) & 0xff) == 0) {
+      break;
+    }
+    if ((*p++ = (data >> 16) & 0xff) == 0) {
+      break;
+    }
+    if ((*p++ = (data >> 24) & 0xff) == 0) {
+      break;
+    }
+  }
+  msg[sizeof(msg) - 1] = '\0';
+
+  _LOG(log, SCOPE_AT_FAULT, "Abort message: '%s'\n", msg);
+}
+
 /*
  * Dumps all information about the specified pid to the tombstone.
  */
-static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal,
-        bool dump_sibling_threads, int* total_sleep_time_usec)
+static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
+                       bool dump_sibling_threads, int* total_sleep_time_usec)
 {
     /* don't copy log messages to tombstone unless this is a dev device */
     char value[PROPERTY_VALUE_MAX];
@@ -645,14 +681,15 @@
         TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
     }
 
-    _LOG(log, false,
+    _LOG(log, SCOPE_AT_FAULT,
             "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
     dump_build_info(log);
     dump_revision_info(log);
     dump_thread_info(log, pid, tid, true);
-    if(signal) {
+    if (signal) {
         dump_fault_addr(log, tid, signal);
     }
+    dump_abort_message(log, tid, abort_msg_address);
 
     ptrace_context_t* context = load_ptrace_context(tid);
     dump_thread(context, log, tid, true, total_sleep_time_usec);
@@ -769,7 +806,7 @@
     return amfd;
 }
 
-char* engrave_tombstone(pid_t pid, pid_t tid, int signal,
+char* engrave_tombstone(pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
         bool dump_sibling_threads, bool quiet, bool* detach_failed,
         int* total_sleep_time_usec) {
     mkdir(TOMBSTONE_DIR, 0755);
@@ -791,7 +828,7 @@
     log.tfd = fd;
     log.amfd = activity_manager_connect();
     log.quiet = quiet;
-    *detach_failed = dump_crash(&log, pid, tid, signal, dump_sibling_threads,
+    *detach_failed = dump_crash(&log, pid, tid, signal, abort_msg_address, dump_sibling_threads,
             total_sleep_time_usec);
 
     close(log.amfd);
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index edcd7b1..d4a1a96 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -25,7 +25,7 @@
 
 /* Creates a tombstone file and writes the crash dump to it.
  * Returns the path of the tombstone, which must be freed using free(). */
-char* engrave_tombstone(pid_t pid, pid_t tid, int signal,
+char* engrave_tombstone(pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
         bool dump_sibling_threads, bool quiet, bool* detach_failed, int* total_sleep_time_usec);
 
 #endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/utility.c b/debuggerd/utility.c
index de9200a..9bf3c18 100644
--- a/debuggerd/utility.c
+++ b/debuggerd/utility.c
@@ -39,6 +39,7 @@
         int written = TEMP_FAILURE_RETRY( write(fd, buf + len - to_write, to_write) );
         if (written < 0) {
             /* hard failure */
+            LOG("AM write failure (%d / %s)\n", errno, strerror(errno));
             return -1;
         }
         to_write -= written;
@@ -46,20 +47,20 @@
     return len;
 }
 
-void _LOG(log_t* log, bool in_tombstone_only, const char *fmt, ...) {
+void _LOG(log_t* log, int scopeFlags, const char *fmt, ...) {
     char buf[512];
     bool want_tfd_write;
     bool want_log_write;
     bool want_amfd_write;
-    int len;
+    int len = 0;
 
     va_list ap;
     va_start(ap, fmt);
 
     // where is the information going to go?
-    want_tfd_write = log && log->tfd >= 0;      // write to the tombstone fd?
-    want_log_write = !in_tombstone_only && (!log || !log->quiet);
-    want_amfd_write = log && log->amfd >= 0;    // only used when want_log_write is true
+    want_tfd_write = log && log->tfd >= 0;
+    want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
+    want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0;
 
     // if we're going to need the literal string, generate it once here
     if (want_tfd_write || want_amfd_write) {
@@ -78,7 +79,6 @@
             int written = write_to_am(log->amfd, buf, len);
             if (written <= 0) {
                 // timeout or other failure on write; stop informing the activity manager
-                LOG("AM write failure, giving up\n");
                 log->amfd = -1;
             }
         }
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 8d31e5e..1f006ed 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -30,22 +30,32 @@
     bool quiet;
 } log_t;
 
-/* Log information onto the tombstone. */
-void _LOG(log_t* log, bool in_tombstone_only, const char *fmt, ...)
+/* Log information onto the tombstone.  scopeFlags is a bitmask of the flags defined
+ * here. */
+void _LOG(log_t* log, int scopeFlags, const char *fmt, ...)
         __attribute__ ((format(printf, 3, 4)));
 
-#define LOG(fmt...) _LOG(NULL, 0, fmt)
+/* The message pertains specifically to the faulting thread / process */
+#define SCOPE_AT_FAULT (1 << 0)
+/* The message contains sensitive information such as RAM contents */
+#define SCOPE_SENSITIVE  (1 << 1)
+
+#define IS_AT_FAULT(x)    (((x) & SCOPE_AT_FAULT) != 0)
+#define IS_SENSITIVE(x)    (((x) & SCOPE_SENSITIVE) != 0)
+
+/* Further helpful macros */
+#define LOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
 
 /* Set to 1 for normal debug traces */
 #if 0
-#define XLOG(fmt...) _LOG(NULL, 0, fmt)
+#define XLOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
 #else
 #define XLOG(fmt...) do {} while(0)
 #endif
 
 /* Set to 1 for chatty debug traces. Includes all resolved dynamic symbols */
 #if 0
-#define XLOG2(fmt...) _LOG(NULL, 0, fmt)
+#define XLOG2(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
 #else
 #define XLOG2(fmt...) do {} while(0)
 #endif
diff --git a/debuggerd/x86/machine.c b/debuggerd/x86/machine.c
index 01da5fe..af79092 100644
--- a/debuggerd/x86/machine.c
+++ b/debuggerd/x86/machine.c
@@ -38,21 +38,21 @@
 void dump_registers(const ptrace_context_t* context __attribute((unused)),
         log_t* log, pid_t tid, bool at_fault) {
     struct pt_regs_x86 r;
-    bool only_in_tombstone = !at_fault;
+    int scopeFlags = (at_fault ? SCOPE_AT_FAULT : 0);
 
     if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-        _LOG(log, only_in_tombstone, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
         return;
     }
     //if there is no stack, no print just like arm
     if(!r.ebp)
         return;
-    _LOG(log, only_in_tombstone, "    eax %08x  ebx %08x  ecx %08x  edx %08x\n",
+    _LOG(log, scopeFlags, "    eax %08x  ebx %08x  ecx %08x  edx %08x\n",
          r.eax, r.ebx, r.ecx, r.edx);
-    _LOG(log, only_in_tombstone, "    esi %08x  edi %08x\n",
+    _LOG(log, scopeFlags, "    esi %08x  edi %08x\n",
          r.esi, r.edi);
-    _LOG(log, only_in_tombstone, "    xcs %08x  xds %08x  xes %08x  xfs %08x  xss %08x\n",
+    _LOG(log, scopeFlags, "    xcs %08x  xds %08x  xes %08x  xfs %08x  xss %08x\n",
          r.xcs, r.xds, r.xes, r.xfs, r.xss);
-    _LOG(log, only_in_tombstone, "    eip %08x  ebp %08x  esp %08x  flags %08x\n",
+    _LOG(log, scopeFlags, "    eip %08x  ebp %08x  esp %08x  flags %08x\n",
          r.eip, r.ebp, r.esp, r.eflags);
 }
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index 5a8e796..4eda523 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -34,10 +34,10 @@
     DEBUGGER_ACTION_DUMP_BACKTRACE,
 } debugger_action_t;
 
-/* message sent over the socket */
 typedef struct {
     debugger_action_t action;
     pid_t tid;
+    uintptr_t abort_msg_address;
 } debugger_msg_t;
 
 /* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
diff --git a/init/keychords.c b/init/keychords.c
index aab0819..061d157 100644
--- a/init/keychords.c
+++ b/init/keychords.c
@@ -100,10 +100,7 @@
     int ret;
     __u16 id;
 
-    // only handle keychords if ro.debuggable is set or adb is enabled.
-    // the logic here is that bugreports should be enabled in userdebug or eng builds
-    // and on user builds for users that are developers.
-    debuggable = property_get("ro.debuggable");
+    // Only handle keychords if adb is enabled.
     adb_enabled = property_get("init.svc.adbd");
     ret = read(keychord_fd, &id, sizeof(id));
     if (ret != sizeof(id)) {
@@ -111,8 +108,7 @@
         return;
     }
 
-    if ((debuggable && !strcmp(debuggable, "1")) ||
-        (adb_enabled && !strcmp(adb_enabled, "running"))) {
+    if ((adb_enabled && !strcmp(adb_enabled, "running"))) {
         svc = service_find_by_keychord(id);
         if (svc) {
             INFO("starting service %s from keychord\n", svc->name);