Various crash diagnostic improvements.

Register dumps, restore backtraces on Mac OS where possible, Mac demangling,
more comments, logging when using an abort hook, and more selective use of
abort hooks.

Linux:

 *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
 Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR) fault addr 0xdeadd00d
 Registers:
     eax: 0x00000000    ebx: 0x5598eff4    ecx: 0x56300000    edx: 0x55992de0
     edi: 0x5597e478    esi: 0xfff1f3c8    ebp: 0xfff1f3e8    esp: 0xfff1f390
     eip: 0x558a82ff eflags: 0x00010246
      cs: 0x00000023     ds: 0x0000002b     es: 0x0000002b     fs: 0x00000007
      gs: 0x00000063     ss: 0x0000002b
 Backtrace:
 	#00 art::Backtrace::Dump(std::ostream&)+0x4c [0x559357ac] (libartd.so)
 	#01 ??+0x3b73b0 [0x559343b0] (libartd.so)
 	#02 [0x55573410] (???)
 	#03 art::LogMessage::~LogMessage()+0x3bd [0x557e2e6d] (libartd.so)
 	#04 ?? [0x8088941] (dex2oatd)
 	#05 ?? [0x80898f7] (dex2oatd)
 	#06 __libc_start_main+0xe6 [0x55b06bd6] (libc.so.6)
 	#07 ?? [0x8085b31] (dex2oatd)

Mac OS:

 *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
 Fatal signal 6 (SIGABRT), code 0 (?)
 Registers:
     eax: 0x00000000    ebx: 0xc008bce0    ecx: 0xc008bc5c    edx: 0x906559c6
     edi: 0xac0f52c0    esi: 0x00000006    ebp: 0xc008bc78    esp: 0xc008bc5c
     eip: 0x906559c6 eflags: 0x00000246
      cs: 0x0000000b     ds: 0x00000023     es: 0x00000023     fs: 0x0000001f
      gs: 0x0000000f     ss: 0x00000023
 Backtrace:
 	#00 art::Backtrace::Dump(std::ostream&) + 40 [0x001ce25a] (libartd.dylib)
 	#01 _ZN3artL22HandleUnexpectedSignalEiP9__siginfoPv + 1051 [0x001cdacb] (libartd.dylib)
 	#02 _sigtramp + 43 [0x90a4559b] (libsystem_c.dylib)
 	#03 0x0 + 4294967295 [0xffffffff] (???)
 	#04 abort + 167 [0x909e0bdd] (libsystem_c.dylib)
 	#05 art::Runtime::Abort() + 322 [0x00192312] (libartd.dylib)
 	#06 art::LogMessage::~LogMessage() + 413 [0x00135a6d] (libartd.dylib)
 	#07 art::dex2oat(int, char**) + 6183 [0x00091927] (dex2oatd)
 	#08 start + 53 [0x0008fb75] (dex2oatd)

Change-Id: I68d215f09723f236889242cfe8aa8819afea4a60
diff --git a/src/jdwp/jdwp_expand_buf.cc b/src/jdwp/jdwp_expand_buf.cc
index 96c2cfe..307167e 100644
--- a/src/jdwp/jdwp_expand_buf.cc
+++ b/src/jdwp/jdwp_expand_buf.cc
@@ -96,8 +96,7 @@
 
   uint8_t* newPtr = (uint8_t*) realloc(pBuf->storage, pBuf->maxLen);
   if (newPtr == NULL) {
-    LOG(ERROR) << "realloc(" << pBuf->maxLen << ") failed";
-    abort();
+    LOG(FATAL) << "realloc(" << pBuf->maxLen << ") failed";
   }
 
   pBuf->storage = newPtr;
diff --git a/src/runtime.cc b/src/runtime.cc
index 3f80260..8fe760e 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -161,11 +161,15 @@
 
   // Call the abort hook if we have one.
   if (Runtime::Current() != NULL && Runtime::Current()->abort_ != NULL) {
+    LOG(INTERNAL_FATAL) << "Calling abort hook...";
     Runtime::Current()->abort_();
     // notreached
+    LOG(INTERNAL_FATAL) << "Unexpectedly returned from abort hook!";
   }
 
-  // If we call abort(3) on a device, all threads in the process
+  // TODO: finish merging patches to fix abort(3) in bionic, then lose this!
+  // Bionic doesn't implement POSIX semantics for abort(3) in a multi-threaded
+  // process, so if we call abort(3) on a device, all threads in the process
   // receive SIGABRT.  debuggerd dumps the stack trace of the main
   // thread, whether or not that was the thread that failed.  By
   // stuffing a value into a bogus address, we cause a segmentation
