Implement Runtime::Abort and switch LOG(FATAL) over to it.

Runtime::Abort takes arguments so it can provide less misleading log output,
but this shouldn't matter to callers because they should be using LOG(FATAL)
anyway.

This patch also fixes an errno/errno_ mixup in the logging code.

Change-Id: If24b66b7bbf0bf7c0ecb93dd806d82b1d21ee239
diff --git a/build/Android.common.mk b/build/Android.common.mk
index ac9553e..a351dc7 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -56,12 +56,14 @@
 LIBART_TARGET_SRC_FILES := \
 	$(LIBART_COMMON_SRC_FILES) \
 	src/assembler_arm.cc \
-	src/logging_android.cc
+	src/logging_android.cc \
+	src/runtime_android.cc
 
 LIBART_HOST_SRC_FILES := \
 	$(LIBART_COMMON_SRC_FILES) \
 	src/assembler_x86.cc \
-	src/logging_linux.cc
+	src/logging_linux.cc \
+	src/runtime_linux.cc
 
 TEST_COMMON_SRC_FILES := \
 	src/class_linker_test.cc \
diff --git a/src/logging.h b/src/logging.h
index 24ffdbc..98eb953 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -109,6 +109,8 @@
 
  private:
   std::stringstream buffer_;
+  const char* file_;
+  int line_;
   LogSeverity severity_;
   int errno_;
 
diff --git a/src/logging_android.cc b/src/logging_android.cc
index 9d97dbb..56e2dae 100644
--- a/src/logging_android.cc
+++ b/src/logging_android.cc
@@ -7,24 +7,25 @@
 #include <unistd.h>
 
 #include "cutils/log.h"
+#include "runtime.h"
 
 static const int kLogSeverityToAndroidLogPriority[] = {
   ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
 };
 
 LogMessage::LogMessage(const char* file, int line, LogSeverity severity, int error)
-: severity_(severity), errno_(error)
+: file_(file), line_(line), severity_(severity), errno_(error)
 {
 }
 
 LogMessage::~LogMessage() {
   if (errno_ != -1) {
-    stream() << ": " << strerror(errno);
+    stream() << ": " << strerror(errno_);
   }
   int priority = kLogSeverityToAndroidLogPriority[severity_];
   LOG_PRI(priority, LOG_TAG, "%s", buffer_.str().c_str());
   if (severity_ == FATAL) {
-    abort();  // TODO: dvmAbort
+    art::Runtime::Abort(file_, line_);
   }
 }
 
diff --git a/src/logging_linux.cc b/src/logging_linux.cc
index 9feceea..4be989d 100644
--- a/src/logging_linux.cc
+++ b/src/logging_linux.cc
@@ -3,12 +3,12 @@
 
 #include "logging.h"
 
+#include "runtime.h"
 #include "scoped_ptr.h"
 #include "stringprintf.h"
 
 #include <cstdio>
 #include <cstring>
-#include <execinfo.h>
 #include <iostream>
 #include <sys/types.h>
 #include <unistd.h>
@@ -23,44 +23,22 @@
 #endif
 #undef __KERNEL__
 
-static void dumpStackTrace(std::ostream& os) {
-  // Get the raw stack frames.
-  size_t MAX_STACK_FRAMES = 64;
-  void* stack_frames[MAX_STACK_FRAMES];
-  size_t frame_count = backtrace(stack_frames, MAX_STACK_FRAMES);
-
-  // Turn them into something human-readable with symbols.
-  // TODO: in practice, we may find that we should use backtrace_symbols_fd
-  // to avoid allocation, rather than use our own custom formatting.
-  art::scoped_ptr_malloc<char*> strings(backtrace_symbols(stack_frames, frame_count));
-  if (strings.get() == NULL) {
-    os << "backtrace_symbols failed: " << strerror(errno) << std::endl;
-    return;
-  }
-
-  for (size_t i = 0; i < frame_count; ++i) {
-    os << StringPrintf("\t#%02d %s", i, strings.get()[i]) << std::endl;
-  }
-}
-
 LogMessage::LogMessage(const char* file, int line, LogSeverity severity, int error)
-: severity_(severity), errno_(error)
+: line_(line), severity_(severity), errno_(error)
 {
   const char* last_slash = strrchr(file, '/');
-  const char* leaf = (last_slash == NULL) ? file : last_slash + 1;
+  file_ = (last_slash == NULL) ? file : last_slash + 1;
   stream() << StringPrintf("%c %5d %5d %s:%d] ",
-    "IWEF"[severity], getpid(), gettid(), leaf, line);
+      "IWEF"[severity], getpid(), gettid(), file_, line);
 }
 
 LogMessage::~LogMessage() {
   if (errno_ != -1) {
-    stream() << ": " << strerror(errno);
+    stream() << ": " << strerror(errno_);
   }
   stream() << std::endl;
   if (severity_ == FATAL) {
-    stream() << "Aborting:" << std::endl;
-    dumpStackTrace(stream());
-    abort();
+    art::Runtime::Abort(file_, line_);
   }
 }
 
