Merge "Rewrite libbacktrace using C++."
diff --git a/debuggerd/backtrace.c b/debuggerd/backtrace.c
index 6f82792..aa7a3c2 100644
--- a/debuggerd/backtrace.c
+++ b/debuggerd/backtrace.c
@@ -89,12 +89,12 @@
 
     wait_for_stop(tid, total_sleep_time_usec);
 
-    backtrace_t backtrace;
-    if (!backtrace_get_data(&backtrace, tid)) {
+    backtrace_context_t context;
+    if (!backtrace_create_context(&context, tid, -1, 0)) {
         _LOG(log, SCOPE_AT_FAULT, "Could not create backtrace context.\n");
     } else {
-        dump_backtrace_to_log(&backtrace, log, SCOPE_AT_FAULT, "  ");
-        backtrace_free_data(&backtrace);
+        dump_backtrace_to_log(&context, log, SCOPE_AT_FAULT, "  ");
+        backtrace_destroy_context(&context);
     }
 
     if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
@@ -137,11 +137,11 @@
     dump_process_footer(&log, pid);
 }
 
-void dump_backtrace_to_log(const backtrace_t* backtrace, log_t* log,
+void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log,
                            int scope_flags, const char* prefix) {
     char buf[512];
-    for (size_t i = 0; i < backtrace->num_frames; i++) {
-        backtrace_format_frame_data(&backtrace->frames[i], i, buf, sizeof(buf));
+    for (size_t i = 0; i < context->backtrace->num_frames; i++) {
+        backtrace_format_frame_data(context, i, buf, sizeof(buf));
         _LOG(log, scope_flags, "%s%s\n", prefix, buf);
     }
 }
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index 9d61e6f..54a60b2 100644
--- a/debuggerd/backtrace.h
+++ b/debuggerd/backtrace.h
@@ -31,7 +31,7 @@
         int* total_sleep_time_usec);
 
 /* Dumps the backtrace in the backtrace data structure to the log. */
-void dump_backtrace_to_log(const backtrace_t* backtrace, log_t* log,
+void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log,
         int scope_flags, const char* prefix);
 
 #endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/tombstone.c b/debuggerd/tombstone.c
index 24debf4..48d7aa9 100644
--- a/debuggerd/tombstone.c
+++ b/debuggerd/tombstone.c
@@ -228,39 +228,39 @@
     }
 }
 
-static void dump_stack_segment(const backtrace_t* backtrace, log_t* log,
+static void dump_stack_segment(const backtrace_context_t* context, log_t* log,
         int scope_flags, uintptr_t *sp, size_t words, int label) {
     for (size_t i = 0; i < words; i++) {
         uint32_t stack_content;
-        if (!backtrace_read_word(backtrace, *sp, &stack_content)) {
+        if (!backtrace_read_word(context, *sp, &stack_content)) {
             break;
         }
 
-        const char* map_name = backtrace_get_map_info(backtrace, stack_content, NULL);
+        const char* map_name = backtrace_get_map_name(context, stack_content, NULL);
         if (!map_name) {
             map_name = "";
         }
         uintptr_t offset = 0;
-        char* proc_name = backtrace_get_proc_name(backtrace, stack_content, &offset);
-        if (proc_name) {
+        char* func_name = backtrace_get_func_name(context, stack_content, &offset);
+        if (func_name) {
             if (!i && label >= 0) {
                 if (offset) {
                     _LOG(log, scope_flags, "    #%02d  %08x  %08x  %s (%s+%u)\n",
-                            label, *sp, stack_content, map_name, proc_name, offset);
+                            label, *sp, stack_content, map_name, func_name, offset);
                 } else {
                     _LOG(log, scope_flags, "    #%02d  %08x  %08x  %s (%s)\n",
-                            label, *sp, stack_content, map_name, proc_name);
+                            label, *sp, stack_content, map_name, func_name);
                 }
             } else {
                 if (offset) {
                     _LOG(log, scope_flags, "         %08x  %08x  %s (%s+%u)\n",
-                            *sp, stack_content, map_name, proc_name, offset);
+                            *sp, stack_content, map_name, func_name, offset);
                 } else {
                     _LOG(log, scope_flags, "         %08x  %08x  %s (%s)\n",
-                            *sp, stack_content, map_name, proc_name);
+                            *sp, stack_content, map_name, func_name);
                 }
             }
-            free(proc_name);
+            free(func_name);
         } else {
             if (!i && label >= 0) {
                 _LOG(log, scope_flags, "    #%02d  %08x  %08x  %s\n",
@@ -275,7 +275,8 @@
     }
 }
 
-static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags) {
+static void dump_stack(const backtrace_context_t* context, log_t* log, int scope_flags) {
+    const backtrace_t* backtrace = context->backtrace;
     size_t first = 0, last;
     for (size_t i = 0; i < backtrace->num_frames; i++) {
         if (backtrace->frames[i].sp) {
@@ -294,7 +295,7 @@
 
     // Dump a few words before the first frame.
     uintptr_t sp = backtrace->frames[first].sp - STACK_WORDS * sizeof(uint32_t);
-    dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1);
+    dump_stack_segment(context, log, scope_flags, &sp, STACK_WORDS, -1);
 
     // Dump a few words from all successive frames.
     // Only log the first 3 frames, put the rest in the tombstone.
@@ -308,7 +309,7 @@
             scope_flags &= (~SCOPE_AT_FAULT);
         }
         if (i == last) {
-            dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, i);
+            dump_stack_segment(context, log, scope_flags, &sp, STACK_WORDS, i);
             if (sp < frame->sp + frame->stack_size) {
                 _LOG(log, scope_flags, "         ........  ........\n");
             }
@@ -319,19 +320,19 @@
             } else if (words > STACK_WORDS) {
                 words = STACK_WORDS;
             }
-            dump_stack_segment(backtrace, log, scope_flags, &sp, words, i);
+            dump_stack_segment(context, log, scope_flags, &sp, words, i);
         }
     }
 }
 
-static void dump_backtrace_and_stack(const backtrace_t* backtrace, log_t* log,
-        int scope_flags) {
-    if (backtrace->num_frames) {
+static void dump_backtrace_and_stack(const backtrace_context_t* context,
+        log_t* log, int scope_flags) {
+    if (context->backtrace->num_frames) {
         _LOG(log, scope_flags, "\nbacktrace:\n");
-        dump_backtrace_to_log(backtrace, log, scope_flags, "    ");
+        dump_backtrace_to_log(context, log, scope_flags, "    ");
 
         _LOG(log, scope_flags, "\nstack:\n");
-        dump_stack(backtrace, log, scope_flags);
+        dump_stack(context, log, scope_flags);
     }
 }
 
@@ -399,12 +400,13 @@
     dump_map(log, prev, "map above", scope_flags);
 }
 
-static void dump_thread(const backtrace_t* backtrace, log_t* log, int scope_flags,
-        int* total_sleep_time_usec) {
+static void dump_thread(const backtrace_context_t* context, log_t* log,
+        int scope_flags, int* total_sleep_time_usec) {
+    const backtrace_t* backtrace = context->backtrace;
     wait_for_stop(backtrace->tid, total_sleep_time_usec);
 
     dump_registers(log, backtrace->tid, scope_flags);
-    dump_backtrace_and_stack(backtrace, log, scope_flags);
+    dump_backtrace_and_stack(context, log, scope_flags);
     if (IS_AT_FAULT(scope_flags)) {
         dump_memory_and_code(log, backtrace->tid, scope_flags);
         dump_nearby_maps(backtrace->map_info_list, log, backtrace->tid, scope_flags);
@@ -446,11 +448,11 @@
 
         _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
         dump_thread_info(log, pid, new_tid, 0);
-        backtrace_t new_backtrace;
-        if (backtrace_get_data(&new_backtrace, new_tid)) {
-            dump_thread(&new_backtrace, log, 0, total_sleep_time_usec);
+        backtrace_context_t new_context;
+        if (backtrace_create_context(&new_context, pid, new_tid, 0)) {
+            dump_thread(&new_context, log, 0, total_sleep_time_usec);
+            backtrace_destroy_context(&new_context);
         }
-        backtrace_free_data(&new_backtrace);
 
         if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
             LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
@@ -606,7 +608,7 @@
     dump_log_file(log, pid, "/dev/log/main", tailOnly);
 }
 
-static void dump_abort_message(const backtrace_t* backtrace, log_t* log, uintptr_t address) {
+static void dump_abort_message(const backtrace_context_t* context, log_t* log, uintptr_t address) {
   if (address == 0) {
     return;
   }
@@ -618,7 +620,7 @@
   char* p = &msg[0];
   while (p < &msg[sizeof(msg)]) {
     uint32_t data;
-    if (!backtrace_read_word(backtrace, address, &data)) {
+    if (!backtrace_read_word(context, address, &data)) {
       break;
     }
     address += sizeof(uint32_t);
@@ -673,11 +675,11 @@
         dump_fault_addr(log, tid, signal);
     }
 
-    backtrace_t backtrace;
-    if (backtrace_get_data(&backtrace, tid)) {
-        dump_abort_message(&backtrace, log, abort_msg_address);
-        dump_thread(&backtrace, log, SCOPE_AT_FAULT, total_sleep_time_usec);
-        backtrace_free_data(&backtrace);
+    backtrace_context_t context;
+    if (backtrace_create_context(&context, pid, tid, 0)) {
+        dump_abort_message(&context, log, abort_msg_address);
+        dump_thread(&context, log, SCOPE_AT_FAULT, total_sleep_time_usec);
+        backtrace_destroy_context(&context);
     }
 
     if (want_logs) {
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
new file mode 100644
index 0000000..0b75e83
--- /dev/null
+++ b/include/backtrace/Backtrace.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BACKTRACE_BACKTRACE_H
+#define _BACKTRACE_BACKTRACE_H
+
+#include <backtrace/backtrace.h>
+
+#include <string>
+
+class BacktraceImpl;
+
+class Backtrace {
+public:
+  Backtrace(BacktraceImpl* impl);
+  virtual ~Backtrace();
+
+  // Get the current stack trace and store in the backtrace_ structure.
+  virtual bool Unwind(size_t num_ignore_frames);
+
+  // Get the function name and offset into the function given the pc.
+  // If the string is empty, then no valid function name was found.
+  virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset);
+
+  // Get the name of the map associated with the given pc. If NULL is returned,
+  // then map_start is not set. Otherwise, map_start is the beginning of this
+  // map.
+  virtual const char* GetMapName(uintptr_t pc, uintptr_t* map_start);
+
+  // Finds the memory map associated with the given ptr.
+  virtual const backtrace_map_info_t* FindMapInfo(uintptr_t ptr);
+
+  // Read the data at a specific address.
+  virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0;
+
+  // Create a string representing the formatted line of backtrace information
+  // for a single frame.
+  virtual std::string FormatFrameData(size_t frame_num);
+
+  pid_t Pid() { return backtrace_.pid; }
+  pid_t Tid() { return backtrace_.tid; }
+  size_t NumFrames() { return backtrace_.num_frames; }
+
+  const backtrace_t* GetBacktrace() { return &backtrace_; }
+
+  const backtrace_frame_data_t* GetFrame(size_t frame_num) {
+    return &backtrace_.frames[frame_num];
+  }
+
+  // Create the correct Backtrace object based on what is to be unwound.
+  // If pid < 0 or equals the current pid, then the Backtrace object
+  // corresponds to the current process.
+  // If pid < 0 or equals the current pid and tid >= 0, then the Backtrace
+  // object corresponds to a thread in the current process.
+  // If pid >= 0 and tid < 0, then the Backtrace object corresponds to a
+  // different process.
+  // Tracing a thread in a different process is not supported.
+  static Backtrace* Create(pid_t pid, pid_t tid);
+
+protected:
+  virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value);
+
+  BacktraceImpl* impl_;
+
+  backtrace_map_info_t* map_info_;
+
+  backtrace_t backtrace_;
+
+  friend class BacktraceImpl;
+};
+
+#endif // _BACKTRACE_BACKTRACE_H
diff --git a/include/backtrace/backtrace.h b/include/backtrace/backtrace.h
index b6bff38..b35a6d5 100644
--- a/include/backtrace/backtrace.h
+++ b/include/backtrace/backtrace.h
@@ -21,9 +21,7 @@
 #include <stdbool.h>
 #include <inttypes.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+__BEGIN_DECLS
 
 #define MAX_BACKTRACE_FRAMES 64
 
@@ -43,48 +41,58 @@
   size_t stack_size;      /* The size of the stack, zero indicate an unknown stack size. */
   const char* map_name;   /* The name of the map to which this pc belongs, NULL indicates the pc doesn't belong to a known map. */
   uintptr_t map_offset;   /* pc relative to the start of the map, only valid if map_name is not NULL. */
-  char* proc_name;        /* The function name associated with this pc, NULL if not found. */
-  uintptr_t proc_offset;  /* pc relative to the start of the procedure, only valid if proc_name is not NULL. */
+  char* func_name;        /* The function name associated with this pc, NULL if not found. */
+  uintptr_t func_offset;  /* pc relative to the start of the function, only valid if func_name is not NULL. */
 } backtrace_frame_data_t;
 
 typedef struct {
   backtrace_frame_data_t frames[MAX_BACKTRACE_FRAMES];
   size_t num_frames;
 
+  pid_t pid;
   pid_t tid;
   backtrace_map_info_t* map_info_list;
-  void* private_data;
 } backtrace_t;
 
-/* Gather the backtrace data for tid and fill in the backtrace structure.
- * If tid < 0, then gather the backtrace for the current thread.
- */
-bool backtrace_get_data(backtrace_t* backtrace, pid_t tid);
+typedef struct {
+  void* data;
+  const backtrace_t* backtrace;
+} backtrace_context_t;
 
-/* Free any memory associated with the backtrace structure. */
-void backtrace_free_data(backtrace_t* backtrace);
+/* Create a context for the backtrace data and gather the backtrace.
+ * If pid < 0, then gather the backtrace for the current process.
+ */
+bool backtrace_create_context(
+    backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames);
+
+/* Gather the backtrace data for a pthread instead of a process. */
+bool backtrace_create_thread_context(
+    backtrace_context_t* context, pid_t tid, size_t num_ignore_frames);
+
+/* Free any memory allocated during the context create. */
+void backtrace_destroy_context(backtrace_context_t* context);
 
 /* Read data at a specific address for a process. */
 bool backtrace_read_word(
-    const backtrace_t* backtrace, uintptr_t ptr, uint32_t* value);
+    const backtrace_context_t* context, uintptr_t ptr, uint32_t* value);
 
-/* Get information about the map associated with a pc. If NULL is
+/* Get information about the map name associated with a pc. If NULL is
  * returned, then map_start is not set.
  */
-const char* backtrace_get_map_info(
-    const backtrace_t* backtrace, uintptr_t pc, uintptr_t* map_start);
+const char* backtrace_get_map_name(
+    const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start);
 
-/* Get the procedure name and offest given the pc. If NULL is returned,
- * then proc_offset is not set. The returned string is allocated using
+/* Get the function name and offset given the pc. If NULL is returned,
+ * then func_offset is not set. The returned string is allocated using
  * malloc and must be freed by the caller.
  */
-char* backtrace_get_proc_name(
-    const backtrace_t* backtrace, uintptr_t pc, uintptr_t* proc_offset);
+char* backtrace_get_func_name(
+    const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset);
 
-/* Loads memory map from /proc/<tid>/maps. If tid < 0, then load the memory
+/* Loads memory map from /proc/<pid>/maps. If pid < 0, then load the memory
  * map for the current process.
  */
-backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid);
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid);
 
 /* Frees memory associated with the map list. */
 void backtrace_destroy_map_info_list(backtrace_map_info_t* map_info_list);
@@ -95,10 +103,12 @@
 
 /* Create a formatted line of backtrace information for a single frame. */
 void backtrace_format_frame_data(
-    const backtrace_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size);
+    const backtrace_context_t* context, size_t frame_num, char* buf,
+    size_t buf_size);
 
-#ifdef __cplusplus
-}
-#endif
+/* Get the backtrace data structure associated with the context. */
+const backtrace_t* backtrace_get_data(backtrace_context_t* context);
+
+__END_DECLS
 
 #endif /* _BACKTRACE_H */
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 4197bbb..66d7e62 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -1,67 +1,109 @@
 LOCAL_PATH:= $(call my-dir)
 
+common_src := \
+	Backtrace.cpp \
+	BacktraceThread.cpp \
+	map_info.c \
+	thread_utils.c \
+
+common_cflags := \
+	-Wall \
+	-Wno-unused-parameter \
+	-Werror \
+
+common_conlyflags := \
+	-std=gnu99 \
+
+common_cppflags := \
+	-std=gnu++11 \
+
+common_shared_libs := \
+	libcutils \
+	libgccdemangle \
+	liblog \
+
+# To enable using libunwind on each arch, add it to the list below.
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),))
+
 #----------------------------------------------------------------------------
