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