diff --git a/src/runtime.cc b/src/runtime.cc
index e1ad32d..0f768c5 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -2,6 +2,9 @@
 
 #include "src/runtime.h"
 
+#include <cstdio>
+#include <cstdlib>
+
 #include "src/class_linker.h"
 #include "src/heap.h"
 #include "src/thread.h"
@@ -15,6 +18,33 @@
   delete thread_list_;
 }
 
+void Runtime::Abort(const char* file, int line) {
+  // Get any pending output out of the way.
+  fflush(NULL);
+
+  // Many people have difficulty distinguish aborts from crashes,
+  // so be explicit.
+  LogMessage(file, line, ERROR, -1).stream() << "Runtime aborting...";
+
+  // TODO: if we support an abort hook, call it here.
+
+  // Perform any platform-specific pre-abort actions.
+  PlatformAbort(file, line);
+
+  // If we call abort(3) on a device, all threads in the process
+  // receive SIBABRT.
+  // 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
+  // fault in the current thread, and get a useful log from debuggerd.
+  // We can also trivially tell the difference between a VM crash and
+  // a deliberate abort by looking at the fault address.
+  *reinterpret_cast<char*>(0xdeadd00d) = 38;
+  abort();
+
+  // notreached
+}
+
 Runtime* Runtime::Create() {
   scoped_ptr<Runtime> runtime(new Runtime());
   bool success = runtime->Init();
diff --git a/src/runtime.h b/src/runtime.h
index 76f7676..9245f19 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -21,6 +21,13 @@
   // Compiles a dex file.
   static void Compile(const StringPiece& filename);
 
+  // Aborts semi-cleanly. Used in the implementation of LOG(FATAL), which most
+  // callers should prefer.
+  // This isn't marked ((noreturn)) because then gcc will merge multiple calls
+  // in a single function together. This reduces code size slightly, but means
+  // that the native stack trace we get may point at the wrong call site.
+  static void Abort(const char* file, int line);
+
   // Attaches the current native thread to the runtime.
   bool AttachCurrentThread();
 
@@ -30,6 +37,8 @@
   ~Runtime();
 
  private:
+  static void PlatformAbort(const char*, int);
+
   Runtime() : class_linker_(NULL), heap_(NULL), thread_list_(NULL) {}
 
   // Initializes a new uninitialized runtime.
diff --git a/src/runtime_android.cc b/src/runtime_android.cc
new file mode 100644
index 0000000..958d6e5
--- /dev/null
+++ b/src/runtime_android.cc
@@ -0,0 +1,12 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+// Author: enh@google.com (Elliott Hughes)
+
+#include "runtime.h"
+
+namespace art {
+
+void Runtime::PlatformAbort(const char*, int) {
+  // On a device, debuggerd will give us a stack trace. Nothing to do here.
+}
+
+}  // namespace art
diff --git a/src/runtime_linux.cc b/src/runtime_linux.cc
new file mode 100644
index 0000000..e59111f
--- /dev/null
+++ b/src/runtime_linux.cc
@@ -0,0 +1,37 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+// Author: enh@google.com (Elliott Hughes)
+
+#include "runtime.h"
+
+#include <execinfo.h>
+
+#include "logging.h"
+#include "scoped_ptr.h"
+#include "stringprintf.h"
+
+namespace art {
+
+void Runtime::PlatformAbort(const char* file, int line) {
+  // On the host, we don't have debuggerd to dump a stack for us.
+
+  // 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);
+
+  // Turn them into something human-readable with symbols.
+  // TODO: in practice, we may find that we should use backtrace_symbols_fd
+  // to avoid allocation, rather than use our own custom formatting.
+  art::scoped_ptr_malloc<char*> symbols(backtrace_symbols(frames, frame_count));
+  if (symbols.get() == NULL) {
+    PLOG(ERROR) << "backtrace_symbols failed";
+    return;
+  }
+
+  for (size_t i = 0; i < frame_count; ++i) {
+    LogMessage(file, line, ERROR, -1).stream()
+        << StringPrintf("\t#%02d %s", i, symbols.get()[i]);
+  }
+}
+
+}  // namespace art