Demangle C++ names in backtraces.

Change-Id: Id4ccefc1e0cbed357b09b84ef6f51b287493e6fd
diff --git a/src/runtime_linux.cc b/src/runtime_linux.cc
index e4bc035..9b9cc07 100644
--- a/src/runtime_linux.cc
+++ b/src/runtime_linux.cc
@@ -2,6 +2,7 @@
 
 #include "runtime.h"
 
+#include <cxxabi.h>
 #include <execinfo.h>
 
 #include "logging.h"
@@ -10,6 +11,21 @@
 
 namespace art {
 
+std::string Demangle(const std::string& mangled_name) {
+  if (mangled_name.empty()) {
+    return "??";
+  }
+
+  // http://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html
+  int status;
+  scoped_ptr_malloc<char> result(abi::__cxa_demangle(mangled_name.c_str(), NULL, NULL, &status));
+  if (result != NULL) {
+    return result.get();
+  }
+
+  return mangled_name + "()";
+}
+
 void Runtime::PlatformAbort(const char* file, int line) {
   // On the host, we don't have debuggerd to dump a stack for us.
 
@@ -19,17 +35,33 @@
   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.
   scoped_ptr_malloc<char*> symbols(backtrace_symbols(frames, frame_count));
   if (symbols == NULL) {
     PLOG(ERROR) << "backtrace_symbols failed";
     return;
   }
 
+  // backtrace_symbols(3) gives us lines like this:
+  // "/usr/local/google/home/enh/a1/out/host/linux-x86/bin/../lib/libartd.so(_ZN3art7Runtime13PlatformAbortEPKci+0x15b) [0xf76c5af3]"
+
+  // We extract the pieces and demangle, so we can produce output like this:
+  // libartd.so:-1] 	#00 art::Runtime::PlatformAbort(char const*, int) +0x15b [0xf770dd51]
+
   for (size_t i = 0; i < frame_count; ++i) {
-    LogMessage(file, line, ERROR, -1).stream()
-        << StringPrintf("\t#%02d %s", i, symbols.get()[i]);
+    std::string text(symbols.get()[i]);
+
+    size_t index = text.find('(');
+    std::string filename(text.substr(0, index));
+    text.erase(0, index + 1);
+
+    index = text.find_first_of("+)");
+    std::string function_name(Demangle(text.substr(0, index)));
+    text.erase(0, index);
+    index = text.find(')');
+    text.erase(index, 1);
+
+    std::string log_line(StringPrintf("\t#%02d ", i) + function_name + text);
+    LogMessage(filename.c_str(), -1, ERROR, -1).stream() << log_line;
   }
 }