-# The libbacktrace library using libunwind
+# The native libbacktrace library with libunwind.
 #----------------------------------------------------------------------------
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	unwind.c \
-	unwind_remote.c \
-	unwind_local.c \
-	common.c \
-	demangle.c \
-	map_info.c \
+	$(common_src) \
+	UnwindCurrent.cpp \
+	UnwindPtrace.cpp \
 
 LOCAL_CFLAGS := \
-	-Wall \
-	-Wno-unused-parameter \
-	-Werror \
-	-std=gnu99 \
+	$(common_cflags) \
+
+LOCAL_CONLYFLAGS += \
+	$(common_conlyflags) \
+
+LOCAL_CPPFLAGS += \
+	$(common_cppflags) \
 
 LOCAL_MODULE := libbacktrace
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libunwind \
-	libunwind-ptrace \
-	libgccdemangle \
-
 LOCAL_C_INCLUDES := \
+	$(common_c_includes) \
 	external/libunwind/include \
 
-# The libunwind code is not in the tree yet, so don't build this library yet.
-#include $(BUILD_SHARED_LIBRARY)
+LOCAL_SHARED_LIBRARIES := \
+	$(common_shared_libs) \
+	libunwind \
+	libunwind-ptrace \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
+include external/stlport/libstlport.mk
+
+include $(BUILD_SHARED_LIBRARY)
+
+else
 
 #----------------------------------------------------------------------------
-# The libbacktrace library using libcorkscrew
+# The native libbacktrace library with libcorkscrew.
 #----------------------------------------------------------------------------
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	corkscrew.c \
-	common.c \
-	demangle.c \
-	map_info.c \
+	$(common_src) \
+	Corkscrew.cpp \
 
 LOCAL_CFLAGS := \
-	-Wall \
-	-Wno-unused-parameter \
-	-Werror \
-	-std=gnu99 \
+	$(common_cflags) \
+
+LOCAL_CONLYFLAGS += \
+	$(common_conlyflags) \
+
+LOCAL_CPPFLAGS += \
+	$(common_cppflags) \
 
 LOCAL_MODULE := libbacktrace
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_C_INCLUDES := \
+	$(common_c_includes) \
+	system/core/libcorkscrew \
+
 LOCAL_SHARED_LIBRARIES := \
+	$(common_shared_libs) \
 	libcorkscrew \
 	libdl \
-	libgccdemangle \
-	liblog \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
+include external/stlport/libstlport.mk
 
 include $(BUILD_SHARED_LIBRARY)
 
+endif
+
 #----------------------------------------------------------------------------
 # libbacktrace test library, all optimizations turned off
 #----------------------------------------------------------------------------
@@ -77,6 +119,9 @@
 	-std=gnu99 \
 	-O0 \
 
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
 include $(BUILD_SHARED_LIBRARY)
 
 #----------------------------------------------------------------------------
@@ -88,16 +133,36 @@
 LOCAL_MODULE_FLAGS := debug
 
 LOCAL_SRC_FILES := \
-	backtrace_test.c \
+	backtrace_test.cpp \
+	thread_utils.c \
 
 LOCAL_CFLAGS += \
-	-std=gnu99 \
+	-fno-builtin \
+	-fstack-protector-all \
+	-O0 \
+	-g \
+	-DGTEST_OS_LINUX_ANDROID \
+	-DGTEST_HAS_STD_STRING \
 
-LOCAL_SHARED_LIBRARIES := \
+LOCAL_CONLYFLAGS += \
+	$(common_conlyflags) \
+
+LOCAL_CPPFLAGS += \
+	$(common_cppflags) \
+	-fpermissive \
+
+LOCAL_SHARED_LIBRARIES += \
+	libcutils \
 	libbacktrace_test \
 	libbacktrace \
 
-include $(BUILD_EXECUTABLE)
+LOCAL_LDLIBS := \
+	-lpthread \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
+include $(BUILD_NATIVE_TEST)
 
 #----------------------------------------------------------------------------
 # Only linux-x86 host versions of libbacktrace supported.
@@ -110,22 +175,26 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES += \
-	corkscrew.c \
-	common.c \
-	demangle.c \
-	map_info.c \
+	$(common_src) \
+	Corkscrew.cpp \
 
 LOCAL_CFLAGS += \
-	-Wall \
-	-Wno-unused-parameter \
-	-Werror \
-	-std=gnu99 \
+	$(common_cflags) \
+
+LOCAL_CONLYFLAGS += \
+	$(common_conlyflags) \
+
+LOCAL_CPPFLAGS += \
+	$(common_cppflags) \
+
+LOCAL_C_INCLUDES := \
+	$(common_c_includes) \
+	system/core/libcorkscrew \
 
 LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libcorkscrew \
 	libgccdemangle \
 	liblog \
+	libcorkscrew \
 
 LOCAL_LDLIBS += \
 	-ldl \
@@ -134,6 +203,9 @@
 LOCAL_MODULE := libbacktrace
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
 include $(BUILD_HOST_SHARED_LIBRARY)
 
 #----------------------------------------------------------------------------
@@ -151,6 +223,9 @@
 	-std=gnu99 \
 	-O0 \
 
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
 include $(BUILD_HOST_SHARED_LIBRARY)
 
 #----------------------------------------------------------------------------
@@ -162,15 +237,29 @@
 LOCAL_MODULE_FLAGS := debug
 
 LOCAL_SRC_FILES := \
-	backtrace_test.c \
+	backtrace_test.cpp \
+	thread_utils.c \
 
 LOCAL_CFLAGS += \
-	-std=gnu99 \
+	-fno-builtin \
+	-fstack-protector-all \
+	-O0 \
+	-g \
+	-DGTEST_HAS_STD_STRING \
 
 LOCAL_SHARED_LIBRARIES := \
 	libbacktrace_test \
 	libbacktrace \
 