@@ -301,7 +305,10 @@
 
   parsed->hook_vfprintf_ = vfprintf;
   parsed->hook_exit_ = exit;
-  parsed->hook_abort_ = abort;
+  parsed->hook_abort_ = NULL; // We don't call abort(3) by default; see Runtime::Abort.
+#if defined(__APPLE__)
+  parsed->hook_abort_ = abort; // On the Mac, abort(3) gives better results; see Runtime::InitPlatformSignalHandlers.
+#endif
 
 //  gLogVerbosity.class_linker = true; // TODO: don't check this in!
 //  gLogVerbosity.compiler = true; // TODO: don't check this in!
diff --git a/src/runtime_linux.cc b/src/runtime_linux.cc
index b7e7d01..75540b8 100644
--- a/src/runtime_linux.cc
+++ b/src/runtime_linux.cc
@@ -19,6 +19,7 @@
 #include <cxxabi.h>
 #include <execinfo.h>
 #include <signal.h>
+#include <string.h>
 
 #include "logging.h"
 #include "stringprintf.h"
@@ -39,50 +40,90 @@
     return result;
   }
 
-  return mangled_name + "()";
+  return mangled_name;
 }
 
-static void Backtrace() {
-  // Get the raw stack frames.
-  size_t MAX_STACK_FRAMES = 64;
-  void* frames[MAX_STACK_FRAMES];
-  size_t frame_count = backtrace(frames, MAX_STACK_FRAMES);
+struct Backtrace {
+  void Dump(std::ostream& os) {
+    // Get the raw stack frames.
+    size_t MAX_STACK_FRAMES = 128;
+    void* frames[MAX_STACK_FRAMES];
+    size_t frame_count = backtrace(frames, MAX_STACK_FRAMES);
+    if (frame_count == 0) {
+      os << "--- backtrace(3) returned no frames";
+      return;
+    }
 
-  // Turn them into something human-readable with symbols.
-  char** symbols = backtrace_symbols(frames, frame_count);
-  if (symbols == NULL) {
-    PLOG(ERROR) << "backtrace_symbols failed";
-    return;
-  }
+    // Turn them into something human-readable with symbols.
+    char** symbols = backtrace_symbols(frames, frame_count);
+    if (symbols == NULL) {
+      os << "--- backtrace_symbols(3) failed";
+      return;
+    }
 
-  // backtrace_symbols(3) gives us lines like this:
-  // "/usr/local/google/home/enh/a1/out/host/linux-x86/bin/../lib/libartd.so(_ZN3art7Runtime5AbortEPKci+0x15b) [0xf76c5af3]"
-  // "[0xf7b62057]"
 
-  // We extract the pieces and demangle, so we can produce output like this:
-  // libartd.so:-1]    #00 art::Runtime::Abort(char const*, int) +0x15b [0xf770dd51]
+    // Parse the backtrace strings and demangle, so we can produce output like this:
+    // ]    #00 art::Runtime::Abort(char const*, int)+0x15b [0xf770dd51] (libartd.so)
+    for (size_t i = 0; i < frame_count; ++i) {
+      std::string text(symbols[i]);
+      std::string filename("???");
+      std::string function_name;
 
-  for (size_t i = 0; i < frame_count; ++i) {
-    std::string text(symbols[i]);
-    std::string filename("??");
-    std::string function_name;
-
-    size_t index = text.find('(');
-    if (index != std::string::npos) {
+#if defined(__APPLE__)
+      // backtrace_symbols(3) gives us lines like this on Mac OS:
+      // "0   libartd.dylib                       0x001cd29a _ZN3art9Backtrace4DumpERSo + 40>"
+      // "3   ???                                 0xffffffff 0x0 + 4294967295>"
+      text.erase(0, 4);
+      size_t index = text.find(' ');
       filename = text.substr(0, index);
+      text.erase(0, 40 - 4);
+      index = text.find(' ');
+      std::string address(text.substr(0, index));
       text.erase(0, index + 1);
-
-      index = text.find_first_of("+)");
+      index = text.find(' ');
       function_name = Demangle(text.substr(0, index));
       text.erase(0, index);
-      index = text.find(')');
-      text.erase(index, 1);
-    }
-    std::string log_line(StringPrintf("\t#%02zd ", i) + function_name + text);
-    LogMessage(filename.c_str(), -1, INTERNAL_FATAL, -1).stream() << log_line;
-  }
+      text += " [" + address + "]";
+#else
+      // backtrace_symbols(3) gives us lines like this on Linux:
+      // "/usr/local/google/home/enh/a1/out/host/linux-x86/bin/../lib/libartd.so(_ZN3art7Runtime5AbortEPKci+0x15b) [0xf76c5af3]"
+      // "[0xf7b62057]"
+      size_t index = text.find('(');
+      if (index != std::string::npos) {
+        filename = text.substr(0, index);
+        text.erase(0, index + 1);
 
-  free(symbols);
+        index = text.find_first_of("+)");
+        function_name = Demangle(text.substr(0, index));
+        text.erase(0, index);
+        index = text.find(')');
+        text.erase(index, 1);
+      }
+#endif
+
+      const char* last_slash = strrchr(filename.c_str(), '/');
+      const char* so_name = (last_slash == NULL) ? filename.c_str() : last_slash + 1;
+      os << StringPrintf("\t#%02zd ", i) << function_name << text << " (" << so_name << ")\n";
+    }
+
+    free(symbols);
+  }
+};
+
+static const char* GetSignalName(int signal_number) {
+  switch (signal_number) {
+    case SIGABRT: return "SIGABRT";
+    case SIGBUS: return "SIGBUS";
+    case SIGFPE: return "SIGFPE";
+    case SIGILL: return "SIGILL";
+    case SIGPIPE: return "SIGPIPE";
+    case SIGSEGV: return "SIGSEGV";
+#if defined(STIGSTLFKT)
+    case SIGSTKFLT: return "SIGSTKFLT";
+#endif
+    case SIGTRAP: return "SIGTRAP";
+  }
+  return "??";
 }
 
 static const char* GetSignalCodeName(int signal_number, int signal_code) {
@@ -153,43 +194,84 @@
   return "?";
 }
 
-static void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void*) {
-  const char* signal_name = "?";
-  bool has_address = false;
-  if (signal_number == SIGILL) {
-    signal_name = "SIGILL";
-    has_address = true;
-  } else if (signal_number == SIGTRAP) {
-    signal_name = "SIGTRAP";
-  } else if (signal_number == SIGABRT) {
-    signal_name = "SIGABRT";
-  } else if (signal_number == SIGBUS) {
-    signal_name = "SIGBUS";
-    has_address = true;
-  } else if (signal_number == SIGFPE) {
-    signal_name = "SIGFPE";
-    has_address = true;
-  } else if (signal_number == SIGSEGV) {
-    signal_name = "SIGSEGV";
-    has_address = true;
-#if defined(SIGSTKFLT)
-  } else if (signal_number == SIGSTKFLT) {
-    signal_name = "SIGSTKFLT";
+struct UContext {
+  UContext(void* raw_context) : context(reinterpret_cast<ucontext_t*>(raw_context)->uc_mcontext) {}
+
+  void Dump(std::ostream& os) {
+    // TODO: support non-x86 hosts (not urgent because this code doesn't run on targets).
+#if defined(__APPLE__)
+    DumpRegister32(os, "eax", context->__ss.__eax);
+    DumpRegister32(os, "ebx", context->__ss.__ebx);
+    DumpRegister32(os, "ecx", context->__ss.__ecx);
+    DumpRegister32(os, "edx", context->__ss.__edx);
+    os << '\n';
+
+    DumpRegister32(os, "edi", context->__ss.__edi);
+    DumpRegister32(os, "esi", context->__ss.__esi);
+    DumpRegister32(os, "ebp", context->__ss.__ebp);
+    DumpRegister32(os, "esp", context->__ss.__esp);
+    os << '\n';
+
+    DumpRegister32(os, "eip", context->__ss.__eip);
+    DumpRegister32(os, "eflags", context->__ss.__eflags);
+    os << '\n';
+
+    DumpRegister32(os, "cs",  context->__ss.__cs);
+    DumpRegister32(os, "ds",  context->__ss.__ds);
+    DumpRegister32(os, "es",  context->__ss.__es);
+    DumpRegister32(os, "fs",  context->__ss.__fs);
+    os << '\n';
+    DumpRegister32(os, "gs",  context->__ss.__gs);
+    DumpRegister32(os, "ss",  context->__ss.__ss);
+#else
+    DumpRegister32(os, "eax", context.gregs[REG_EAX]);
+    DumpRegister32(os, "ebx", context.gregs[REG_EBX]);
+    DumpRegister32(os, "ecx", context.gregs[REG_ECX]);
+    DumpRegister32(os, "edx", context.gregs[REG_EDX]);
+    os << '\n';
+
+    DumpRegister32(os, "edi", context.gregs[REG_EDI]);
+    DumpRegister32(os, "esi", context.gregs[REG_ESI]);
+    DumpRegister32(os, "ebp", context.gregs[REG_EBP]);
+    DumpRegister32(os, "esp", context.gregs[REG_ESP]);
+    os << '\n';
+
+    DumpRegister32(os, "eip", context.gregs[REG_EIP]);
+    DumpRegister32(os, "eflags", context.gregs[REG_EFL]);
+    os << '\n';
+
+    DumpRegister32(os, "cs",  context.gregs[REG_CS]);
+    DumpRegister32(os, "ds",  context.gregs[REG_DS]);
+    DumpRegister32(os, "es",  context.gregs[REG_ES]);
+    DumpRegister32(os, "fs",  context.gregs[REG_FS]);
+    os << '\n';
+    DumpRegister32(os, "gs",  context.gregs[REG_GS]);
+    DumpRegister32(os, "ss",  context.gregs[REG_SS]);
 #endif
-  } else if (signal_number == SIGPIPE) {
-    signal_name = "SIGPIPE";
   }
 
-  // Remove ourselves as signal handler for this signal, in case of recursion.
-  signal(signal_number, SIG_DFL);
+  void DumpRegister32(std::ostream& os, const char* name, uint32_t value) {
+    os << StringPrintf(" %6s: 0x%08x", name, value);
+  }
+
+  mcontext_t& context;
+};
+
+static void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_context) {
+  bool has_address = (signal_number == SIGILL || signal_number == SIGBUS ||
+                      signal_number == SIGFPE || signal_number == SIGSEGV);
+
+  UContext thread_context(raw_context);
+  Backtrace thread_backtrace;
 
   LOG(INTERNAL_FATAL) << "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"
                       << StringPrintf("Fatal signal %d (%s), code %d (%s)",
-                                      signal_number, signal_name,
+                                      signal_number, GetSignalName(signal_number),
                                       info->si_code,
                                       GetSignalCodeName(signal_number, info->si_code))
-                      << (has_address ? StringPrintf(" fault addr %p", info->si_addr) : "");
-  Backtrace();
+                      << (has_address ? StringPrintf(" fault addr %p", info->si_addr) : "") << "\n"
+                      << "Registers:\n" << Dumpable<UContext>(thread_context) << "\n"
+                      << "Backtrace:\n" << Dumpable<Backtrace>(thread_backtrace);
 
   // TODO: instead, get debuggerd running on the host, try to connect, and hang around on success.
   if (getenv("debug_db_uid") != NULL) {
@@ -209,7 +291,11 @@
   memset(&action, 0, sizeof(action));
   sigemptyset(&action.sa_mask);
   action.sa_sigaction = HandleUnexpectedSignal;
-  action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+  action.sa_flags = SA_RESTART;
+  // Use the three-argument sa_sigaction handler.
+  action.sa_flags |= SA_SIGINFO;
+  // Remove ourselves as signal handler for this signal, in case of recursion.
+  action.sa_flags |= SA_RESETHAND;
 
   int rc = 0;
   rc += sigaction(SIGILL, &action, NULL);
@@ -217,11 +303,18 @@
   rc += sigaction(SIGABRT, &action, NULL);
   rc += sigaction(SIGBUS, &action, NULL);
   rc += sigaction(SIGFPE, &action, NULL);
-  rc += sigaction(SIGSEGV, &action, NULL);
 #if defined(SIGSTKFLT)
   rc += sigaction(SIGSTKFLT, &action, NULL);
 #endif
   rc += sigaction(SIGPIPE, &action, NULL);
+
+  // Use the alternate signal stack so we can catch stack overflows.
+  // On Mac OS 10.7, backtrace(3) is broken and will return no frames when called from the alternate stack,
+  // so we only use the alternate stack for SIGSEGV so that we at least get backtraces for other signals.
+  // (glibc does the right thing, so we could use the alternate stack for all signals there.)
+  action.sa_flags |= SA_ONSTACK;
+  rc += sigaction(SIGSEGV, &action, NULL);
+
   CHECK_EQ(rc, 0);
 }