Automatically dump stack traces in dvmAbort on the host.

Before:

    E(25569) VM aborting  (dalvikvm)

After:

    E( 9806) VM aborting  (dalvikvm)
    W( 9806) Obtained 7 stack frames.  (dalvikvm)
    W( 9806) #0  /usr/local/google/home/enh/dd4/out/host/linux-x86/bin/../lib/libdvm.so(dvmPrintNativeBackTrace+0x3f) [0xf7678f2f]  (dalvikvm)
    W( 9806) #1  /usr/local/google/home/enh/dd4/out/host/linux-x86/bin/../lib/libdvm.so(dvmAbort+0x52) [0xf7679072]  (dalvikvm)
    W( 9806) #2  /usr/local/google/home/enh/dd4/out/host/linux-x86/bin/../lib/libdvm.so(dvmStartup+0x67f) [0xf767a45f]  (dalvikvm)
    W( 9806) #3  /usr/local/google/home/enh/dd4/out/host/linux-x86/bin/../lib/libdvm.so(JNI_CreateJavaVM+0x1ee) [0xf768152e]  (dalvikvm)
    W( 9806) #4  /usr/local/google/home/enh/dd4/out/host/linux-x86/bin/dalvikvm() [0x8048ae3]  (dalvikvm)
    W( 9806) #5  /lib32/libc.so.6(__libc_start_main+0xe6) [0xf6ed5bd6]  (dalvikvm)
    W( 9806) #6  /usr/local/google/home/enh/dd4/out/host/linux-x86/bin/dalvikvm() [0x8048761]  (dalvikvm)

This makes continuous build crashes more directly useful, and saves having to
switch to the device/break out gdb when doing simple debugging.

Bug: 4176271
Change-Id: I49b40fd56e6aa89d1ddc7c7f299314761456fc28
diff --git a/vm/Init.c b/vm/Init.c
index be63dab..ae4e175 100644
--- a/vm/Init.c
+++ b/vm/Init.c
@@ -1709,6 +1709,41 @@
     return result;
 }
 
+#ifdef __GLIBC__
+#include <execinfo.h>
+/*
+ * glibc-only stack dump function.  Requires link with "--export-dynamic".
+ *
+ * TODO: move this into libs/cutils and make it work for all platforms.
+ */
+void dvmPrintNativeBackTrace(void)
+{
+    size_t MAX_STACK_FRAMES = 64;
+    void* stackFrames[MAX_STACK_FRAMES];
+    size_t frameCount = backtrace(stackFrames, MAX_STACK_FRAMES);
+
+    /*
+     * TODO: in practice, we may find that we should use backtrace_symbols_fd
+     * to avoid allocation, rather than use our own custom formatting.
+     */
+    char** strings = backtrace_symbols(stackFrames, frameCount);
+    if (strings == NULL) {
+        LOGE("backtrace_symbols failed: %s", strerror(errno));
+        return;
+    }
+
+    size_t i;
+    for (i = 0; i < frameCount; ++i) {
+        LOGW("#%d  %s", i, strings[i]);
+    }
+    free(strings);
+}
+#else
+void dvmPrintNativeBackTrace(void) {
+    /* Hopefully, you're on an Android device and debuggerd will do this. */
+}
+#endif
+
 /*
  * Abort the VM.  We get here on fatal errors.  Try very hard not to use
  * this; whenever possible, return an error to somebody responsible.
@@ -1724,6 +1759,12 @@
         (*gDvm.abortHook)();
 
     /*
+     * On the device, debuggerd will give us a stack trace.
+     * On the host, we have to help ourselves.
+     */
+    dvmPrintNativeBackTrace();
+
+    /*
      * If we call abort(), all threads in the process receives a SIBABRT.
      * debuggerd dumps the stack trace of the main thread, whether or not
      * that was the thread that failed.
diff --git a/vm/Misc.h b/vm/Misc.h
index 4dc983e..c1c3d47 100644
--- a/vm/Misc.h
+++ b/vm/Misc.h
@@ -256,6 +256,7 @@
  * it undecorated.
  */
 void dvmAbort(void);
+void dvmPrintNativeBackTrace(void);
 
 #if (!HAVE_STRLCPY)
 /* Implementation of strlcpy() for platforms that don't already have it. */
diff --git a/vm/Thread.c b/vm/Thread.c
index b347834..a003481 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -2346,36 +2346,6 @@
     unlockThreadSuspendCount();
 }
 
-
-#ifdef HAVE_GLIBC
-# define NUM_FRAMES  20
-# include <execinfo.h>
-/*
- * glibc-only stack dump function.  Requires link with "--export-dynamic".
- *
- * TODO: move this into libs/cutils and make it work for all platforms.
- */
-static void printBackTrace(void)
-{
-    void* array[NUM_FRAMES];
-    size_t size;
-    char** strings;
-    size_t i;
-
-    size = backtrace(array, NUM_FRAMES);
-    strings = backtrace_symbols(array, size);
-
-    LOGW("Obtained %zd stack frames.\n", size);
-
-    for (i = 0; i < size; i++)
-        LOGW("%s\n", strings[i]);
-
-    free(strings);
-}
-#else
-static void printBackTrace(void) {}
-#endif
-
 /*
  * Dump the state of the current thread and that of another thread that
  * we think is wedged.
@@ -2383,7 +2353,7 @@
 static void dumpWedgedThread(Thread* thread)
 {
     dvmDumpThread(dvmThreadSelf(), false);
-    printBackTrace();
+    dvmPrintNativeBackTrace();
 
     // dumping a running thread is risky, but could be useful
     dvmDumpThread(thread, true);