-include $(BUILD_HOST_EXECUTABLE)
+LOCAL_CPPFLAGS += \
+	-fpermissive \
+
+LOCAL_LDLIBS := \
+	-lpthread \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
+include $(BUILD_HOST_NATIVE_TEST)
 
 endif # HOST_OS-HOST_ARCH == linux-x86
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
new file mode 100644
index 0000000..eca1c3d
--- /dev/null
+++ b/libbacktrace/Backtrace.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <string>
+
+#include <backtrace/Backtrace.h>
+#include <cutils/log.h>
+
+#include "Backtrace.h"
+#include "thread_utils.h"
+
+//-------------------------------------------------------------------------
+// BacktraceImpl functions.
+//-------------------------------------------------------------------------
+backtrace_t* BacktraceImpl::GetBacktraceData() {
+  return &backtrace_obj_->backtrace_;
+}
+
+//-------------------------------------------------------------------------
+// Backtrace functions.
+//-------------------------------------------------------------------------
+Backtrace::Backtrace(BacktraceImpl* impl) : impl_(impl), map_info_(NULL) {
+  impl_->SetParent(this);
+  backtrace_.num_frames = 0;
+  backtrace_.pid = -1;
+  backtrace_.tid = -1;
+}
+
+Backtrace::~Backtrace() {
+  for (size_t i = 0; i < NumFrames(); i++) {
+    if (backtrace_.frames[i].func_name) {
+      free(backtrace_.frames[i].func_name);
+      backtrace_.frames[i].func_name = NULL;
+    }
+  }
+
+  if (map_info_) {
+    backtrace_destroy_map_info_list(map_info_);
+    map_info_ = NULL;
+  }
+
+  if (impl_) {
+    delete impl_;
+    impl_ = NULL;
+  }
+}
+
+bool Backtrace::Unwind(size_t num_ignore_frames) {
+  return impl_->Unwind(num_ignore_frames);
+}
+
+__BEGIN_DECLS
+extern char* __cxa_demangle (const char* mangled, char* buf, size_t* len,
+                             int* status);
+__END_DECLS
+
+std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
+  std::string func_name = impl_->GetFunctionNameRaw(pc, offset);
+  if (!func_name.empty()) {
+#if defined(__APPLE__)
+    // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
+    if (symbol_name[0] != '_') {
+      return func_name;
+    }
+#endif
+    char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0);
+    if (name) {
+      func_name = name;
+      free(name);
+    }
+  }
+  return func_name;
+}
+
+bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) {
+  if (ptr & 3) {
+    ALOGW("Backtrace::verifyReadWordArgs: invalid pointer %p", (void*)ptr);
+    *out_value = (uint32_t)-1;
+    return false;
+  }
+  return true;
+}
+
+const char* Backtrace::GetMapName(uintptr_t pc, uintptr_t* map_start) {
+  const backtrace_map_info_t* map_info = FindMapInfo(pc);
+  if (map_info) {
+    if (map_start) {
+      *map_start = map_info->start;
+    }
+    return map_info->name;
+  }
+  return NULL;
+}
+
+const backtrace_map_info_t* Backtrace::FindMapInfo(uintptr_t ptr) {
+  return backtrace_find_map_info(map_info_, ptr);
+}
+
+std::string Backtrace::FormatFrameData(size_t frame_num) {
+  backtrace_frame_data_t* frame = &backtrace_.frames[frame_num];
+  const char* map_name;
+  if (frame->map_name) {
+    map_name = frame->map_name;
+  } else {
+    map_name = "<unknown>";
+  }
+  uintptr_t relative_pc;
+  if (frame->map_offset) {
+    relative_pc = frame->map_offset;
+  } else {
+    relative_pc = frame->pc;
+  }
+
+  char buf[512];
+  if (frame->func_name && frame->func_offset) {
+    snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR "  %s (%s+%" PRIuPTR ")",
+             frame_num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
+             frame->func_name, frame->func_offset);
+  } else if (frame->func_name) {
+    snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR "  %s (%s)", frame_num,
+             (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name);
+  } else {
+    snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR "  %s", frame_num,
+             (int)sizeof(uintptr_t)*2, relative_pc, map_name);
+  }
+
+  return buf;
+}
+
+//-------------------------------------------------------------------------
+// BacktraceCurrent functions.
+//-------------------------------------------------------------------------
+BacktraceCurrent::BacktraceCurrent(BacktraceImpl* impl) : Backtrace(impl) {
+  map_info_ = backtrace_create_map_info_list(-1);
+
+  backtrace_.pid = getpid();
+}
+
+BacktraceCurrent::~BacktraceCurrent() {
+}
+
+bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) {
+  if (!VerifyReadWordArgs(ptr, out_value)) {
+    return false;
+  }
+
+  const backtrace_map_info_t* map_info = FindMapInfo(ptr);
+  if (map_info && map_info->is_readable) {
+    *out_value = *reinterpret_cast<uint32_t*>(ptr);
+    return true;
+  } else {
+    ALOGW("BacktraceCurrent::readWord: pointer %p not in a readbale map", reinterpret_cast<void*>(ptr));
+    *out_value = static_cast<uint32_t>(-1);
+    return false;
+  }
+}
+
+//-------------------------------------------------------------------------
+// BacktracePtrace functions.
+//-------------------------------------------------------------------------
+BacktracePtrace::BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid)
+    : Backtrace(impl) {
+  map_info_ = backtrace_create_map_info_list(tid);
+
+  backtrace_.pid = pid;
+  backtrace_.tid = tid;
+}
+
+BacktracePtrace::~BacktracePtrace() {
+}
+
+bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) {
+  if (!VerifyReadWordArgs(ptr, out_value)) {
+    return false;
+  }
+
+#if defined(__APPLE__)
+  ALOGW("BacktracePtrace::readWord: MacOS does not support reading from another pid.\n");
+  return false;
+#else
+  // ptrace() returns -1 and sets errno when the operation fails.
+  // To disambiguate -1 from a valid result, we clear errno beforehand.
+  errno = 0;
+  *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
+  if (*out_value == static_cast<uint32_t>(-1) && errno) {
+    ALOGW("BacktracePtrace::readWord: invalid pointer 0x%08x reading from tid %d, "
+          "ptrace() errno=%d", ptr, Tid(), errno);
+    return false;
+  }
+  return true;
+#endif
+}
+
+Backtrace* Backtrace::Create(pid_t pid, pid_t tid) {
+  if (pid < 0 || pid == getpid()) {
+    if (tid < 0 || tid == gettid()) {
+      return CreateCurrentObj();
+    } else {
+      return CreateThreadObj(tid);
+    }
+  } else if (tid < 0) {
+    return CreatePtraceObj(pid, pid);
+  } else {
+    return CreatePtraceObj(pid, tid);
+  }
+}
+
+//-------------------------------------------------------------------------
+// Common interface functions.
+//-------------------------------------------------------------------------
+bool backtrace_create_context(
+    backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames) {
+  Backtrace* backtrace = Backtrace::Create(pid, tid);
+  if (!backtrace) {
+    return false;
+  }
+  if (!backtrace->Unwind(num_ignore_frames)) {
+    delete backtrace;
+    return false;
+  }
+
+  context->data = backtrace;
+  context->backtrace = backtrace->GetBacktrace();
+  return true;
+}
+
+void backtrace_destroy_context(backtrace_context_t* context) {
+  if (context->data) {
+    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+    delete backtrace;
+    context->data = NULL;
+  }
+  context->backtrace = NULL;
+}
+
+const backtrace_t* backtrace_get_data(backtrace_context_t* context) {
+  if (context && context->data) {
+    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+    return backtrace->GetBacktrace();
+  }
+  return NULL;
+}
+
+bool backtrace_read_word(const backtrace_context_t* context, uintptr_t ptr, uint32_t* value) {
+  if (context->data) {
+    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+    return backtrace->ReadWord(ptr, value);
+  }
+  return true;
+}
+
+const char* backtrace_get_map_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start) {
+  if (context->data) {
+    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+    return backtrace->GetMapName(pc, map_start);
+  }
+  return NULL;
+}
+
+char* backtrace_get_func_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset) {
+  if (context->data) {
+    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+    std::string func_name = backtrace->GetFunctionName(pc, func_offset);
+    if (!func_name.empty()) {
+      return strdup(func_name.c_str());
+    }
+  }
+  return NULL;
+}
+
+void backtrace_format_frame_data(
+    const backtrace_context_t* context, size_t frame_num, char* buf,
+    size_t buf_size) {
+  if (buf_size == 0 || buf == NULL) {
+    ALOGW("backtrace_format_frame_data: bad call buf %p buf_size %zu\n",
+          buf, buf_size);
+    return;
+  }
+  if (context->data) {
+    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+    std::string line = backtrace->FormatFrameData(frame_num);
+    if (line.size() > buf_size) {
+      memcpy(buf, line.c_str(), buf_size-1);
+      buf[buf_size] = '\0';
+    } else {
+      memcpy(buf, line.c_str(), line.size()+1);
+    }
+  }
+}
diff --git a/libbacktrace/Backtrace.h b/libbacktrace/Backtrace.h
new file mode 100644
index 0000000..b89bc89
--- /dev/null
+++ b/libbacktrace/Backtrace.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_BACKTRACE_H
+#define _LIBBACKTRACE_BACKTRACE_H
+
+#include <backtrace/Backtrace.h>
+
+#include <sys/types.h>
+
+class BacktraceImpl {
+public:
+  virtual ~BacktraceImpl() { }
+
+  virtual bool Unwind(size_t num_ignore_frames) = 0;
+
+  // The name returned is not demangled, Backtrace::GetFunctionName()
+  // takes care of demangling the name.
+  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0;
+
+  void SetParent(Backtrace* backtrace) { backtrace_obj_ = backtrace; }
+
+protected:
+  backtrace_t* GetBacktraceData();
+
+  Backtrace* backtrace_obj_;
+};
+
+class BacktraceCurrent : public Backtrace {
+public:
+  BacktraceCurrent(BacktraceImpl* impl);
+  virtual ~BacktraceCurrent();
+
+  bool ReadWord(uintptr_t ptr, uint32_t* out_value);
+};
+
+class BacktracePtrace : public Backtrace {
+public:
+  BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid);
+  virtual ~BacktracePtrace();
+
+  bool ReadWord(uintptr_t ptr, uint32_t* out_value);
+};
+
+Backtrace* CreateCurrentObj();
+Backtrace* CreatePtraceObj(pid_t pid, pid_t tid);
+Backtrace* CreateThreadObj(pid_t tid);
+
+#endif // _LIBBACKTRACE_BACKTRACE_H
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp
new file mode 100644
index 0000000..6c3641e
--- /dev/null
+++ b/libbacktrace/BacktraceThread.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <cutils/atomic.h>
+#include <cutils/log.h>
+
+#include "BacktraceThread.h"
+#include "thread_utils.h"
+
+//-------------------------------------------------------------------------
+// ThreadEntry implementation.
+//-------------------------------------------------------------------------
+static ThreadEntry* g_list = NULL;
+static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+ThreadEntry::ThreadEntry(
+    BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames)
+    : thread_intf_(intf), pid_(pid), tid_(tid), next_(NULL), prev_(NULL),
+      state_(STATE_WAITING), num_ignore_frames_(num_ignore_frames) {
+}
+
+ThreadEntry::~ThreadEntry() {
+  pthread_mutex_lock(&g_mutex);
+  if (g_list == this) {
+    g_list = next_;
+  } else {
+    if (next_) {
+      next_->prev_ = prev_;
+    }
+    prev_->next_ = next_;
+  }
+  pthread_mutex_unlock(&g_mutex);
+
+  next_ = NULL;
+  prev_ = NULL;
+}
+
+ThreadEntry* ThreadEntry::AddThreadToUnwind(
+    BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) {
+  ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames);
+
+  pthread_mutex_lock(&g_mutex);
+  ThreadEntry* cur_entry = g_list;
+  while (cur_entry != NULL) {
+    if (cur_entry->Match(pid, tid)) {
+      // There is already an entry for this pid/tid, this is bad.
+      ALOGW("%s::%s(): Entry for pid %d tid %d already exists.\n",
+            __FILE__, __FUNCTION__, pid, tid);
+
+      pthread_mutex_unlock(&g_mutex);
+      return NULL;
+    }
+    cur_entry = cur_entry->next_;
+  }
+
+  // Add the entry to the list.
+  entry->next_ = g_list;
+  if (g_list) {
+    g_list->prev_ = entry;
+  }
+  g_list = entry;
+  pthread_mutex_unlock(&g_mutex);
+
+  return entry;
+}
+
+//-------------------------------------------------------------------------
+// BacktraceThread functions.
+//-------------------------------------------------------------------------
+static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
+                          void* sigcontext) {
+  if (pthread_mutex_lock(&g_mutex) == 0) {
+    pid_t pid = getpid();
+    pid_t tid = gettid();
+    ThreadEntry* cur_entry = g_list;
+    while (cur_entry) {
+      if (cur_entry->Match(pid, tid)) {
+        break;
+      }
+      cur_entry = cur_entry->next_;
+    }
+    pthread_mutex_unlock(&g_mutex);
+    if (!cur_entry) {
+      ALOGW("%s::%s(): Unable to find pid %d tid %d information\n",
+            __FILE__, __FUNCTION__, pid, tid);
+      return;
+    }
+
+    if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state_) == 0) {
+      cur_entry->thread_intf_->ThreadUnwind(siginfo, sigcontext,
+                                            cur_entry->num_ignore_frames_);
+    }
+    android_atomic_release_store(STATE_DONE, &cur_entry->state_);
+  }
+}
+
+BacktraceThread::BacktraceThread(
+    BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid)
+    : BacktraceCurrent(impl), thread_intf_(thread_intf) {
+  backtrace_.tid = tid;
+}
+
+BacktraceThread::~BacktraceThread() {
+}
+
+void BacktraceThread::FinishUnwind() {
+  for (size_t i = 0; i < NumFrames(); i++) {
+    backtrace_frame_data_t* frame = &backtrace_.frames[i];
+
+    frame->map_offset = 0;
+    uintptr_t map_start;
+    frame->map_name = GetMapName(frame->pc, &map_start);
+    if (frame->map_name) {
+      frame->map_offset = frame->pc - map_start;
+    }
+
+    frame->func_offset = 0;
+    std::string func_name = GetFunctionName(frame->pc, &frame->func_offset);
+    if (!func_name.empty()) {
+      frame->func_name = strdup(func_name.c_str());
+    }
+  }
+}
+
+bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
+  entry->state_ = STATE_WAITING;
+
+  if (tgkill(Pid(), Tid(), SIGURG) != 0) {
+    ALOGW("%s::%s(): tgkill failed %s\n", __FILE__, __FUNCTION__, strerror(errno));
+    return false;
+  }
+
+  // Allow up to a second for the dump to occur.
+  int wait_millis = 1000;
+  int32_t state;
+  while (true) {
+    state = android_atomic_acquire_load(&entry->state_);
+    if (state != STATE_WAITING) {
+      break;
+    }
+    if (wait_millis--) {
+      usleep(1000);
+    } else {
+      break;
+    }
+  }
+
+  bool cancelled = false;
+  if (state == STATE_WAITING) {
+    if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state_) == 0) {
+      ALOGW("%s::%s(): Cancelled dump of thread %d\n", __FILE__, __FUNCTION__,
+            entry->tid_);
+      state = STATE_CANCEL;
+      cancelled = true;
+    } else {
+      state = android_atomic_acquire_load(&entry->state_);
+    }
+  }
+
+  // Wait for at most one minute for the dump to finish.
+  wait_millis = 60000;
+  while (android_atomic_acquire_load(&entry->state_) != STATE_DONE) {
+    if (wait_millis--) {
+      usleep(1000);
+    } else {
+      ALOGW("%s::%s(): Didn't finish thread unwind in 60 seconds.\n",
+            __FILE__, __FUNCTION__);
+      break;
+    }
+  }
+  return !cancelled;
+}
+
+bool BacktraceThread::Unwind(size_t num_ignore_frames) {
+  if (!thread_intf_->Init()) {
+    return false;
+  }
+
+  ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
+      thread_intf_, Pid(), Tid(), num_ignore_frames);
+  if (!entry) {
+    return false;
+  }
+
+  bool retval = false;
+  struct sigaction act, oldact;
+  memset(&act, 0, sizeof(act));
+  act.sa_sigaction = SignalHandler;
+  act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+  sigemptyset(&act.sa_mask);
+  if (sigaction(SIGURG, &act, &oldact) == 0) {
+    retval = TriggerUnwindOnThread(entry);
+    sigaction(SIGURG, &oldact, NULL);
+  } else {
+    ALOGW("%s::%s(): sigaction failed %s\n", __FILE__, __FUNCTION__, strerror(errno));
+  }
+
+  if (retval) {
+    FinishUnwind();
+  }
+  delete entry;
+
+  return retval;
+}
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h
new file mode 100644
index 0000000..afea771
--- /dev/null
+++ b/libbacktrace/BacktraceThread.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_BACKTRACE_THREAD_H
+#define _LIBBACKTRACE_BACKTRACE_THREAD_H
+
+#include <inttypes.h>
+#include <pthread.h>
+#include <sys/types.h>
+
+#include "Backtrace.h"
+
+typedef enum {
+  STATE_WAITING = 0,
+  STATE_DUMPING,
+  STATE_DONE,
+  STATE_CANCEL,
+} state_e;
+
+class BacktraceThreadInterface;
+
+class ThreadEntry {
+public:
+  ThreadEntry(
+      BacktraceThreadInterface* impl, pid_t pid, pid_t tid,
+      size_t num_ignore_frames);
+  ~ThreadEntry();
+
+  bool Match(pid_t pid, pid_t tid) { return (pid == pid_ && tid == tid_); }
+
+  static ThreadEntry* AddThreadToUnwind(
+      BacktraceThreadInterface* thread_intf, pid_t pid, pid_t tid,
+      size_t num_ignored_frames);
+
+  BacktraceThreadInterface* thread_intf_;
+  pid_t pid_;
+  pid_t tid_;
+  ThreadEntry* next_;
+  ThreadEntry* prev_;
+  int32_t state_;
+  int num_ignore_frames_;
+};
+
+// Interface class that does not contain any local storage, only defines
+// virtual functions to be defined by subclasses.
+class BacktraceThreadInterface {
+public:
+  virtual ~BacktraceThreadInterface() { }
+
+  virtual bool Init() = 0;
+
+  virtual void ThreadUnwind(
+      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) = 0;
+};
+
+class BacktraceThread : public BacktraceCurrent {
+public:
+  // impl and thread_intf should point to the same object, this allows
+  // the compiler to catch if an implementation does not properly
+  // subclass both.
+  BacktraceThread(
+      BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid);
+  virtual ~BacktraceThread();
+
+  virtual bool Unwind(size_t num_ignore_frames);
+
+  virtual void ThreadUnwind(
+      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
+    thread_intf_->ThreadUnwind(siginfo, sigcontext, num_ignore_frames);
+  }
+
+private:
+  virtual bool TriggerUnwindOnThread(ThreadEntry* entry);
+
+  virtual void FinishUnwind();
+
+  BacktraceThreadInterface* thread_intf_;
+};
+
+#endif // _LIBBACKTRACE_BACKTRACE_THREAD_H
diff --git a/libbacktrace/Corkscrew.cpp b/libbacktrace/Corkscrew.cpp
new file mode 100644
index 0000000..8ba1e80
--- /dev/null
+++ b/libbacktrace/Corkscrew.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libbacktrace"
+
+#include <backtrace/backtrace.h>
+
+#include <string.h>
+
+#include <backtrace-arch.h>
+#include <cutils/log.h>
+#include <corkscrew/backtrace.h>
+
+#ifndef __USE_GNU
+#define __USE_GNU
+#endif
+#include <dlfcn.h>
+
+#include "Corkscrew.h"
+
+//-------------------------------------------------------------------------
+// CorkscrewCommon functions.
+//-------------------------------------------------------------------------
+bool CorkscrewCommon::GenerateFrameData(
+    backtrace_frame_t* cork_frames, ssize_t num_frames) {
+  if (num_frames < 0) {
+    ALOGW("CorkscrewCommon::GenerateFrameData: libcorkscrew unwind failed.\n");
+    return false;
+  }
+
+  backtrace_t* data = GetBacktraceData();
+  data->num_frames = num_frames;
+  for (size_t i = 0; i < data->num_frames; i++) {
+    backtrace_frame_data_t* frame = &data->frames[i];
+    frame->pc = cork_frames[i].absolute_pc;
+    frame->sp = cork_frames[i].stack_top;
+    frame->stack_size = cork_frames[i].stack_size;
+    frame->map_name = NULL;
+    frame->map_offset = 0;
+    frame->func_name = NULL;
+    frame->func_offset = 0;
+
+    uintptr_t map_start;
+    frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
+    if (frame->map_name) {
+      frame->map_offset = frame->pc - map_start;
+    }
+
+    std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
+    if (!func_name.empty()) {
+      frame->func_name = strdup(func_name.c_str());
+    }
+  }
+  return true;
+}
+
+//-------------------------------------------------------------------------
+// CorkscrewCurrent functions.
+//-------------------------------------------------------------------------
+CorkscrewCurrent::CorkscrewCurrent() {
+}
+
+CorkscrewCurrent::~CorkscrewCurrent() {
+}
+
+bool CorkscrewCurrent::Unwind(size_t num_ignore_frames) {
+  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
+  ssize_t num_frames = unwind_backtrace(frames, num_ignore_frames, MAX_BACKTRACE_FRAMES);
+
+  return GenerateFrameData(frames, num_frames);
+}
+
+std::string CorkscrewCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  *offset = 0;
+
+  // Get information about the current thread.
+  Dl_info info;
+  const backtrace_map_info_t* map_info = backtrace_obj_->FindMapInfo(pc);
+  const char* symbol_name = NULL;
+  if (map_info && dladdr((const void*)pc, &info) && info.dli_sname) {
+    *offset = pc - map_info->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase;
+    symbol_name = info.dli_sname;
+
+    return symbol_name;
+  }
+  return "";
+}
+
+//-------------------------------------------------------------------------
+// CorkscrewThread functions.
+//-------------------------------------------------------------------------
+CorkscrewThread::CorkscrewThread() {
+}
+
+CorkscrewThread::~CorkscrewThread() {
+  if (corkscrew_map_info_) {
+    free_map_info_list(corkscrew_map_info_);
+    corkscrew_map_info_ = NULL;
+  }
+}
+
+bool CorkscrewThread::Init() {
+  corkscrew_map_info_ = load_map_info_list(backtrace_obj_->Pid());
+  return corkscrew_map_info_ != NULL;
+}
+
+void CorkscrewThread::ThreadUnwind(
+    siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
+  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
+  ssize_t num_frames = unwind_backtrace_signal_arch(
+      siginfo, sigcontext, corkscrew_map_info_, frames, num_ignore_frames,
+      MAX_BACKTRACE_FRAMES);
+  if (num_frames > 0) {
+    backtrace_t* data = GetBacktraceData();
+    data->num_frames = num_frames;
+    for (size_t i = 0; i < data->num_frames; i++) {
+      backtrace_frame_data_t* frame = &data->frames[i];
+      frame->pc = frames[i].absolute_pc;
+      frame->sp = frames[i].stack_top;
+      frame->stack_size = frames[i].stack_size;
+
+      frame->map_offset = 0;
+      frame->map_name = NULL;
+      frame->map_offset = 0;
+
+      frame->func_offset = 0;
+      frame->func_name = NULL;
+    }
+  }
+}
+
+//-------------------------------------------------------------------------
+// CorkscrewPtrace functions.
+//-------------------------------------------------------------------------
+CorkscrewPtrace::CorkscrewPtrace() : ptrace_context_(NULL) {
+}
+
+CorkscrewPtrace::~CorkscrewPtrace() {
+  if (ptrace_context_) {
+    free_ptrace_context(ptrace_context_);
+    ptrace_context_ = NULL;
+  }
+}
+
+bool CorkscrewPtrace::Unwind(size_t num_ignore_frames) {
+  ptrace_context_ = load_ptrace_context(backtrace_obj_->Tid());
+
+  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
+  ssize_t num_frames = unwind_backtrace_ptrace(
+      backtrace_obj_->Tid(), ptrace_context_, frames, num_ignore_frames,
+      MAX_BACKTRACE_FRAMES);
+
+  return GenerateFrameData(frames, num_frames);
+}
+
+std::string CorkscrewPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  // Get information about a different process.
+  const map_info_t* map_info;
+  const symbol_t* symbol;
+  find_symbol_ptrace(ptrace_context_, pc, &map_info, &symbol);
+  char* symbol_name = NULL;
+  if (symbol) {
+    if (map_info) {
+      *offset = pc - map_info->start - symbol->start;
+    }
+    symbol_name = symbol->name;
+    return symbol_name;
+  }
+
+  return "";
+}
+
+//-------------------------------------------------------------------------
+// C++ object createion functions.
+//-------------------------------------------------------------------------
+Backtrace* CreateCurrentObj() {
+  return new BacktraceCurrent(new CorkscrewCurrent());
+}
+
+Backtrace* CreatePtraceObj(pid_t pid, pid_t tid) {
+  return new BacktracePtrace(new CorkscrewPtrace(), pid, tid);
+}
+
+Backtrace* CreateThreadObj(pid_t tid) {
+  CorkscrewThread* thread_obj = new CorkscrewThread();
+  return new BacktraceThread(thread_obj, thread_obj, tid);
+}
diff --git a/libbacktrace/Corkscrew.h b/libbacktrace/Corkscrew.h
new file mode 100644
index 0000000..7cb125c
--- /dev/null
+++ b/libbacktrace/Corkscrew.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_CORKSCREW_H
+#define _LIBBACKTRACE_CORKSCREW_H
+
+#include <inttypes.h>
+
+#include <string>
+
+#include <backtrace/backtrace.h>
+#include <backtrace/Backtrace.h>
+
+#include <corkscrew/backtrace.h>
+
+#include "Backtrace.h"
+#include "BacktraceThread.h"
+
+class CorkscrewCommon : public BacktraceImpl {
+public:
+  bool GenerateFrameData(backtrace_frame_t* cork_frames, ssize_t num_frames);
+};
+
+class CorkscrewCurrent : public CorkscrewCommon {
+public:
+  CorkscrewCurrent();
+  virtual ~CorkscrewCurrent();
+
+  virtual bool Unwind(size_t num_ignore_threads);
+
+  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+};
+
+class CorkscrewThread : public CorkscrewCurrent, public BacktraceThreadInterface {
+public:
+  CorkscrewThread();
+  virtual ~CorkscrewThread();
+
+  virtual bool Init();
+
+  virtual void ThreadUnwind(
+      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
+
+private:
+  map_info_t* corkscrew_map_info_;
+};
+
+class CorkscrewPtrace : public CorkscrewCommon {
+public:
+  CorkscrewPtrace();
+  virtual ~CorkscrewPtrace();
+
+  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+  virtual bool Unwind(size_t num_ignore_threads);
+
+private:
+  ptrace_context_t* ptrace_context_;
+};
+
+#endif // _LIBBACKTRACE_CORKSCREW_H
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
new file mode 100644
index 0000000..0280e93
--- /dev/null
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libbacktrace"
+
+#include <sys/types.h>
+
+#include <cutils/log.h>
+
+#include <backtrace/backtrace.h>
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+
+#include "UnwindCurrent.h"
+
+#if defined(__arm__)
+  #if !defined(__BIONIC_HAVE_UCONTEXT_T)
+  // The Current version of the Android <signal.h> doesn't define ucontext_t.
+  #include <asm/sigcontext.h> // Ensure 'struct sigcontext' is defined.
+
+  // Machine context at the time a signal was raised.
+  typedef struct ucontext {
+    uint32_t uc_flags;
+    struct ucontext* uc_link;
+    stack_t uc_stack;
+    struct sigcontext uc_mcontext;
+    uint32_t uc_sigmask;
+  } ucontext_t;
+  #endif // !__BIONIC_HAVE_UCONTEXT_T
+#endif // defined(__arm__)
+
+//-------------------------------------------------------------------------
+// UnwindCurrent functions.
+//-------------------------------------------------------------------------
+UnwindCurrent::UnwindCurrent() {
+}
+
+UnwindCurrent::~UnwindCurrent() {
+}
+
+bool UnwindCurrent::Unwind(size_t num_ignore_frames) {
+  int ret = unw_getcontext(&context_);
+  if (ret < 0) {
+    ALOGW("UnwindCurrent::Unwind: unw_getcontext failed %d\n", ret);
+    return false;
+  }
+  return UnwindFromContext(num_ignore_frames, true);
+}
+
+std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  *offset = 0;
+  char buf[512];
+  unw_word_t value;
+  if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
+                              &value, &context_) >= 0 && buf[0] != '\0') {
+    *offset = static_cast<uintptr_t>(value);
+    return buf;
+  }
+  return "";
+}
+
+bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) {
+  backtrace_t* backtrace = GetBacktraceData();
+  backtrace->num_frames = 0;
+
+  // The cursor structure is pretty large, do not put it on the stack.
+  unw_cursor_t* cursor = new unw_cursor_t;
+  int ret = unw_init_local(cursor, &context_);
+  if (ret < 0) {
+    ALOGW("UnwindCurrent::UnwindWithContext: unw_init_local failed %d\n", ret);
+    return false;
+  }
+
+  do {
+    unw_word_t pc;
+    ret = unw_get_reg(cursor, UNW_REG_IP, &pc);
+    if (ret < 0) {
+      ALOGW("UnwindCurrent::UnwindWithContext: Failed to read IP %d\n", ret);
+      break;
+    }
+    unw_word_t sp;
+    ret = unw_get_reg(cursor, UNW_REG_SP, &sp);
+    if (ret < 0) {
+      ALOGW("UnwindCurrent::UnwindWithContext: Failed to read SP %d\n", ret);
+      break;
+    }
+
+    if (num_ignore_frames == 0) {
+      size_t num_frames = backtrace->num_frames;
+      backtrace_frame_data_t* frame = &backtrace->frames[num_frames];
+      frame->pc = static_cast<uintptr_t>(pc);
+      frame->sp = static_cast<uintptr_t>(sp);
+      frame->stack_size = 0;
+      frame->map_name = NULL;
+      frame->map_offset = 0;
+      frame->func_name = NULL;
+      frame->func_offset = 0;
+
+      if (num_frames > 0) {
+        // Set the stack size for the previous frame.
+        backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1];
+        prev->stack_size = frame->sp - prev->sp;
+      }
+
+      if (resolve) {
+        std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
+        if (!func_name.empty()) {
+          frame->func_name = strdup(func_name.c_str());
+        }
+
+        uintptr_t map_start;
+        frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
+        if (frame->map_name) {
+          frame->map_offset = frame->pc - map_start;
+        }
+      }
+
+      backtrace->num_frames++;
+    } else {
+      num_ignore_frames--;
+    }
+    ret = unw_step (cursor);
+  } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
+
+  delete cursor;
+  return true;
+}
+
+void UnwindCurrent::ExtractContext(void* sigcontext) {
+  unw_tdep_context_t* context = reinterpret_cast<unw_tdep_context_t*>(&context_);
+
+#if defined(__arm__)
+  const ucontext_t* uc = reinterpret_cast<const ucontext_t*>(sigcontext);
+
+  context->regs[0] = uc->uc_mcontext.arm_r0;
+  context->regs[1] = uc->uc_mcontext.arm_r1;
+  context->regs[2] = uc->uc_mcontext.arm_r2;
+  context->regs[3] = uc->uc_mcontext.arm_r3;
+  context->regs[4] = uc->uc_mcontext.arm_r4;
+  context->regs[5] = uc->uc_mcontext.arm_r5;
+  context->regs[6] = uc->uc_mcontext.arm_r6;
+  context->regs[7] = uc->uc_mcontext.arm_r7;
+  context->regs[8] = uc->uc_mcontext.arm_r8;
+  context->regs[9] = uc->uc_mcontext.arm_r9;
+  context->regs[10] = uc->uc_mcontext.arm_r10;
+  context->regs[11] = uc->uc_mcontext.arm_fp;
+  context->regs[12] = uc->uc_mcontext.arm_ip;
+  context->regs[13] = uc->uc_mcontext.arm_sp;
+  context->regs[14] = uc->uc_mcontext.arm_lr;
+  context->regs[15] = uc->uc_mcontext.arm_pc;
+
+#elif defined(__mips__)
+
+  typedef struct ucontext {
+    uint32_t sp;
+    uint32_t ra;
+    uint32_t pc;
+  } ucontext_t;
+
+  const ucontext_t* uc = (const ucontext_t*)sigcontext;
+
+  context->uc_mcontext.sp = uc->sp;
+  context->uc_mcontext.pc = uc->pc;
+  context->uc_mcontext.ra = uc->ra;
+#elif defined(__x86__)
+
+  #include <asm/sigcontext.h>
+  #include <asm/ucontext.h>
+  typedef struct ucontext ucontext_t;
+
+  const ucontext_t* uc = (const ucontext_t*)sigcontext;
+
+  context->uc_mcontext.gregs[REG_EBP] = uc->uc_mcontext.gregs[REG_EBP];
+  context->uc_mcontext.gregs[REG_ESP] = uc->uc_mcontext.gregs[REG_ESP];
+  context->uc_mcontext.gregs[REG_EIP] = uc->uc_mcontext.gregs[REG_EIP];
+#endif
+}
+
+//-------------------------------------------------------------------------
+// UnwindThread functions.
+//-------------------------------------------------------------------------
+UnwindThread::UnwindThread() {
+}
+
+UnwindThread::~UnwindThread() {
+}
+
+bool UnwindThread::Init() {
+  return true;
+}
+
+void UnwindThread::ThreadUnwind(
+    siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) {
+  ExtractContext(sigcontext);
+  UnwindFromContext(num_ignore_frames, false);
+}
+
+//-------------------------------------------------------------------------
+// C++ object creation function.
+//-------------------------------------------------------------------------
+Backtrace* CreateCurrentObj() {
+  return new BacktraceCurrent(new UnwindCurrent());
+}
+
+Backtrace* CreateThreadObj(pid_t tid) {
+  UnwindThread* thread_obj = new UnwindThread();
+  return new BacktraceThread(thread_obj, thread_obj, tid);
+}
diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h
new file mode 100644
index 0000000..7dc977d
--- /dev/null
+++ b/libbacktrace/UnwindCurrent.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_UNWIND_CURRENT_H
+#define _LIBBACKTRACE_UNWIND_CURRENT_H
+
+#include <string>
+
+#include "Backtrace.h"
+#include "BacktraceThread.h"
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+
+class UnwindCurrent : public BacktraceImpl {
+public:
+  UnwindCurrent();
+  virtual ~UnwindCurrent();
+
+  virtual bool Unwind(size_t num_ignore_frames);
+
+  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+  bool UnwindFromContext(size_t num_ignore_frames, bool resolve);
+
+  void ExtractContext(void* sigcontext);
+
+protected:
+  unw_context_t context_;
+};
+
+class UnwindThread : public UnwindCurrent, public BacktraceThreadInterface {
+public:
+  UnwindThread();
+  virtual ~UnwindThread();
+
+  virtual bool Init();
+
+  virtual void ThreadUnwind(
+      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
+};
+
+#endif // _LIBBACKTRACE_UNWIND_CURRENT_H
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
new file mode 100644
index 0000000..628caa0
--- /dev/null
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libbacktrace"
+
+#include <backtrace/backtrace.h>
+
+#include <sys/types.h>
+#include <string.h>
+
+#include <cutils/log.h>
+
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+
+#include "UnwindPtrace.h"
+
+UnwindPtrace::UnwindPtrace() : addr_space_(NULL), upt_info_(NULL) {
+}
+
+UnwindPtrace::~UnwindPtrace() {
+  if (upt_info_) {
+    _UPT_destroy(upt_info_);
+    upt_info_ = NULL;
+  }
+  if (addr_space_) {
+    unw_destroy_addr_space(addr_space_);
+    addr_space_ = NULL;
+  }
+}
+
+bool UnwindPtrace::Unwind(size_t num_ignore_frames) {
+  addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
+  if (!addr_space_) {
+    ALOGW("UnwindPtrace::Unwind: unw_create_addr_space failed.\n");
+    return false;
+  }
+
+  upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(backtrace_obj_->Tid()));
+  if (!upt_info_) {
+    ALOGW("UnwindPtrace::Unwind: Failed to create upt info.\n");
+    return false;
+  }
+
+  backtrace_t* backtrace = GetBacktraceData();
+  backtrace->num_frames = 0;
+
+  unw_cursor_t cursor;
+  int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
+  if (ret < 0) {
+    ALOGW("UnwindPtrace::Unwind: unw_init_remote failed %d\n", ret);
+    return false;
+  }
+
+  do {
+    unw_word_t pc;
+    ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
+    if (ret < 0) {
+      ALOGW("UnwindPtrace::Unwind: Failed to read IP %d\n", ret);
+      break;
+    }
+    unw_word_t sp;
+    ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
+    if (ret < 0) {
+      ALOGW("UnwindPtrace::Unwind: Failed to read SP %d\n", ret);
+      break;
+    }
+
+    if (num_ignore_frames == 0) {
+      size_t num_frames = backtrace->num_frames;
+      backtrace_frame_data_t* frame = &backtrace->frames[num_frames];
+      frame->pc = static_cast<uintptr_t>(pc);
+      frame->sp = static_cast<uintptr_t>(sp);
+      frame->stack_size = 0;
+      frame->map_name = NULL;
+      frame->map_offset = 0;
+      frame->func_name = NULL;
+      frame->func_offset = 0;
+
+      if (num_frames > 0) {
+        backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1];
+        prev->stack_size = frame->sp - prev->sp;
+      }
+
+      std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
+      if (!func_name.empty()) {
+        frame->func_name = strdup(func_name.c_str());
+      }
+
+      uintptr_t map_start;
+      frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
+      if (frame->map_name) {
+        frame->map_offset = frame->pc - map_start;
+      }
+
+      backtrace->num_frames++;
+    } else {
+      num_ignore_frames--;
+    }
+    ret = unw_step (&cursor);
+  } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
+
+  return true;
+}
+
+std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  *offset = 0;
+  char buf[512];
+  unw_word_t value;
+  if (unw_get_proc_name_by_ip(addr_space_, pc, buf, sizeof(buf), &value,
+                              upt_info_) >= 0 && buf[0] != '\0') {
+    *offset = static_cast<uintptr_t>(value);
+    return buf;
+  }
+  return "";
+}
+
+//-------------------------------------------------------------------------
+// C++ object creation function.
+//-------------------------------------------------------------------------
+Backtrace* CreatePtraceObj(pid_t pid, pid_t tid) {
+  return new BacktracePtrace(new UnwindPtrace(), pid, tid);
+}
diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h
new file mode 100644
index 0000000..781405b
--- /dev/null
+++ b/libbacktrace/UnwindPtrace.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_UNWIND_PTRACE_H
+#define _LIBBACKTRACE_UNWIND_PTRACE_H
+
+#include <string>
+
+#include "Backtrace.h"
+
+#include <libunwind.h>
+
+class UnwindPtrace : public BacktraceImpl {
+public:
+  UnwindPtrace();
+  virtual ~UnwindPtrace();
+
+  virtual bool Unwind(size_t num_ignore_frames);
+
+  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+private:
+  unw_addr_space_t addr_space_;
+  struct UPT_info* upt_info_;
+};
+
+#endif // _LIBBACKTRACE_UNWIND_PTRACE_H
diff --git a/libbacktrace/backtrace_test.c b/libbacktrace/backtrace_test.c
deleted file mode 100644
index 6155c9b..0000000
--- a/libbacktrace/backtrace_test.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <sys/ptrace.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <unistd.h>
-#include <inttypes.h>
-
-#include <backtrace/backtrace.h>
-
-#define FINISH(pid) dump_frames(&backtrace); if (pid < 0) exit(1); else return false;
-
-#define WAIT_INTERVAL_USECS   1000
-
-// Prototypes for functions in the test library.
-int test_level_one(int, int, int, int, bool (*)(pid_t));
-
-int test_recursive_call(int, bool (*)(pid_t));
-
-void dump_frames(const backtrace_t* backtrace) {
-  for (size_t i = 0; i < backtrace->num_frames; i++) {
-    printf("%zu ", i);
-    if (backtrace->frames[i].map_name) {
-      printf("%s", backtrace->frames[i].map_name);
-    } else {
-      printf("<unknown>");
-    }
-    if (backtrace->frames[i].proc_name) {
-      printf(" %s", backtrace->frames[i].proc_name);
-      if (backtrace->frames[i].proc_offset) {
-        printf("+%" PRIuPTR, backtrace->frames[i].proc_offset);
-      }
-    }
-    printf("\n");
-  }
-}
-
-void wait_for_stop(pid_t pid, size_t max_usecs_to_wait) {
-  siginfo_t si;
-  size_t usecs_waited = 0;
-
-  while (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) < 0 && (errno == EINTR || errno == ESRCH)) {
-    if (usecs_waited >= max_usecs_to_wait) {
-      printf("The process did not get to a stopping point in %zu usecs.\n",
-             usecs_waited);
-      break;
-    }
-    usleep(WAIT_INTERVAL_USECS);
-    usecs_waited += WAIT_INTERVAL_USECS;
-  }
-}
-
-bool check_frame(const backtrace_t* backtrace, size_t frame_num,
-                 const char* expected_name) {
-  if (backtrace->frames[frame_num].proc_name == NULL) {
-    printf("  Frame %zu function name expected %s, real value is NULL.\n",
-           frame_num, expected_name);
-    return false;
-  }
-  if (strcmp(backtrace->frames[frame_num].proc_name, expected_name) != 0) {
-    printf("  Frame %zu function name expected %s, real value is %s.\n",
-           frame_num, expected_name, backtrace->frames[frame_num].proc_name);
-    return false;
-  }
-  return true;
-}
-
-bool verify_level_backtrace(pid_t pid) {
-  const char* test_type;
-  if (pid < 0) {
-    test_type = "current";
-  } else {
-    test_type = "running";
-  }
-
-  backtrace_t backtrace;
-  if (!backtrace_get_data(&backtrace, pid)) {
-    printf("  backtrace_get_data failed on %s process.\n", test_type);
-    FINISH(pid);
-  }
-
-  if (backtrace.num_frames == 0) {
-    printf("  backtrace_get_data returned no frames for %s process.\n",
-           test_type);
-    FINISH(pid);
-  }
-
-  // Look through the frames starting at the highest to find the
-  // frame we want.
-  size_t frame_num = 0;
-  for (size_t i = backtrace.num_frames-1; i > 2; i--) {
-    if (backtrace.frames[i].proc_name != NULL &&
-        strcmp(backtrace.frames[i].proc_name, "test_level_one") == 0) {
-      frame_num = i;
-      break;
-    }
-  }
-  if (!frame_num) {
-    printf("  backtrace_get_data did not include the test_level_one frame.\n");
-    FINISH(pid);
-  }
-
-  if (!check_frame(&backtrace, frame_num, "test_level_one")) {
-    FINISH(pid);
-  }
-  if (!check_frame(&backtrace, frame_num-1, "test_level_two")) {
-    FINISH(pid);
-  }
-  if (!check_frame(&backtrace, frame_num-2, "test_level_three")) {
-    FINISH(pid);
-  }
-  if (!check_frame(&backtrace, frame_num-3, "test_level_four")) {
-    FINISH(pid);
-  }
-  backtrace_free_data(&backtrace);
-
-  return true;
-}
-
-bool verify_max_backtrace(pid_t pid) {
-  const char* test_type;
-  if (pid < 0) {
-    test_type = "current";
-  } else {
-    test_type = "running";
-  }
-
-  backtrace_t backtrace;
-  if (!backtrace_get_data(&backtrace, pid)) {
-    printf("  backtrace_get_data failed on %s process.\n", test_type);
-    FINISH(pid);
-  }
-
-  if (backtrace.num_frames != MAX_BACKTRACE_FRAMES) {
-    printf("  backtrace_get_data %s process max frame check failed:\n",
-           test_type);
-    printf("    Expected num frames to be %zu, found %zu\n",
-           MAX_BACKTRACE_FRAMES, backtrace.num_frames);
-    FINISH(pid);
-  }
-  backtrace_free_data(&backtrace);
-
-  return true;
-}
-
-void verify_proc_test(pid_t pid, bool (*verify_func)(pid_t)) {
-  printf("  Waiting 5 seconds for process to get to infinite loop.\n");
-  sleep(5);
-  if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) {
-    printf("Failed to attach to pid %d\n", pid);
-    kill(pid, SIGKILL);
-    exit(1);
-  }
-
-  // Wait up to 1 second for the process to get to a point that we can trace it.
-  wait_for_stop(pid, 1000000);
-
-  bool pass = verify_func(pid);
-  if (ptrace(PTRACE_DETACH, pid, 0, 0) != 0) {
-    printf("Failed to detach from pid %d\n", pid);
-    kill(pid, SIGKILL);
-    exit(1);
-  }
-
-  kill(pid, SIGKILL);
-  int status;
-  if (waitpid(pid, &status, 0) != pid) {
-    printf("Forked process did not terminate properly.\n");
-    exit(1);
-  }
-
-  if (!pass) {
-    exit(1);
-  }
-}
-
-int main() {
-  printf("Running level test on current process...\n");
-  int value = test_level_one(1, 2, 3, 4, verify_level_backtrace);
-  if (value == 0) {
-    printf("This should never happen.\n");
-    exit(1);
-  }
-  printf("  Passed.\n");
-
-  printf("Running max level test on current process...\n");
-  value = test_recursive_call(MAX_BACKTRACE_FRAMES+10, verify_max_backtrace);
-  if (value == 0) {
-    printf("This should never happen.\n");
-    exit(1);
-  }
-  printf("  Passed.\n");
-
-  printf("Running level test on process...\n");
-  pid_t pid;
-  if ((pid = fork()) == 0) {
-    value = test_level_one(1, 2, 3, 4, NULL);
-    if (value == 0) {
-      printf("This should never happen.\n");
-    }
-    exit(1);
-  }
-  verify_proc_test(pid, verify_level_backtrace);
-  printf("  Passed.\n");
-
-  printf("Running max frame test on process...\n");
-  if ((pid = fork()) == 0) {
-    value = test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL);
-    if (value == 0) {
-      printf("This should never happen.\n");
-    }
-    exit(1);
-  }
-  verify_proc_test(pid, verify_max_backtrace);
-  printf("  Passed.\n");
-
-  printf("All tests passed.\n");
-  return 0;
-}
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
new file mode 100644
index 0000000..48e2bdc
--- /dev/null
+++ b/libbacktrace/backtrace_test.cpp
@@ -0,0 +1,660 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <backtrace/backtrace.h>
+
+#include <cutils/atomic.h>
+#include <gtest/gtest.h>
+
+#include <vector>
+
+#include "thread_utils.h"
+
+// Number of microseconds per milliseconds.
+#define US_PER_MSEC             1000
+
+// Number of nanoseconds in a second.
+#define NS_PER_SEC              1000000000ULL
+
+// Number of simultaneous dumping operations to perform.
+#define NUM_THREADS  20
+
+// Number of simultaneous threads running in our forked process.
+#define NUM_PTRACE_THREADS 5
+
+typedef struct {
+  pid_t tid;
+  int32_t state;
+  pthread_t threadId;
+} thread_t;
+
+typedef struct {
+  thread_t thread;
+  backtrace_context_t context;
+  int32_t* now;
+  int32_t done;
+} dump_thread_t;
+
+extern "C" {
+// Prototypes for functions in the test library.
+int test_level_one(int, int, int, int, void (*)(void*), void*);
+
+int test_recursive_call(int, void (*)(void*), void*);
+}
+
+uint64_t NanoTime() {
+  struct timespec t = { 0, 0 };
+  clock_gettime(CLOCK_MONOTONIC, &t);
+  return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec);
+}
+
+void DumpFrames(const backtrace_context_t* context) {
+  if (context->backtrace->num_frames == 0) {
+    printf("    No frames to dump\n");
+  } else {
+    char line[512];
+    for (size_t i = 0; i < context->backtrace->num_frames; i++) {
+      backtrace_format_frame_data(context, i, line, sizeof(line));
+      printf("    %s\n", line);
+    }
+  }
+}
+
+void WaitForStop(pid_t pid) {
+  uint64_t start = NanoTime();
+
+  siginfo_t si;
+  while (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) < 0 && (errno == EINTR || errno == ESRCH)) {
+    if ((NanoTime() - start) > NS_PER_SEC) {
+      printf("The process did not get to a stopping point in 1 second.\n");
+      break;
+    }
+    usleep(US_PER_MSEC);
+  }
+}
+
+bool ReadyLevelBacktrace(const backtrace_t* backtrace) {
+  // See if test_level_four is in the backtrace.
+  bool found = false;
+  for (size_t i = 0; i < backtrace->num_frames; i++) {
+    if (backtrace->frames[i].func_name != NULL &&
+        strcmp(backtrace->frames[i].func_name, "test_level_four") == 0) {
+      found = true;
+      break;
+    }
+  }
+
+  return found;
+}
+
+void VerifyLevelDump(const backtrace_t* backtrace) {
+  ASSERT_GT(backtrace->num_frames, static_cast<size_t>(0));
+  ASSERT_LT(backtrace->num_frames, static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+
+  // Look through the frames starting at the highest to find the
+  // frame we want.
+  size_t frame_num = 0;
+  for (size_t i = backtrace->num_frames-1; i > 2; i--) {
+    if (backtrace->frames[i].func_name != NULL &&
+        strcmp(backtrace->frames[i].func_name, "test_level_one") == 0) {
+      frame_num = i;
+      break;
+    }
+  }
+  ASSERT_GT(frame_num, static_cast<size_t>(0));
+
+  ASSERT_TRUE(NULL != backtrace->frames[frame_num].func_name);
+  ASSERT_STREQ(backtrace->frames[frame_num].func_name, "test_level_one");
+  ASSERT_TRUE(NULL != backtrace->frames[frame_num-1].func_name);
+  ASSERT_STREQ(backtrace->frames[frame_num-1].func_name, "test_level_two");
+  ASSERT_TRUE(NULL != backtrace->frames[frame_num-2].func_name);
+  ASSERT_STREQ(backtrace->frames[frame_num-2].func_name, "test_level_three");
+  ASSERT_TRUE(NULL != backtrace->frames[frame_num-3].func_name);
+  ASSERT_STREQ(backtrace->frames[frame_num-3].func_name, "test_level_four");
+}
+
+void VerifyLevelBacktrace(void*) {
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, -1, -1, 0));
+
+  VerifyLevelDump(context.backtrace);
+
+  backtrace_destroy_context(&context);
+}
+
+bool ReadyMaxBacktrace(const backtrace_t* backtrace) {
+  return (backtrace->num_frames == MAX_BACKTRACE_FRAMES);
+}
+
+void VerifyMaxDump(const backtrace_t* backtrace) {
+  ASSERT_EQ(backtrace->num_frames, static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+  // Verify that the last frame is our recursive call.
+  ASSERT_TRUE(NULL != backtrace->frames[MAX_BACKTRACE_FRAMES-1].func_name);
+  ASSERT_STREQ(backtrace->frames[MAX_BACKTRACE_FRAMES-1].func_name,
+               "test_recursive_call");
+}
+
+void VerifyMaxBacktrace(void*) {
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, -1, -1, 0));
+
+  VerifyMaxDump(context.backtrace);
+
+  backtrace_destroy_context(&context);
+}
+
+void ThreadSetState(void* data) {
+  thread_t* thread = reinterpret_cast<thread_t*>(data);
+  android_atomic_acquire_store(1, &thread->state);
+  volatile int i = 0;
+  while (thread->state) {
+    i++;
+  }
+}
+
+void VerifyThreadTest(pid_t tid, void (*VerifyFunc)(const backtrace_t*)) {
+  backtrace_context_t context;
+
+  backtrace_create_context(&context, getpid(), tid, 0);
+
+  VerifyFunc(context.backtrace);
+
+  backtrace_destroy_context(&context);
+}
+
+bool WaitForNonZero(int32_t* value, uint64_t seconds) {
+  uint64_t start = NanoTime();
+  do {
+    if (android_atomic_acquire_load(value)) {
+      return true;
+    }
+  } while ((NanoTime() - start) < seconds * NS_PER_SEC);
+  return false;
+}
+
+TEST(libbacktrace, local_trace) {
+  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, NULL), 0);
+}
+
+void VerifyIgnoreFrames(
+    const backtrace_t* bt_all, const backtrace_t* bt_ign1,
+    const backtrace_t* bt_ign2, const char* cur_proc) {
+  EXPECT_EQ(bt_all->num_frames, bt_ign1->num_frames + 1);
+  EXPECT_EQ(bt_all->num_frames, bt_ign2->num_frames + 2);
+
+  // Check all of the frames are the same > the current frame.
+  bool check = (cur_proc == NULL);
+  for (size_t i = 0; i < bt_ign2->num_frames; i++) {
+    if (check) {
+      EXPECT_EQ(bt_ign2->frames[i].pc, bt_ign1->frames[i+1].pc);
+      EXPECT_EQ(bt_ign2->frames[i].sp, bt_ign1->frames[i+1].sp);
+      EXPECT_EQ(bt_ign2->frames[i].stack_size, bt_ign1->frames[i+1].stack_size);
+
+      EXPECT_EQ(bt_ign2->frames[i].pc, bt_all->frames[i+2].pc);
+      EXPECT_EQ(bt_ign2->frames[i].sp, bt_all->frames[i+2].sp);
+      EXPECT_EQ(bt_ign2->frames[i].stack_size, bt_all->frames[i+2].stack_size);
+    }
+    if (!check && bt_ign2->frames[i].func_name &&
+        strcmp(bt_ign2->frames[i].func_name, cur_proc) == 0) {
+      check = true;
+    }
+  }
+}
+
+void VerifyLevelIgnoreFrames(void*) {
+  backtrace_context_t all;
+  ASSERT_TRUE(backtrace_create_context(&all, -1, -1, 0));
+  ASSERT_TRUE(all.backtrace != NULL);
+
+  backtrace_context_t ign1;
+  ASSERT_TRUE(backtrace_create_context(&ign1, -1, -1, 1));
+  ASSERT_TRUE(ign1.backtrace != NULL);
+
+  backtrace_context_t ign2;
+  ASSERT_TRUE(backtrace_create_context(&ign2, -1, -1, 2));
+  ASSERT_TRUE(ign2.backtrace != NULL);
+
+  VerifyIgnoreFrames(all.backtrace, ign1.backtrace, ign2.backtrace,
+                     "VerifyLevelIgnoreFrames");
+
+  backtrace_destroy_context(&all);
+  backtrace_destroy_context(&ign1);
+  backtrace_destroy_context(&ign2);
+}
+
+TEST(libbacktrace, local_trace_ignore_frames) {
+  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, NULL), 0);
+}
+
+TEST(libbacktrace, local_max_trace) {
+  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, NULL), 0);
+}
+
+void VerifyProcTest(pid_t pid, pid_t tid,
+                    bool (*ReadyFunc)(const backtrace_t*),
+                    void (*VerifyFunc)(const backtrace_t*)) {
+  pid_t ptrace_tid;
+  if (tid < 0) {
+    ptrace_tid = pid;
+  } else {
+    ptrace_tid = tid;
+  }
+  uint64_t start = NanoTime();
+  bool verified = false;
+  do {
+    usleep(US_PER_MSEC);
+    if (ptrace(PTRACE_ATTACH, ptrace_tid, 0, 0) == 0) {
+      // Wait for the process to get to a stopping point.
+      WaitForStop(ptrace_tid);
+
+      backtrace_context_t context;
+      ASSERT_TRUE(backtrace_create_context(&context, pid, tid, 0));
+      if (ReadyFunc(context.backtrace)) {
+        VerifyFunc(context.backtrace);
+        verified = true;
+      }
+      backtrace_destroy_context(&context);
+      ASSERT_TRUE(ptrace(PTRACE_DETACH, ptrace_tid, 0, 0) == 0);
+    }
+    // If 5 seconds have passed, then we are done.
+  } while (!verified && (NanoTime() - start) <= 5 * NS_PER_SEC);
+  ASSERT_TRUE(verified);
+}
+
+TEST(libbacktrace, ptrace_trace) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    exit(1);
+  }
+  VerifyProcTest(pid, -1, ReadyLevelBacktrace, VerifyLevelDump);
+
+  kill(pid, SIGKILL);
+  int status;
+  ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+TEST(libbacktrace, ptrace_max_trace) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0);
+    exit(1);
+  }
+  VerifyProcTest(pid, -1, ReadyMaxBacktrace, VerifyMaxDump);
+
+  kill(pid, SIGKILL);
+  int status;
+  ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+void VerifyProcessIgnoreFrames(const backtrace_t* bt_all) {
+  pid_t pid = bt_all->pid;
+
+  backtrace_context_t ign1;
+  ASSERT_TRUE(backtrace_create_context(&ign1, pid, -1, 1));
+  ASSERT_TRUE(ign1.backtrace != NULL);
+
+  backtrace_context_t ign2;
+  ASSERT_TRUE(backtrace_create_context(&ign2, pid, -1, 2));
+  ASSERT_TRUE(ign2.backtrace != NULL);
+
+  VerifyIgnoreFrames(bt_all, ign1.backtrace, ign2.backtrace, NULL);
+
+  backtrace_destroy_context(&ign1);
+  backtrace_destroy_context(&ign2);
+}
+
+TEST(libbacktrace, ptrace_ignore_frames) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    exit(1);
+  }
+  VerifyProcTest(pid, -1, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
+
+  kill(pid, SIGKILL);
+  int status;
+  ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+// Create a process with multiple threads and dump all of the threads.
+void* PtraceThreadLevelRun(void*) {
+  EXPECT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+  return NULL;
+}
+
+void GetThreads(pid_t pid, std::vector<pid_t>* threads) {
+  // Get the list of tasks.
+  char task_path[128];
+  snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
+
+  DIR* tasks_dir = opendir(task_path);
+  ASSERT_TRUE(tasks_dir != NULL);
+  struct dirent* entry;
+  while ((entry = readdir(tasks_dir)) != NULL) {
+    char* end;
+    pid_t tid = strtoul(entry->d_name, &end, 10);
+    if (*end == '\0') {
+      threads->push_back(tid);
+    }
+  }
+  closedir(tasks_dir);
+}
+
+TEST(libbacktrace, ptrace_threads) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) {
+      pthread_attr_t attr;
+      pthread_attr_init(&attr);
+      pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+      pthread_t thread;
+      ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, NULL) == 0);
+    }
+    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    exit(1);
+  }
+
+  // Check to see that all of the threads are running before unwinding.
+  std::vector<pid_t> threads;
+  uint64_t start = NanoTime();
+  do {
+    usleep(US_PER_MSEC);
+    threads.clear();
+    GetThreads(pid, &threads);
+  } while ((threads.size() != NUM_PTRACE_THREADS + 1) &&
+      ((NanoTime() - start) <= 5 * NS_PER_SEC));
+  ASSERT_EQ(threads.size(), static_cast<size_t>(NUM_PTRACE_THREADS + 1));
+
+  ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+  WaitForStop(pid);
+  for (std::vector<int>::const_iterator it = threads.begin(); it != threads.end(); ++it) {
+    // Skip the current forked process, we only care about the threads.
+    if (pid == *it) {
+      continue;
+    }
+    VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump);
+  }
+  ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+  kill(pid, SIGKILL);
+  int status;
+  ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+void VerifyLevelThread(void*) {
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, getpid(), gettid(), 0));
+
+  VerifyLevelDump(context.backtrace);
+
+  backtrace_destroy_context(&context);
+}
+
+TEST(libbacktrace, thread_current_level) {
+  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, NULL), 0);
+}
+
+void VerifyMaxThread(void*) {
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, getpid(), gettid(), 0));
+
+  VerifyMaxDump(context.backtrace);
+
+  backtrace_destroy_context(&context);
+}
+
+TEST(libbacktrace, thread_current_max) {
+  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, NULL), 0);
+}
+
+void* ThreadLevelRun(void* data) {
+  thread_t* thread = reinterpret_cast<thread_t*>(data);
+
+  thread->tid = gettid();
+  EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0);
+  return NULL;
+}
+
+TEST(libbacktrace, thread_level_trace) {
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+  thread_t thread_data = { 0, 0, 0 };
+  pthread_t thread;
+  ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0);
+
+  // Wait up to 2 seconds for the tid to be set.
+  ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
+
+  // Save the current signal action and make sure it is restored afterwards.
+  struct sigaction cur_action;
+  ASSERT_TRUE(sigaction(SIGURG, NULL, &cur_action) == 0);
+
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, getpid(), thread_data.tid,0));
+
+  VerifyLevelDump(context.backtrace);
+
+  backtrace_destroy_context(&context);
+
+  // Tell the thread to exit its infinite loop.
+  android_atomic_acquire_store(0, &thread_data.state);
+
+  // Verify that the old action was restored.
+  struct sigaction new_action;
+  ASSERT_TRUE(sigaction(SIGURG, NULL, &new_action) == 0);
+  EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction);
+  EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
+}
+
+TEST(libbacktrace, thread_ignore_frames) {
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+  thread_t thread_data = { 0, 0, 0 };
+  pthread_t thread;
+  ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0);
+
+  // Wait up to 2 seconds for the tid to be set.
+  ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
+
+  backtrace_context_t all;
+  ASSERT_TRUE(backtrace_create_context(&all, getpid(), thread_data.tid, 0));
+
+  backtrace_context_t ign1;
+  ASSERT_TRUE(backtrace_create_context(&ign1, getpid(), thread_data.tid, 1));
+
+  backtrace_context_t ign2;
+  ASSERT_TRUE(backtrace_create_context(&ign2, getpid(), thread_data.tid, 2));
+
+  VerifyIgnoreFrames(all.backtrace, ign1.backtrace, ign2.backtrace, NULL);
+
+  backtrace_destroy_context(&all);
+  backtrace_destroy_context(&ign1);
+  backtrace_destroy_context(&ign2);
+
+  // Tell the thread to exit its infinite loop.
+  android_atomic_acquire_store(0, &thread_data.state);
+}
+
+void* ThreadMaxRun(void* data) {
+  thread_t* thread = reinterpret_cast<thread_t*>(data);
+
+  thread->tid = gettid();
+  EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0);
+  return NULL;
+}
+
+TEST(libbacktrace, thread_max_trace) {
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+  thread_t thread_data = { 0, 0, 0 };
+  pthread_t thread;
+  ASSERT_TRUE(pthread_create(&thread, &attr, ThreadMaxRun, &thread_data) == 0);
+
+  // Wait for the tid to be set.
+  ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
+
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, getpid(), thread_data.tid, 0));
+
+  VerifyMaxDump(context.backtrace);
+
+  backtrace_destroy_context(&context);
+
+  // Tell the thread to exit its infinite loop.
+  android_atomic_acquire_store(0, &thread_data.state);
+}
+
+void* ThreadDump(void* data) {
+  dump_thread_t* dump = reinterpret_cast<dump_thread_t*>(data);
+  while (true) {
+    if (android_atomic_acquire_load(dump->now)) {
+      break;
+    }
+  }
+
+  dump->context.data = NULL;
+  dump->context.backtrace = NULL;
+
+  // The status of the actual unwind will be checked elsewhere.
+  backtrace_create_context(&dump->context, getpid(), dump->thread.tid, 0);
+
+  android_atomic_acquire_store(1, &dump->done);
+
+  return NULL;
+}
+
+TEST(libbacktrace, thread_multiple_dump) {
+  // Dump NUM_THREADS simultaneously.
+  std::vector<thread_t> runners(NUM_THREADS);
+  std::vector<dump_thread_t> dumpers(NUM_THREADS);
+
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+  for (size_t i = 0; i < NUM_THREADS; i++) {
+    // Launch the runners, they will spin in hard loops doing nothing.
+    runners[i].tid = 0;
+    runners[i].state = 0;
+    ASSERT_TRUE(pthread_create(&runners[i].threadId, &attr, ThreadMaxRun, &runners[i]) == 0);
+  }
+
+  // Wait for tids to be set.
+  for (std::vector<thread_t>::iterator it = runners.begin(); it != runners.end(); ++it) {
+    ASSERT_TRUE(WaitForNonZero(&it->state, 10));
+  }
+
+  // Start all of the dumpers at once, they will spin until they are signalled
+  // to begin their dump run.
+  int32_t dump_now = 0;
+  for (size_t i = 0; i < NUM_THREADS; i++) {
+    dumpers[i].thread.tid = runners[i].tid;
+    dumpers[i].thread.state = 0;
+    dumpers[i].done = 0;
+    dumpers[i].now = &dump_now;
+
+    ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0);
+  }
+
+  // Start all of the dumpers going at once.
+  android_atomic_acquire_store(1, &dump_now);
+
+  for (size_t i = 0; i < NUM_THREADS; i++) {
+    ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 10));
+
+    // Tell the runner thread to exit its infinite loop.
+    android_atomic_acquire_store(0, &runners[i].state);
+
+    ASSERT_TRUE(dumpers[i].context.backtrace != NULL);
+    VerifyMaxDump(dumpers[i].context.backtrace);
+    backtrace_destroy_context(&dumpers[i].context);
+  }
+}
+
+TEST(libbacktrace, format_test) {
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, -1, -1, 0));
+  ASSERT_TRUE(context.backtrace != NULL);
+
+  backtrace_frame_data_t* frame = &context.backtrace->frames[1];
+  backtrace_frame_data_t save_frame = *frame;
+
+  memset(frame, 0, sizeof(backtrace_frame_data_t));
+  char buf[512];
+  backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+#if defined(__LP64__)
+  EXPECT_STREQ(buf, "#01 pc 0000000000000000  <unknown>");
+#else
+  EXPECT_STREQ(buf, "#01 pc 00000000  <unknown>");
+#endif
+
+  frame->pc = 0x12345678;
+  frame->map_name = "MapFake";
+  backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+#if defined(__LP64__)
+  EXPECT_STREQ(buf, "#01 pc 0000000012345678  MapFake");
+#else
+  EXPECT_STREQ(buf, "#01 pc 12345678  MapFake");
+#endif
+
+  frame->func_name = "ProcFake";
+  backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+#if defined(__LP64__)
+  EXPECT_STREQ(buf, "#01 pc 0000000012345678  MapFake (ProcFake)");
+#else
+  EXPECT_STREQ(buf, "#01 pc 12345678  MapFake (ProcFake)");
+#endif
+
+  frame->func_offset = 645;
+  backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+#if defined(__LP64__)
+  EXPECT_STREQ(buf, "#01 pc 0000000012345678  MapFake (ProcFake+645)");
+#else
+  EXPECT_STREQ(buf, "#01 pc 12345678  MapFake (ProcFake+645)");
+#endif
+
+  *frame = save_frame;
+
+  backtrace_destroy_context(&context);
+}
diff --git a/libbacktrace/backtrace_testlib.c b/libbacktrace/backtrace_testlib.c
index 9400549..d4d15db 100644
--- a/libbacktrace/backtrace_testlib.c
+++ b/libbacktrace/backtrace_testlib.c
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-#include <stdbool.h>
-#include <unistd.h>
+#include <stdio.h>
 
 int test_level_four(int one, int two, int three, int four,
-                    bool (*callback_func)(pid_t)) {
+                    void (*callback_func)(void*), void* data) {
   if (callback_func != NULL) {
-    callback_func(-1);
+    callback_func(data);
   } else {
     while (1) {
     }
@@ -29,25 +28,25 @@
 }
 
 int test_level_three(int one, int two, int three, int four,
-                     bool (*callback_func)(pid_t)) {
-  return test_level_four(one+3, two+6, three+9, four+12, callback_func) + 3;
+                     void (*callback_func)(void*), void* data) {
+  return test_level_four(one+3, two+6, three+9, four+12, callback_func, data) + 3;
 }
 
 int test_level_two(int one, int two, int three, int four,
-                   bool (*callback_func)(pid_t)) {
-  return test_level_three(one+2, two+4, three+6, four+8, callback_func) + 2;
+                   void (*callback_func)(void*), void* data) {
+  return test_level_three(one+2, two+4, three+6, four+8, callback_func, data) + 2;
 }
 
 int test_level_one(int one, int two, int three, int four,
-                   bool (*callback_func)(pid_t)) {
-  return test_level_two(one+1, two+2, three+3, four+4, callback_func) + 1;
+                   void (*callback_func)(void*), void* data) {
+  return test_level_two(one+1, two+2, three+3, four+4, callback_func, data) + 1;
 }
 
-int test_recursive_call(int level, bool (*callback_func)(pid_t)) {
+int test_recursive_call(int level, void (*callback_func)(void*), void* data) {
   if (level > 0) {
-    return test_recursive_call(level - 1, callback_func) + level;
+    return test_recursive_call(level - 1, callback_func, data) + level;
   } else if (callback_func != NULL) {
-    callback_func(-1);
+    callback_func(data);
   } else {
     while (1) {
     }
diff --git a/libbacktrace/common.c b/libbacktrace/common.c
deleted file mode 100644
index 20786f4..0000000
--- a/libbacktrace/common.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "libbacktrace"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/ptrace.h>
-#include <inttypes.h>
-
-#include <cutils/log.h>
-#include <backtrace/backtrace.h>
-
-#include "common.h"
-
-bool backtrace_read_word(const backtrace_t* backtrace, uintptr_t ptr,
-                         uint32_t* out_value) {
-  if (ptr & 3) {
-    ALOGW("backtrace_read_word: invalid pointer %p", (void*)ptr);
-    *out_value = (uint32_t)-1;
-    return false;
-  }
-
-  // Check if reading from the current process, or a different process.
-  if (backtrace->tid < 0) {
-    const backtrace_map_info_t* map_info = backtrace_find_map_info(backtrace->map_info_list, ptr);
-    if (map_info && map_info->is_readable) {
-      *out_value = *(uint32_t*)ptr;
-      return true;
-    } else {
-      ALOGW("backtrace_read_word: pointer %p not in a readbale map", (void*)ptr);
-      *out_value = (uint32_t)-1;
-      return false;
-    }
-  } else {
-#if defined(__APPLE__)
-    ALOGW("read_word: MacOS does not support reading from another pid.\n");
-    return false;
-#else
-    // ptrace() returns -1 and sets errno when the operation fails.
-    // To disambiguate -1 from a valid result, we clear errno beforehand.
-    errno = 0;
-    *out_value = ptrace(PTRACE_PEEKTEXT, backtrace->tid, (void*)ptr, NULL);
-    if (*out_value == (uint32_t)-1 && errno) {
-      ALOGW("try_get_word: invalid pointer 0x%08x reading from tid %d, "
-            "ptrace() errno=%d", ptr, backtrace->tid, errno);
-      return false;
-    }
-    return true;
-  }
-#endif
-}
-
-const char *backtrace_get_map_info(
-    const backtrace_t* backtrace, uintptr_t pc, uintptr_t* start_pc) {
-  const backtrace_map_info_t* map_info = backtrace_find_map_info(backtrace->map_info_list, pc);
-  if (map_info) {
-    if (start_pc) {
-      *start_pc = map_info->start;
-    }
-    return map_info->name;
-  }
-  return NULL;
-}
-
-void backtrace_format_frame_data(
-    const backtrace_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size) {
-  uintptr_t relative_pc;
-  const char* map_name;
-  if (frame->map_name) {
-    map_name = frame->map_name;
-  } else {
-    map_name = "<unknown>";
-  }
-  if (frame->map_offset) {
-    relative_pc = frame->map_offset;
-  } else {
-    relative_pc = frame->pc;
-  }
-  if (frame->proc_name && frame->proc_offset) {
-    snprintf(buf, buf_size, "#%02zu pc %0*" PRIxPTR "  %s (%s+%" PRIuPTR ")",
-             frame_num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
-             frame->proc_name, frame->proc_offset);
-  } else if (frame->proc_name) {
-    snprintf(buf, buf_size, "#%02zu pc %0*" PRIxPTR "  %s (%s)", frame_num,
-             (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->proc_name);
-  } else {
-    snprintf(buf, buf_size, "#%02zu pc %0*" PRIxPTR "  %s", frame_num,
-             (int)sizeof(uintptr_t)*2, relative_pc, map_name);
-  }
-}
-
-void free_frame_data(backtrace_t* backtrace) {
-  for (size_t i = 0; i < backtrace->num_frames; i++) {
-    if (backtrace->frames[i].proc_name) {
-      free(backtrace->frames[i].proc_name);
-    }
-  }
-  backtrace->num_frames = 0;
-}
diff --git a/libbacktrace/corkscrew.c b/libbacktrace/corkscrew.c
deleted file mode 100644
index 899409a..0000000
--- a/libbacktrace/corkscrew.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "libbacktrace"
-
-#include <string.h>
-
-#include <cutils/log.h>
-#include <backtrace/backtrace.h>
-
-#include <corkscrew/backtrace.h>
-
-#define __USE_GNU
-#include <dlfcn.h>
-
-#include "common.h"
-#include "demangle.h"
-
-bool backtrace_get_data(backtrace_t* backtrace, pid_t tid) {
-  backtrace->num_frames = 0;
-  backtrace->tid = tid;
-  backtrace->private_data = NULL;
-  backtrace->map_info_list = backtrace_create_map_info_list(tid);
-
-  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
-  ssize_t num_frames;
-  if (tid < 0) {
-    // Get data for the current thread.
-    num_frames = unwind_backtrace(frames, 0, MAX_BACKTRACE_FRAMES);
-  } else {
-    // Get data for a different thread.
-    ptrace_context_t* ptrace_context = load_ptrace_context(tid);
-    backtrace->private_data = ptrace_context;
-
-    num_frames = unwind_backtrace_ptrace(
-        tid, ptrace_context, frames, 0, MAX_BACKTRACE_FRAMES);
-  }
-  if (num_frames < 0) {
-      ALOGW("backtrace_get_data: unwind_backtrace_ptrace failed %d\n",
-            num_frames);
-      backtrace_free_data(backtrace);
-      return false;
-  }
-
-  backtrace->num_frames = num_frames;
-  backtrace_frame_data_t* frame;
-  uintptr_t map_start;
-  for (size_t i = 0; i < backtrace->num_frames; i++) {
-    frame = &backtrace->frames[i];
-    frame->pc = frames[i].absolute_pc;
-    frame->sp = frames[i].stack_top;
-    frame->stack_size = frames[i].stack_size;
-
-    frame->map_offset = 0;
-    frame->map_name = backtrace_get_map_info(backtrace, frame->pc, &map_start);
-    if (frame->map_name) {
-      frame->map_offset = frame->pc - map_start;
-    }
-
-    frame->proc_offset = 0;
-    frame->proc_name = backtrace_get_proc_name(backtrace, frame->pc, &frame->proc_offset);
-  }
-
-  return true;
-}
-
-void backtrace_free_data(backtrace_t* backtrace) {
-  free_frame_data(backtrace);
-
-  if (backtrace->map_info_list) {
-    backtrace_destroy_map_info_list(backtrace->map_info_list);
-    backtrace->map_info_list = NULL;
-  }
-
-  if (backtrace->private_data) {
-    ptrace_context_t* ptrace_context = (ptrace_context_t*)backtrace->private_data;
-    free_ptrace_context(ptrace_context);
-    backtrace->private_data = NULL;
-  }
-}
-
-char* backtrace_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
-    uintptr_t* offset) {
-  const char* symbol_name = NULL;
-  *offset = 0;
-  if (backtrace->tid < 0) {
-    // Get information about the current thread.
-    Dl_info info;
-    const backtrace_map_info_t* map_info;
-    map_info = backtrace_find_map_info(backtrace->map_info_list, pc);
-    if (map_info && dladdr((const void*)pc, &info) && info.dli_sname) {
-      *offset = pc - map_info->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase;
-      symbol_name = info.dli_sname;
-    }
-  } else {
-    // Get information about a different thread.
-    ptrace_context_t* ptrace_context = (ptrace_context_t*)backtrace->private_data;
-    const map_info_t* map_info;
-    const symbol_t* symbol;
-    find_symbol_ptrace(ptrace_context, pc, &map_info, &symbol);
-    if (symbol) {
-      if (map_info) {
-        *offset = pc - map_info->start - symbol->start;
-      }
-      symbol_name = symbol->name;
-    }
-  }
-
-  char* name = NULL;
-  if (symbol_name) {
-    name = demangle_symbol_name(symbol_name);
-    if (!name) {
-      name = strdup(symbol_name);
-    }
-  }
-  return name;
-}
diff --git a/libbacktrace/demangle.c b/libbacktrace/demangle.c
deleted file mode 100644
index de9a460..0000000
--- a/libbacktrace/demangle.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <sys/types.h>
-
-#include "demangle.h"
-
-extern char* __cxa_demangle (const char* mangled, char* buf, size_t* len,
-                             int* status);
-
-char* demangle_symbol_name(const char* name) {
-#if defined(__APPLE__)
-  // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
-  if (name != NULL && name[0] != '_') {
-    return NULL;
-  }
-#endif
-  // __cxa_demangle handles NULL by returning NULL
-  return __cxa_demangle(name, 0, 0, 0);
-}
diff --git a/libbacktrace/demangle.h b/libbacktrace/demangle.h
deleted file mode 100644
index a5318ac..0000000
--- a/libbacktrace/demangle.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _DEMANGLE_H
-#define _DEMANGLE_H
-
-/* Called to demangle a symbol name to be printed. Returns an allocated
- * string that must be freed by the caller.
- */
-char* demangle_symbol_name(const char* name);
-
-#endif /* _DEMANGLE_H */
diff --git a/libbacktrace/stubs.c b/libbacktrace/stubs.c
deleted file mode 100644
index 1741601..0000000
--- a/libbacktrace/stubs.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "libbacktrace"
-
-#include <cutils/log.h>
-#include <backtrace/backtrace.h>
-
-bool backtrace_get_data(backtrace_t* backtrace, pid_t tid) {
-  ALOGW("backtrace_get_data: unsupported architecture.\n");
-  return true;
-}
-
-void backtrace_free_data(backtrace_t* backtrace) {
-  ALOGW("backtrace_free_data: unsupported architecture.\n");
-}
-
-bool backtrace_read_word(const backtrace_t* backtrace, uintptr_t ptr,
-                         uint32_t* out_value) {
-  ALOGW("backtrace_read_word: unsupported architecture.\n");
-  return false;
-}
-
-const char *backtrace_get_map_info(const backtrace_t* backtrace,
-    uintptr_t pc, uintptr_t* start_pc) {
-  ALOGW("backtrace_get_map_info: unsupported architecture.\n");
-  return NULL;
-}
-
-char* backtrace_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
-    uintptr_t* offset) {
-  ALOGW("backtrace_get_proc_name: unsupported architecture.\n");
-  return NULL;
-}
-
-void backtrace_format_frame_data(
-    const backtrace_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size) {
-  ALOGW("backtrace_format_frame_data: unsupported architecture.\n");
-  buf[0] = '\0';
-}
diff --git a/libbacktrace/thread_utils.c b/libbacktrace/thread_utils.c
new file mode 100644
index 0000000..6f4cd3c
--- /dev/null
+++ b/libbacktrace/thread_utils.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "thread_utils.h"
+
+#if defined(__APPLE__)
+
+#include <sys/syscall.h>
+
+// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
+pid_t gettid() {
+  return syscall(SYS_thread_selfid);
+}
+
+#elif !defined(__BIONIC__)
+
+// glibc doesn't implement or export either gettid or tgkill.
+#include <unistd.h>
+#include <sys/syscall.h>
+
+pid_t gettid() {
+  return syscall(__NR_gettid);
+}
+
+int tgkill(int tgid, int tid, int sig) {
+  return syscall(__NR_tgkill, tgid, tid, sig);
+}
+
+#endif
diff --git a/libbacktrace/common.h b/libbacktrace/thread_utils.h
similarity index 73%
rename from libbacktrace/common.h
rename to libbacktrace/thread_utils.h
index 9eef964..ae4c929 100644
--- a/libbacktrace/common.h
+++ b/libbacktrace/thread_utils.h
@@ -14,12 +14,17 @@
  * limitations under the License.
  */
 
-#ifndef _COMMON_H
-#define _COMMON_H
+#ifndef _LIBBACKTRACE_THREAD_UTILS_H
+#define _LIBBACKTRACE_THREAD_UTILS_H
 
-#include <backtrace/backtrace.h>
+#include <unistd.h>
 
-/* Common routine to free any data allocated to store frame information. */
-void free_frame_data(backtrace_t* backtrace);
+__BEGIN_DECLS
 
-#endif /* _COMMON_H */
+int tgkill(int tgid, int tid, int sig);
+
+pid_t gettid();
+
+__END_DECLS
+
+#endif /* _LIBBACKTRACE_THREAD_UTILS_H */
diff --git a/libbacktrace/unwind.c b/libbacktrace/unwind.c
deleted file mode 100644
index f75e518..0000000
--- a/libbacktrace/unwind.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <backtrace/backtrace.h>
-
-#include "common.h"
-#include "unwind.h"
-
-bool backtrace_get_data(backtrace_t* backtrace, pid_t tid) {
-  backtrace->num_frames = 0;
-  backtrace->tid = tid;
-
-  backtrace->map_info_list = backtrace_create_map_info_list(tid);
-  if (tid < 0) {
-    return local_get_data(backtrace);
-  } else {
-    return remote_get_data(backtrace);
-  }
-}
-
-/* Free any memory related to the frame data. */
-void backtrace_free_data(backtrace_t* backtrace) {
-  free_frame_data(backtrace);
-
-  if (backtrace->map_info_list) {
-    backtrace_destroy_map_info_list(backtrace->map_info_list);
-    backtrace->map_info_list = NULL;
-  }
-
-  if (backtrace->tid < 0) {
-    local_free_data(backtrace);
-  } else {
-    remote_free_data(backtrace);
-  }
-}
-
-char* backtrace_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
-                              uintptr_t* offset) {
-  if (backtrace->tid < 0) {
-    return local_get_proc_name(backtrace, pc, offset);
-  } else {
-    return remote_get_proc_name(backtrace, pc, offset);
-  }
-}
diff --git a/libbacktrace/unwind.h b/libbacktrace/unwind.h
deleted file mode 100644
index 9ba96a4..0000000
--- a/libbacktrace/unwind.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _UNWIND_H
-#define _UNWIND_H
-
-bool local_get_data(backtrace_t* backtrace);
-
-void local_free_data(backtrace_t* backtrace);
-
-char* local_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
-                          uintptr_t* offset);
-
-bool remote_get_data(backtrace_t* backtrace);
-
-void remote_free_data(backtrace_t* backtrace);
-
-char* remote_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
-                           uintptr_t* offset);
-
-#endif /* _UNWIND_H */
diff --git a/libbacktrace/unwind_local.c b/libbacktrace/unwind_local.c
deleted file mode 100644
index d467d8a..0000000
--- a/libbacktrace/unwind_local.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "libbacktrace"
-
-#include <string.h>
-
-#include <cutils/log.h>
-#include <backtrace/backtrace.h>
-
-#define UNW_LOCAL_ONLY
-#include <libunwind.h>
-#include <libunwind-ptrace.h>
-
-#include "common.h"
-#include "demangle.h"
-
-static bool local_get_frames(backtrace_t* backtrace) {
-  unw_context_t* context = (unw_context_t*)backtrace->private_data;
-  unw_cursor_t cursor;
-
-  int ret = unw_getcontext(context);
-  if (ret < 0) {
-    ALOGW("local_get_frames: unw_getcontext failed %d\n", ret);
-    return false;
-  }
-
-  ret = unw_init_local(&cursor, context);
-  if (ret < 0) {
-    ALOGW("local_get_frames: unw_init_local failed %d\n", ret);
-    return false;
-  }
-
-  backtrace_frame_data_t* frame;
-  bool returnValue = true;
-  backtrace->num_frames = 0;
-  uintptr_t map_start;
-  unw_word_t value;
-  do {
-    frame = &backtrace->frames[backtrace->num_frames];
-    frame->stack_size = 0;
-    frame->map_name = NULL;
-    frame->map_offset = 0;
-    frame->proc_name = NULL;
-    frame->proc_offset = 0;
-
-    ret = unw_get_reg(&cursor, UNW_REG_IP, &value);
-    if (ret < 0) {
-      ALOGW("get_frames: Failed to read IP %d\n", ret);
-      returnValue = false;
-      break;
-    }
-    frame->pc = (uintptr_t)value;
-    ret = unw_get_reg(&cursor, UNW_REG_SP, &value);
-    if (ret < 0) {
-      ALOGW("get_frames: Failed to read IP %d\n", ret);
-      returnValue = false;
-      break;
-    }
-    frame->sp = (uintptr_t)value;
-
-    if (backtrace->num_frames) {
-      backtrace_frame_data_t* prev = &backtrace->frames[backtrace->num_frames-1];
-      prev->stack_size = frame->sp - prev->sp;
-    }
-
-    frame->proc_name = backtrace_get_proc_name(backtrace, frame->pc, &frame->proc_offset);
-
-    frame->map_name = backtrace_get_map_info(backtrace, frame->pc, &map_start);
-    if (frame->map_name) {
-      frame->map_offset = frame->pc - map_start;
-    }
-
-    backtrace->num_frames++;
-    ret = unw_step (&cursor);
-  } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
-
-  return returnValue;
-}
-
-bool local_get_data(backtrace_t* backtrace) {
-  unw_context_t *context = (unw_context_t*)malloc(sizeof(unw_context_t));
-  backtrace->private_data = context;
-
-  if (!local_get_frames(backtrace)) {
-    backtrace_free_data(backtrace);
-    return false;
-  }
-
-  return true;
-}
-
-void local_free_data(backtrace_t* backtrace) {
-  if (backtrace->private_data) {
-    free(backtrace->private_data);
-    backtrace->private_data = NULL;
-  }
-}
-
-char* local_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
-                          uintptr_t* offset) {
-  unw_context_t* context = (unw_context_t*)backtrace->private_data;
-  char buf[512];
-
-  *offset = 0;
-  unw_word_t value;
-  if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
-                              &value, context) >= 0 && buf[0] != '\0') {
-    *offset = (uintptr_t)value;
-    char* symbol = demangle_symbol_name(buf);
-    if (!symbol) {
-      symbol = strdup(buf);
-    }
-    return symbol;
-  }
-  return NULL;
-}
diff --git a/libbacktrace/unwind_remote.c b/libbacktrace/unwind_remote.c
deleted file mode 100644
index 1c624d7..0000000
--- a/libbacktrace/unwind_remote.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "libbacktrace"
-
-#include <sys/ptrace.h>
-#include <string.h>
-
-#include <cutils/log.h>
-#include <backtrace/backtrace.h>
-
-#include <libunwind.h>
-#include <libunwind-ptrace.h>
-
-#include "common.h"
-#include "demangle.h"
-
-typedef struct {
-  unw_addr_space_t addr_space;
-  struct UPT_info* upt_info;
-} backtrace_private_t;
-
-static bool remote_get_frames(backtrace_t* backtrace) {
-  backtrace_private_t* data = (backtrace_private_t*)backtrace->private_data;
-  unw_cursor_t cursor;
-  int ret = unw_init_remote(&cursor, data->addr_space, data->upt_info);
-  if (ret < 0) {
-    ALOGW("remote_get_frames: unw_init_remote failed %d\n", ret);
-    return false;
-  }
-
-  backtrace_frame_data_t* frame;
-  bool returnValue = true;
-  backtrace->num_frames = 0;
-  uintptr_t map_start;
-  unw_word_t value;
-  do {
-    frame = &backtrace->frames[backtrace->num_frames];
-    frame->stack_size = 0;
-    frame->map_name = NULL;
-    frame->map_offset = 0;
-    frame->proc_name = NULL;
-    frame->proc_offset = 0;
-
-    ret = unw_get_reg(&cursor, UNW_REG_IP, &value);
-    if (ret < 0) {
-      ALOGW("remote_get_frames: Failed to read IP %d\n", ret);
-      returnValue = false;
-      break;
-    }
-    frame->pc = (uintptr_t)value;
-    ret = unw_get_reg(&cursor, UNW_REG_SP, &value);
-    if (ret < 0) {
-      ALOGW("remote_get_frames: Failed to read SP %d\n", ret);
-      returnValue = false;
-      break;
-    }
-    frame->sp = (uintptr_t)value;
-
-    if (backtrace->num_frames) {
-      backtrace_frame_data_t* prev = &backtrace->frames[backtrace->num_frames-1];
-      prev->stack_size = frame->sp - prev->sp;
-    }
-
-    frame->proc_name = backtrace_get_proc_name(backtrace, frame->pc, &frame->proc_offset);
-
-    frame->map_name = backtrace_get_map_info(backtrace, frame->pc, &map_start);
-    if (frame->map_name) {
-      frame->map_offset = frame->pc - map_start;
-    }
-
-    backtrace->num_frames++;
-    ret = unw_step (&cursor);
-  } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
-
-  return returnValue;
-}
-
-bool remote_get_data(backtrace_t* backtrace) {
-  backtrace_private_t* data = (backtrace_private_t*)malloc(sizeof(backtrace_private_t));
-  if (!data) {
-    ALOGW("remote_get_data: Failed to allocate memory.\n");
-    backtrace_free_data(backtrace);
-    return false;
-  }
-  data->addr_space = NULL;
-  data->upt_info = NULL;
-
-  backtrace->private_data = data;
-  data->addr_space = unw_create_addr_space(&_UPT_accessors, 0);
-  if (!data->addr_space) {
-    ALOGW("remote_get_data: Failed to create unw address space.\n");
-    backtrace_free_data(backtrace);
-    return false;
-  }
-
-  data->upt_info = _UPT_create(backtrace->tid);
-  if (!data->upt_info) {
-    ALOGW("remote_get_data: Failed to create upt info.\n");
-    backtrace_free_data(backtrace);
-    return false;
-  }
-
-  if (!remote_get_frames(backtrace)) {
-    backtrace_free_data(backtrace);
-    return false;
-  }
-
-  return true;
-}
-
-void remote_free_data(backtrace_t* backtrace) {
-  if (backtrace->private_data) {
-    backtrace_private_t* data = (backtrace_private_t*)backtrace->private_data;
-    if (data->upt_info) {
-      _UPT_destroy(data->upt_info);
-      data->upt_info = NULL;
-    }
-    if (data->addr_space) {
-      unw_destroy_addr_space(data->addr_space);
-    }
-
-    free(backtrace->private_data);
-    backtrace->private_data = NULL;
-  }
-}
-
-char* remote_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
-                           uintptr_t* offset) {
-  backtrace_private_t* data = (backtrace_private_t*)backtrace->private_data;
-  char buf[512];
-
-  *offset = 0;
-  unw_word_t value;
-  if (unw_get_proc_name_by_ip(data->addr_space, pc, buf, sizeof(buf), &value,
-                              data->upt_info) >= 0 && buf[0] != '\0') {
-    *offset = (uintptr_t)value;
-    char* symbol = demangle_symbol_name(buf);
-    if (!symbol) {
-      symbol = strdup(buf);
-    }
-    return symbol;
-  }
-  return NULL;
-}