am 7f80f37d: (-s ours) DO NOT MERGE Restore libcorkscrew unwinding.

* commit '7f80f37da0ce0141d241bab624a7c77aae250ddd':
  DO NOT MERGE Restore libcorkscrew unwinding.
diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk
new file mode 100644
index 0000000..2f55645
--- /dev/null
+++ b/libbacktrace/Android.build.mk
@@ -0,0 +1,81 @@
+#
+# Copyright (C) 2014 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 $(CLEAR_VARS)
+
+LOCAL_MODULE := $(module)
+LOCAL_MODULE_TAGS := $(module_tag)
+LOCAL_MULTILIB := $($(module)_multilib)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+    $(LOCAL_PATH)/Android.mk \
+    $(LOCAL_PATH)/Android.build.mk \
+
+LOCAL_CFLAGS := \
+    $(common_cflags) \
+    $($(module)_cflags) \
+    $($(module)_cflags_$(build_type)) \
+
+LOCAL_CONLYFLAGS += \
+    $(common_conlyflags) \
+    $($(module)_conlyflags) \
+    $($(module)_conlyflags_$(build_type)) \
+
+LOCAL_CPPFLAGS += \
+    $(common_cppflags) \
+    $($(module)_cppflags) \
+    $($(module)_cppflags_$(build_type)) \
+
+LOCAL_C_INCLUDES := \
+    $(common_c_includes) \
+    $($(module)_c_includes) \
+    $($(module)_c_includes_$(build_type)) \
+
+LOCAL_SRC_FILES := \
+    $($(module)_src_files) \
+    $($(module)_src_files_$(build_type)) \
+
+LOCAL_STATIC_LIBRARIES := \
+    $($(module)_static_libraries) \
+    $($(module)_static_libraries_$(build_type)) \
+
+LOCAL_SHARED_LIBRARIES := \
+    $($(module)_shared_libraries) \
+    $($(module)_shared_libraries_$(build_type)) \
+
+LOCAL_LDLIBS := \
+    $($(module)_ldlibs) \
+    $($(module)_ldlibs_$(build_type)) \
+
+ifeq ($(build_type),target)
+  ifneq ($($(module)_libc++),)
+    include external/libcxx/libcxx.mk
+  else
+    include external/stlport/libstlport.mk
+  endif
+
+  include $(BUILD_$(build_target))
+endif
+
+ifeq ($(build_type),host)
+  # Only build if host builds are supported.
+  ifeq ($(build_host),true)
+    ifneq ($($(module)_libc++),)
+      include external/libcxx/libcxx.mk
+    endif
+    include $(BUILD_HOST_$(build_target))
+  endif
+endif
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
old mode 100644
new mode 100755
index 80cd861..c321369
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -1,14 +1,23 @@
-LOCAL_PATH:= $(call my-dir)
+#
+# Copyright (C) 2014 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.
+#
 
-common_src := \
-	BacktraceImpl.cpp \
-	BacktraceMap.cpp \
-	BacktraceThread.cpp \
-	thread_utils.c \
+LOCAL_PATH:= $(call my-dir)
 
 common_cflags := \
 	-Wall \
-	-Wno-unused-parameter \
 	-Werror \
 
 common_conlyflags := \
@@ -17,274 +26,185 @@
 common_cppflags := \
 	-std=gnu++11 \
 
-common_shared_libs := \
+build_host := false
+ifeq ($(HOST_OS),linux)
+ifeq ($(HOST_ARCH),$(filter $(HOST_ARCH),x86 x86_64))
+build_host := true
+endif
+endif
+
+#-------------------------------------------------------------------------
+# The libbacktrace library.
+#-------------------------------------------------------------------------
+libbacktrace_src_files := \
+	BacktraceImpl.cpp \
+	BacktraceMap.cpp \
+	BacktraceThread.cpp \
+	thread_utils.c \
+
+libbacktrace_shared_libraries_target := \
 	libcutils \
 	libgccdemangle \
-	liblog \
 
-# To enable using libunwind on each arch, add it to this list.
-libunwind_architectures :=
-
-ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),$(libunwind_architectures)))
-
-#----------------------------------------------------------------------------
-# The native libbacktrace library with libunwind.
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	$(common_src) \
+libbacktrace_src_files += \
 	UnwindCurrent.cpp \
 	UnwindMap.cpp \
 	UnwindPtrace.cpp \
 
-LOCAL_CFLAGS := \
-	$(common_cflags) \
-
-LOCAL_CONLYFLAGS += \
-	$(common_conlyflags) \
-
-LOCAL_CPPFLAGS += \
-	$(common_cppflags) \
-
-LOCAL_MODULE := libbacktrace
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_C_INCLUDES := \
-	$(common_c_includes) \
+libbacktrace_c_includes := \
 	external/libunwind/include \
 
-LOCAL_SHARED_LIBRARIES := \
-	$(common_shared_libs) \
+libbacktrace_shared_libraries := \
 	libunwind \
 	libunwind-ptrace \
 
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
-
-include external/stlport/libstlport.mk
-
-include $(BUILD_SHARED_LIBRARY)
-
-else
-
-#----------------------------------------------------------------------------
-# The native libbacktrace library with libcorkscrew.
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	$(common_src) \
-	Corkscrew.cpp \
-
-LOCAL_CFLAGS := \
-	$(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 \
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
-
-include external/stlport/libstlport.mk
-
-include $(BUILD_SHARED_LIBRARY)
-
-endif
-
-#----------------------------------------------------------------------------
-# libbacktrace test library, all optimizations turned off
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libbacktrace_test
-LOCAL_MODULE_FLAGS := debug
-
-LOCAL_SRC_FILES := \
-	backtrace_testlib.c
-
-LOCAL_CFLAGS += \
-	-std=gnu99 \
-	-O0 \
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
-
-include $(BUILD_SHARED_LIBRARY)
-
-#----------------------------------------------------------------------------
-# libbacktrace test executable
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := backtrace_test
-LOCAL_MODULE_FLAGS := debug
-
-LOCAL_SRC_FILES := \
-	backtrace_test.cpp \
-	thread_utils.c \
-
-LOCAL_CFLAGS += \
-	$(common_cflags) \
-	-fno-builtin \
-	-fstack-protector-all \
-	-O0 \
-	-g \
-	-DGTEST_OS_LINUX_ANDROID \
-	-DGTEST_HAS_STD_STRING \
-
-ifeq ($(TARGET_ARCH),arm64)
-  $(info TODO: $(LOCAL_PATH)/Android.mk -fstack-protector not yet available for the AArch64 toolchain)
-  LOCAL_CFLAGS += -fno-stack-protector
-endif # arm64
-
-LOCAL_CONLYFLAGS += \
-	$(common_conlyflags) \
-
-LOCAL_CPPFLAGS += \
-	$(common_cppflags) \
-
-LOCAL_SHARED_LIBRARIES += \
-	libcutils \
-	libbacktrace_test \
-	libbacktrace \
-
-LOCAL_LDLIBS := \
-	-lpthread \
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
-
-include $(BUILD_NATIVE_TEST)
-
-#----------------------------------------------------------------------------
-# Only x86 host versions of libbacktrace supported.
-#----------------------------------------------------------------------------
-ifeq ($(HOST_ARCH),x86)
-
-#----------------------------------------------------------------------------
-# The host libbacktrace library using libcorkscrew
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-
-LOCAL_CFLAGS += \
-	$(common_cflags) \
-
-LOCAL_CONLYFLAGS += \
-	$(common_conlyflags) \
-
-LOCAL_C_INCLUDES := \
-	$(common_c_includes) \
-
-LOCAL_SHARED_LIBRARIES := \
-	libgccdemangle \
+libbacktrace_shared_libraries_host := \
 	liblog \
 
-LOCAL_MODULE := libbacktrace
-LOCAL_MODULE_TAGS := optional
+libbacktrace_static_libraries_host := \
+	libcutils \
 
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
+module := libbacktrace
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+include $(LOCAL_PATH)/Android.build.mk
 
-ifeq ($(HOST_OS),linux)
-LOCAL_SRC_FILES += \
-	$(common_src) \
-	Corkscrew.cpp \
-
-LOCAL_C_INCLUDES += \
-	system/core/libcorkscrew \
-
-LOCAL_SHARED_LIBRARIES := \
-	libcorkscrew \
-
-LOCAL_CPPFLAGS += \
-	$(common_cppflags) \
-
-LOCAL_LDLIBS += \
-	-ldl \
-	-lrt \
-
-else
-LOCAL_SRC_FILES += \
+# Don't build for unbundled branches
+ifeq (,$(TARGET_BUILD_APPS))
+#-------------------------------------------------------------------------
+# The libbacktrace library (libc++)
+#-------------------------------------------------------------------------
+libbacktrace_libc++_src_files := \
+	BacktraceImpl.cpp \
 	BacktraceMap.cpp \
-
-endif
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-#----------------------------------------------------------------------------
-# The host test is only supported on linux.
-#----------------------------------------------------------------------------
-ifeq ($(HOST_OS),linux)
-
-#----------------------------------------------------------------------------
-# libbacktrace host test library, all optimizations turned off
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libbacktrace_test
-LOCAL_MODULE_FLAGS := debug
-
-LOCAL_SRC_FILES := \
-	backtrace_testlib.c
-
-LOCAL_CFLAGS += \
-	-std=gnu99 \
-	-O0 \
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-#----------------------------------------------------------------------------
-# libbacktrace host test executable
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := backtrace_test
-LOCAL_MODULE_FLAGS := debug
-
-LOCAL_SRC_FILES := \
-	backtrace_test.cpp \
+	BacktraceThread.cpp \
 	thread_utils.c \
 
-LOCAL_CFLAGS += \
-	$(common_cflags) \
+libbacktrace_libc++_shared_libraries_target := \
+	libcutils \
+	libgccdemangle \
+
+libbacktrace_libc++_src_files += \
+	UnwindCurrent.cpp \
+	UnwindMap.cpp \
+	UnwindPtrace.cpp \
+
+libbacktrace_libc++_c_includes := \
+	external/libunwind/include \
+
+libbacktrace_libc++_shared_libraries := \
+	libunwind \
+	libunwind-ptrace \
+
+libbacktrace_libc++_shared_libraries_host := \
+	liblog \
+
+libbacktrace_libc++_static_libraries_host := \
+	libcutils \
+
+libbacktrace_libc++_libc++ := true
+
+module := libbacktrace_libc++
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+libbacktrace_libc++_multilib := both
+include $(LOCAL_PATH)/Android.build.mk
+libbacktrace_libc++_multilib :=
+endif
+
+#-------------------------------------------------------------------------
+# The libbacktrace_test library needed by backtrace_test.
+#-------------------------------------------------------------------------
+libbacktrace_test_cflags := \
+	-O0 \
+
+libbacktrace_test_src_files := \
+	backtrace_testlib.c \
+
+module := libbacktrace_test
+module_tag := debug
+build_type := target
+build_target := SHARED_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+include $(LOCAL_PATH)/Android.build.mk
+
+#-------------------------------------------------------------------------
+# The backtrace_test executable.
+#-------------------------------------------------------------------------
+backtrace_test_cflags := \
 	-fno-builtin \
-	-fstack-protector-all \
 	-O0 \
 	-g \
-	-DGTEST_HAS_STD_STRING \
 
-LOCAL_SHARED_LIBRARIES := \
+backtrace_test_cflags_target := \
+	-DENABLE_PSS_TESTS \
+
+backtrace_test_src_files := \
+	backtrace_test.cpp \
+	GetPss.cpp \
+	thread_utils.c \
+
+backtrace_test_ldlibs_host := \
+	-lpthread \
+	-lrt \
+
+backtrace_test_shared_libraries := \
 	libbacktrace_test \
 	libbacktrace \
 
-LOCAL_LDLIBS := \
-	-lpthread \
+backtrace_test_shared_libraries_target := \
+	libcutils \
 
-LOCAL_ADDITIONAL_DEPENDENCIES := \
-	$(LOCAL_PATH)/Android.mk
+backtrace_test_static_libraries_host := \
+	libcutils \
 
-include $(BUILD_HOST_NATIVE_TEST)
+module := backtrace_test
+module_tag := debug
+build_type := target
+build_target := NATIVE_TEST
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+include $(LOCAL_PATH)/Android.build.mk
 
-endif # HOST_OS == linux
+#----------------------------------------------------------------------------
+# Special truncated libbacktrace library for mac.
+#----------------------------------------------------------------------------
+ifeq ($(HOST_OS),darwin)
 
-endif # HOST_ARCH == x86
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+	BacktraceMap.cpp \
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+# Don't build for unbundled branches
+ifeq (,$(TARGET_BUILD_APPS))
+#-------------------------------------------------------------------------
+# The libbacktrace library (libc++)
+#-------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbacktrace_libc++
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+	BacktraceMap.cpp \
+
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+endif # TARGET_BUILD_APPS
+
+endif # HOST_OS-darwin
diff --git a/libbacktrace/BacktraceImpl.cpp b/libbacktrace/BacktraceImpl.cpp
index 39296b4..405b042 100644
--- a/libbacktrace/BacktraceImpl.cpp
+++ b/libbacktrace/BacktraceImpl.cpp
@@ -19,17 +19,16 @@
 #include <string.h>
 #include <sys/ptrace.h>
 #include <sys/types.h>
+#include <ucontext.h>
 #include <unistd.h>
 
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-
 #include <string>
 
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
 #include "BacktraceImpl.h"
+#include "BacktraceLog.h"
 #include "thread_utils.h"
 
 //-------------------------------------------------------------------------
@@ -57,8 +56,8 @@
   }
 }
 
-bool Backtrace::Unwind(size_t num_ignore_frames) {
-  return impl_->Unwind(num_ignore_frames);
+bool Backtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  return impl_->Unwind(num_ignore_frames, ucontext);
 }
 
 extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
@@ -82,10 +81,10 @@
   return func_name;
 }
 
-bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) {
-  if (ptr & 3) {
+bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
+  if (ptr & (sizeof(word_t)-1)) {
     BACK_LOGW("invalid pointer %p", (void*)ptr);
-    *out_value = (uint32_t)-1;
+    *out_value = (word_t)-1;
     return false;
   }
   return true;
@@ -143,18 +142,18 @@
 BacktraceCurrent::~BacktraceCurrent() {
 }
 
-bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) {
+bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
   if (!VerifyReadWordArgs(ptr, out_value)) {
     return false;
   }
 
   const backtrace_map_t* map = FindMap(ptr);
   if (map && map->flags & PROT_READ) {
-    *out_value = *reinterpret_cast<uint32_t*>(ptr);
+    *out_value = *reinterpret_cast<word_t*>(ptr);
     return true;
   } else {
     BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
-    *out_value = static_cast<uint32_t>(-1);
+    *out_value = static_cast<word_t>(-1);
     return false;
   }
 }
@@ -171,7 +170,7 @@
 BacktracePtrace::~BacktracePtrace() {
 }
 
-bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) {
+bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
   if (!VerifyReadWordArgs(ptr, out_value)) {
     return false;
   }
@@ -184,7 +183,7 @@
   // 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) {
+  if (*out_value == static_cast<word_t>(-1) && errno) {
     BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
               reinterpret_cast<void*>(ptr), Tid(), strerror(errno));
     return false;
diff --git a/libbacktrace/BacktraceImpl.h b/libbacktrace/BacktraceImpl.h
old mode 100644
new mode 100755
index af014d5..d34ad05
--- a/libbacktrace/BacktraceImpl.h
+++ b/libbacktrace/BacktraceImpl.h
@@ -21,17 +21,12 @@
 #include <backtrace/BacktraceMap.h>
 
 #include <sys/types.h>
-#include <log/log.h>
-
-// Macro to log the function name along with the warning message.
-#define BACK_LOGW(format, ...) \
-  ALOGW("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
 
 class BacktraceImpl {
 public:
   virtual ~BacktraceImpl() { }
 
-  virtual bool Unwind(size_t num_ignore_frames) = 0;
+  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) = 0;
 
   // The name returned is not demangled, Backtrace::GetFunctionName()
   // takes care of demangling the name.
@@ -61,7 +56,7 @@
   BacktraceCurrent(BacktraceImpl* impl, BacktraceMap* map);
   virtual ~BacktraceCurrent();
 
-  bool ReadWord(uintptr_t ptr, uint32_t* out_value);
+  bool ReadWord(uintptr_t ptr, word_t* out_value);
 };
 
 class BacktracePtrace : public Backtrace {
@@ -69,7 +64,7 @@
   BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map);
   virtual ~BacktracePtrace();
 
-  bool ReadWord(uintptr_t ptr, uint32_t* out_value);
+  bool ReadWord(uintptr_t ptr, word_t* out_value);
 };
 
 Backtrace* CreateCurrentObj(BacktraceMap* map);
diff --git a/libbacktrace/BacktraceLog.h b/libbacktrace/BacktraceLog.h
new file mode 100755
index 0000000..1632ec2
--- /dev/null
+++ b/libbacktrace/BacktraceLog.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 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_LOG_H
+#define _LIBBACKTRACE_BACKTRACE_LOG_H
+
+#define LOG_TAG "libbacktrace"
+
+#include <log/log.h>
+
+// Macro to log the function name along with the warning message.
+#define BACK_LOGW(format, ...) \
+  ALOGW("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
+
+#endif // _LIBBACKTRACE_BACKTRACE_LOG_H
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 6320800..f38e484 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -93,7 +93,8 @@
   }
 
   ALOGV("Parsed map: start=%p, end=%p, flags=%x, name=%s",
-        map->start, map->end, map->flags, map->name.c_str());
+        reinterpret_cast<void*>(map->start), reinterpret_cast<void*>(map->end),
+        map->flags, map->name.c_str());
   return true;
 }
 
@@ -107,11 +108,11 @@
 
 #if defined(__APPLE__)
   // cmd is guaranteed to always be big enough to hold this string.
-  sprintf(cmd, "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
+  snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
   FILE* fp = popen(cmd, "r");
 #else
   // path is guaranteed to always be big enough to hold this string.
-  sprintf(path, "/proc/%d/maps", pid_);
+  snprintf(path, sizeof(path), "/proc/%d/maps", pid_);
   FILE* fp = fopen(path, "r");
 #endif
   if (fp == NULL) {
@@ -136,7 +137,7 @@
 #if defined(__APPLE__)
 // Corkscrew and libunwind don't compile on the mac, so create a generic
 // map object.
-BacktraceMap* BacktraceMap::Create(pid_t pid) {
+BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
   BacktraceMap* map = new BacktraceMap(pid);
   if (!map->Build()) {
     delete map;
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp
index 5ffe516..b47cd2a 100644
--- a/libbacktrace/BacktraceThread.cpp
+++ b/libbacktrace/BacktraceThread.cpp
@@ -16,200 +16,195 @@
 
 #include <errno.h>
 #include <inttypes.h>
+#include <limits.h>
+#include <linux/futex.h>
 #include <pthread.h>
 #include <signal.h>
 #include <string.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
 #include <sys/types.h>
+#include <ucontext.h>
 
 #include <cutils/atomic.h>
 
+#include "BacktraceLog.h"
 #include "BacktraceThread.h"
 #include "thread_utils.h"
 
+static inline int futex(volatile int* uaddr, int op, int val, const struct timespec* ts, volatile int* uaddr2, int val3) {
+  return syscall(__NR_futex, uaddr, op, val, ts, uaddr2, val3);
+}
+
 //-------------------------------------------------------------------------
 // ThreadEntry implementation.
 //-------------------------------------------------------------------------
-static ThreadEntry* g_list = NULL;
-static pthread_mutex_t g_entry_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
+ThreadEntry* ThreadEntry::list_ = NULL;
+pthread_mutex_t ThreadEntry::list_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) {
+// Assumes that ThreadEntry::list_mutex_ has already been locked before
+// creating a ThreadEntry object.
+ThreadEntry::ThreadEntry(pid_t pid, pid_t tid)
+    : pid_(pid), tid_(tid), futex_(0), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), next_(ThreadEntry::list_), prev_(NULL) {
+  // Add ourselves to the list.
+  if (ThreadEntry::list_) {
+    ThreadEntry::list_->prev_ = this;
+  }
+  ThreadEntry::list_ = this;
 }
 
-ThreadEntry::~ThreadEntry() {
-  pthread_mutex_lock(&g_entry_mutex);
-  if (g_list == this) {
-    g_list = next;
+ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) {
+  pthread_mutex_lock(&ThreadEntry::list_mutex_);
+  ThreadEntry* entry = list_;
+  while (entry != NULL) {
+    if (entry->Match(pid, tid)) {
+      break;
+    }
+    entry = entry->next_;
+  }
+
+  if (!entry) {
+    if (create) {
+      entry = new ThreadEntry(pid, tid);
+    }
   } else {
-    if (next) {
-      next->prev = prev;
-    }
-    prev->next = next;
+    entry->ref_count_++;
   }
-  pthread_mutex_unlock(&g_entry_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_entry_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.
-      BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid);
-
-      pthread_mutex_unlock(&g_entry_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_entry_mutex);
+  pthread_mutex_unlock(&ThreadEntry::list_mutex_);
 
   return entry;
 }
 
+void ThreadEntry::Remove(ThreadEntry* entry) {
+  pthread_mutex_unlock(&entry->mutex_);
+
+  pthread_mutex_lock(&ThreadEntry::list_mutex_);
+  if (--entry->ref_count_ == 0) {
+    delete entry;
+  }
+  pthread_mutex_unlock(&ThreadEntry::list_mutex_);
+}
+
+// Assumes that ThreadEntry::list_mutex_ has already been locked before
+// deleting a ThreadEntry object.
+ThreadEntry::~ThreadEntry() {
+  if (list_ == this) {
+    list_ = next_;
+  } else {
+    if (next_) {
+      next_->prev_ = prev_;
+    }
+    prev_->next_ = next_;
+  }
+
+  next_ = NULL;
+  prev_ = NULL;
+}
+
+void ThreadEntry::Wait(int value) {
+  timespec ts;
+  ts.tv_sec = 10;
+  ts.tv_nsec = 0;
+  errno = 0;
+  futex(&futex_, FUTEX_WAIT, value, &ts, NULL, 0);
+  if (errno != 0 && errno != EWOULDBLOCK) {
+    BACK_LOGW("futex wait failed, futex = %d: %s", futex_, strerror(errno));
+  }
+}
+
+void ThreadEntry::Wake() {
+  futex_++;
+  futex(&futex_, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
+}
+
+void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) {
+  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext);
+  // The only thing the unwinder cares about is the mcontext data.
+  memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext));
+}
+
 //-------------------------------------------------------------------------
 // BacktraceThread functions.
 //-------------------------------------------------------------------------
-static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
-                          void* sigcontext) {
-  if (pthread_mutex_lock(&g_entry_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_entry_mutex);
-    if (!cur_entry) {
-      BACK_LOGW("Unable to find pid %d tid %d information", pid, tid);
-      return;
-    }
+static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
 
-    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);
+static void SignalHandler(int, siginfo_t*, void* sigcontext) {
+  ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
+  if (!entry) {
+    BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid());
+    return;
   }
+
+  entry->CopyUcontextFromSigcontext(sigcontext);
+
+  // Indicate the ucontext is now valid.
+  entry->Wake();
+
+  // Pause the thread until the unwind is complete. This avoids having
+  // the thread run ahead causing problems.
+  entry->Wait(1);
+
+  ThreadEntry::Remove(entry);
 }
 
-BacktraceThread::BacktraceThread(
-    BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid,
-    BacktraceMap* map)
-    : BacktraceCurrent(impl, map), thread_intf_(thread_intf) {
+BacktraceThread::BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map)
+    : BacktraceCurrent(impl, map) {
   tid_ = tid;
 }
 
 BacktraceThread::~BacktraceThread() {
 }
 
-void BacktraceThread::FinishUnwind() {
-  for (std::vector<backtrace_frame_data_t>::iterator it = frames_.begin();
-       it != frames_.end(); ++it) {
-    it->map = FindMap(it->pc);
-
-    it->func_offset = 0;
-    it->func_name = GetFunctionName(it->pc, &it->func_offset);
-  }
-}
-
-bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
-  entry->state = STATE_WAITING;
-
-  if (tgkill(Pid(), Tid(), SIGURG) != 0) {
-    BACK_LOGW("tgkill failed %s", strerror(errno));
-    return false;
-  }
-
-  // Allow up to ten seconds for the dump to start.
-  int wait_millis = 10000;
-  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) {
-      BACK_LOGW("Cancelled dump of thread %d", entry->tid);
-      state = STATE_CANCEL;
-      cancelled = true;
-    } else {
-      state = android_atomic_acquire_load(&entry->state);
-    }
-  }
-
-  // Wait for at most ten seconds for the cancel or dump to finish.
-  wait_millis = 10000;
-  while (android_atomic_acquire_load(&entry->state) != STATE_DONE) {
-    if (wait_millis--) {
-      usleep(1000);
-    } else {
-      BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
-      break;
-    }
-  }
-  return !cancelled;
-}
-
-bool BacktraceThread::Unwind(size_t num_ignore_frames) {
-  ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
-      thread_intf_, Pid(), Tid(), num_ignore_frames);
-  if (!entry) {
-    return false;
+bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (ucontext) {
+    // Unwind using an already existing ucontext.
+    return impl_->Unwind(num_ignore_frames, ucontext);
   }
 
   // Prevent multiple threads trying to set the trigger action on different
   // threads at the same time.
-  bool retval = false;
-  if (pthread_mutex_lock(&g_sigaction_mutex) == 0) {
-    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 {
-      BACK_LOGW("sigaction failed %s", strerror(errno));
-    }
+  if (pthread_mutex_lock(&g_sigaction_mutex) < 0) {
+    BACK_LOGW("sigaction failed: %s", strerror(errno));
+    return false;
+  }
+
+  ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid());
+  entry->Lock();
+
+  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(THREAD_SIGNAL, &act, &oldact) != 0) {
+    BACK_LOGW("sigaction failed %s", strerror(errno));
+    entry->Unlock();
+    ThreadEntry::Remove(entry);
     pthread_mutex_unlock(&g_sigaction_mutex);
-  } else {
-    BACK_LOGW("unable to acquire sigaction mutex.");
+    return false;
   }
 
-  if (retval) {
-    FinishUnwind();
+  if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
+    BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno));
+    sigaction(THREAD_SIGNAL, &oldact, NULL);
+    entry->Unlock();
+    ThreadEntry::Remove(entry);
+    pthread_mutex_unlock(&g_sigaction_mutex);
+    return false;
   }
-  delete entry;
 
-  return retval;
+  // Wait for the thread to get the ucontext.
+  entry->Wait(0);
+
+  // After the thread has received the signal, allow other unwinders to
+  // continue.
+  sigaction(THREAD_SIGNAL, &oldact, NULL);
+  pthread_mutex_unlock(&g_sigaction_mutex);
+
+  bool unwind_done = impl_->Unwind(num_ignore_frames, entry->GetUcontext());
+
+  // Tell the signal handler to exit and release the entry.
+  entry->Wake();
+
+  return unwind_done;
 }
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h
index 3412d58..ff3e9f3 100644
--- a/libbacktrace/BacktraceThread.h
+++ b/libbacktrace/BacktraceThread.h
@@ -18,73 +18,71 @@
 #define _LIBBACKTRACE_BACKTRACE_THREAD_H
 
 #include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
 #include <sys/types.h>
+#include <ucontext.h>
 
 #include "BacktraceImpl.h"
 
-enum state_e {
-  STATE_WAITING = 0,
-  STATE_DUMPING,
-  STATE_DONE,
-  STATE_CANCEL,
-};
+// The signal used to cause a thread to dump the stack.
+#if defined(__GLIBC__)
+// GLIBC reserves __SIGRTMIN signals, so use SIGRTMIN to avoid errors.
+#define THREAD_SIGNAL SIGRTMIN
+#else
+#define THREAD_SIGNAL (__SIGRTMIN+1)
+#endif
 
-class BacktraceThreadInterface;
+class ThreadEntry {
+public:
+  static ThreadEntry* Get(pid_t pid, pid_t tid, bool create = true);
 
-struct ThreadEntry {
-  ThreadEntry(
-      BacktraceThreadInterface* impl, pid_t pid, pid_t tid,
-      size_t num_ignore_frames);
+  static void Remove(ThreadEntry* entry);
+
+  void Wake();
+
+  void Wait(int);
+
+  void CopyUcontextFromSigcontext(void*);
+
+  inline void Lock() {
+    pthread_mutex_lock(&mutex_);
+    // Reset the futex value in case of multiple unwinds of the same thread.
+    futex_ = 0;
+  }
+
+  inline void Unlock() {
+    pthread_mutex_unlock(&mutex_);
+  }
+
+  inline ucontext_t* GetUcontext() { return &ucontext_; }
+
+private:
+  ThreadEntry(pid_t pid, pid_t tid);
   ~ThreadEntry();
 
-  bool Match(pid_t chk_pid, pid_t chk_tid) { return (chk_pid == pid && chk_tid == tid); }
+  bool Match(pid_t chk_pid, pid_t chk_tid) { return (chk_pid == pid_ && chk_tid == tid_); }
 
-  static ThreadEntry* AddThreadToUnwind(
-      BacktraceThreadInterface* thread_intf, pid_t pid, pid_t tid,
-      size_t num_ignored_frames);
+  pid_t pid_;
+  pid_t tid_;
+  int futex_;
+  int ref_count_;
+  pthread_mutex_t mutex_;
+  ThreadEntry* next_;
+  ThreadEntry* prev_;
+  ucontext_t ucontext_;
 
-  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 void ThreadUnwind(
-      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) = 0;
+  static ThreadEntry* list_;
+  static pthread_mutex_t list_mutex_;
 };
 
 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,
-      BacktraceMap* map);
+  BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map);
   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_;
+  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
 };
 
 #endif // _LIBBACKTRACE_BACKTRACE_THREAD_H
diff --git a/libbacktrace/Corkscrew.cpp b/libbacktrace/Corkscrew.cpp
deleted file mode 100644
index efeee2e..0000000
--- a/libbacktrace/Corkscrew.cpp
+++ /dev/null
@@ -1,251 +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 <backtrace/Backtrace.h>
-
-#include <string.h>
-
-#include <backtrace-arch.h>
-#include <corkscrew/backtrace.h>
-
-#ifndef __USE_GNU
-#define __USE_GNU
-#endif
-#include <dlfcn.h>
-
-#include "Corkscrew.h"
-
-//-------------------------------------------------------------------------
-// CorkscrewMap functions.
-//-------------------------------------------------------------------------
-CorkscrewMap::CorkscrewMap(pid_t pid) : BacktraceMap(pid), map_info_(NULL) {
-}
-
-CorkscrewMap::~CorkscrewMap() {
-  if (map_info_) {
-    free_map_info_list(map_info_);
-    map_info_ = NULL;
-  }
-}
-
-bool CorkscrewMap::Build() {
-  map_info_ = load_map_info_list(pid_);
-
-  // Use the information in map_info_ to construct the BacktraceMap data
-  // rather than reparsing /proc/self/maps.
-  map_info_t* cur_map = map_info_;
-  while (cur_map) {
-    backtrace_map_t map;
-    map.start = cur_map->start;
-    map.end = cur_map->end;
-    map.flags = 0;
-    if (cur_map->is_readable) {
-      map.flags |= PROT_READ;
-    }
-    if (cur_map->is_writable) {
-      map.flags |= PROT_WRITE;
-    }
-    if (cur_map->is_executable) {
-      map.flags |= PROT_EXEC;
-    }
-    map.name = cur_map->name;
-
-    // The maps are in descending order, but we want them in ascending order.
-    maps_.push_front(map);
-
-    cur_map = cur_map->next;
-  }
-  return map_info_ != NULL;
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewCommon functions.
-//-------------------------------------------------------------------------
-bool CorkscrewCommon::GenerateFrameData(
-    backtrace_frame_t* cork_frames, ssize_t num_frames) {
-  if (num_frames < 0) {
-    BACK_LOGW("libcorkscrew unwind failed.");
-    return false;
-  }
-
-  std::vector<backtrace_frame_data_t>* frames = GetFrames();
-  frames->resize(num_frames);
-  size_t i = 0;
-  for (std::vector<backtrace_frame_data_t>::iterator it = frames->begin();
-       it != frames->end(); ++it, ++i) {
-    it->num = i;
-    it->pc = cork_frames[i].absolute_pc;
-    it->sp = cork_frames[i].stack_top;
-    it->stack_size = cork_frames[i].stack_size;
-    it->func_offset = 0;
-
-    it->map = FindMap(it->pc);
-    it->func_name = GetFunctionName(it->pc, &it->func_offset);
-  }
-  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;
-
-  Dl_info info;
-  const backtrace_map_t* map = FindMap(pc);
-  if (map) {
-    if (dladdr((const void*)pc, &info)) {
-      if (info.dli_sname) {
-        *offset = pc - map->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase;
-        return info.dli_sname;
-      }
-    } else {
-      // dladdr(3) didn't find a symbol; maybe it's static? Look in the ELF file...
-      symbol_table_t* symbol_table = load_symbol_table(map->name.c_str());
-      if (symbol_table) {
-        // First check if we can find the symbol using a relative pc.
-        std::string name;
-        const symbol_t* elf_symbol = find_symbol(symbol_table, pc - map->start);
-        if (elf_symbol) {
-          name = elf_symbol->name;
-          *offset = pc - map->start - elf_symbol->start;
-        } else if ((elf_symbol = find_symbol(symbol_table, pc)) != NULL) {
-          // Found the symbol using the absolute pc.
-          name = elf_symbol->name;
-          *offset = pc - elf_symbol->start;
-        }
-        free_symbol_table(symbol_table);
-        return name;
-      }
-    }
-  }
-  return "";
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewThread functions.
-//-------------------------------------------------------------------------
-CorkscrewThread::CorkscrewThread() {
-}
-
-CorkscrewThread::~CorkscrewThread() {
-}
-
-void CorkscrewThread::ThreadUnwind(
-    siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
-  backtrace_frame_t cork_frames[MAX_BACKTRACE_FRAMES];
-  CorkscrewMap* map = static_cast<CorkscrewMap*>(GetMap());
-  ssize_t num_frames = unwind_backtrace_signal_arch(
-      siginfo, sigcontext, map->GetMapInfo(), cork_frames,
-      num_ignore_frames, MAX_BACKTRACE_FRAMES);
-  if (num_frames > 0) {
-    std::vector<backtrace_frame_data_t>* frames = GetFrames();
-    frames->resize(num_frames);
-    size_t i = 0;
-    for (std::vector<backtrace_frame_data_t>::iterator it = frames->begin();
-         it != frames->end(); ++it, ++i) {
-      it->num = i;
-      it->pc = cork_frames[i].absolute_pc;
-      it->sp = cork_frames[i].stack_top;
-      it->stack_size = cork_frames[i].stack_size;
-      it->map = NULL;
-      it->func_offset = 0;
-    }
-  }
-}
-
-//-------------------------------------------------------------------------
-// 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(Tid());
-
-  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
-  ssize_t num_frames = unwind_backtrace_ptrace(
-      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 creation functions.
-//-------------------------------------------------------------------------
-Backtrace* CreateCurrentObj(BacktraceMap* map) {
-  return new BacktraceCurrent(new CorkscrewCurrent(), map);
-}
-
-Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) {
-  return new BacktracePtrace(new CorkscrewPtrace(), pid, tid, map);
-}
-
-Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) {
-  CorkscrewThread* thread_obj = new CorkscrewThread();
-  return new BacktraceThread(thread_obj, thread_obj, tid, map);
-}
-
-//-------------------------------------------------------------------------
-// BacktraceMap create function.
-//-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::Create(pid_t pid) {
-  BacktraceMap* map = new CorkscrewMap(pid);
-  if (!map->Build()) {
-    delete map;
-    return NULL;
-  }
-  return map;
-}
diff --git a/libbacktrace/Corkscrew.h b/libbacktrace/Corkscrew.h
deleted file mode 100644
index 1633398..0000000
--- a/libbacktrace/Corkscrew.h
+++ /dev/null
@@ -1,82 +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 _LIBBACKTRACE_CORKSCREW_H
-#define _LIBBACKTRACE_CORKSCREW_H
-
-#include <inttypes.h>
-
-#include <string>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include <corkscrew/backtrace.h>
-
-#include "BacktraceImpl.h"
-#include "BacktraceThread.h"
-
-class CorkscrewMap : public BacktraceMap {
-public:
-  CorkscrewMap(pid_t pid);
-  virtual ~CorkscrewMap();
-
-  virtual bool Build();
-
-  map_info_t* GetMapInfo() { return map_info_; }
-
-private:
-  map_info_t* map_info_;
-};
-
-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 void ThreadUnwind(
-      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
-};
-
-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/GetPss.cpp b/libbacktrace/GetPss.cpp
new file mode 100644
index 0000000..442383b
--- /dev/null
+++ b/libbacktrace/GetPss.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 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 <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+// This is an extremely simplified version of libpagemap.
+
+#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << (bits)) - 1))
+
+#define PAGEMAP_PRESENT(x)     (_BITS(x, 63, 1))
+#define PAGEMAP_SWAPPED(x)     (_BITS(x, 62, 1))
+#define PAGEMAP_SHIFT(x)       (_BITS(x, 55, 6))
+#define PAGEMAP_PFN(x)         (_BITS(x, 0, 55))
+#define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
+#define PAGEMAP_SWAP_TYPE(x)   (_BITS(x, 0,  5))
+
+static bool ReadData(int fd, unsigned long place, uint64_t *data) {
+  if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) {
+    return false;
+  }
+  if (read(fd, (void*)data, sizeof(uint64_t)) != (ssize_t)sizeof(uint64_t)) {
+    return false;
+  }
+  return true;
+}
+
+size_t GetPssBytes() {
+  FILE* maps = fopen("/proc/self/maps", "r");
+  assert(maps != NULL);
+
+  int pagecount_fd = open("/proc/kpagecount", O_RDONLY);
+  assert(pagecount_fd >= 0);
+
+  int pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
+  assert(pagemap_fd >= 0);
+
+  char line[4096];
+  size_t total_pss = 0;
+  int pagesize = getpagesize();
+  while (fgets(line, sizeof(line), maps)) {
+    uintptr_t start, end;
+    if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " ", &start, &end) != 2) {
+      total_pss = 0;
+      break;
+    }
+    for (size_t page = start/pagesize; page < end/pagesize; page++) {
+      uint64_t data;
+      if (ReadData(pagemap_fd, page, &data)) {
+        if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) {
+          uint64_t count;
+          if (ReadData(pagecount_fd, PAGEMAP_PFN(data), &count)) {
+            total_pss += (count >= 1) ? pagesize / count : 0;
+          }
+        }
+      }
+    }
+  }
+
+  fclose(maps);
+
+  close(pagecount_fd);
+  close(pagemap_fd);
+
+  return total_pss;
+}
diff --git a/libbacktrace/GetPss.h b/libbacktrace/GetPss.h
new file mode 100644
index 0000000..787c33d
--- /dev/null
+++ b/libbacktrace/GetPss.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 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_GET_PSS_H
+#define _LIBBACKTRACE_GET_PSS_H
+
+size_t GetPssBytes();
+
+#endif // _LIBBACKTRACE_GET_PSS_H
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
old mode 100644
new mode 100755
index 17b71b9..b176aaf
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "libbacktrace"
-
 #include <sys/types.h>
+#include <ucontext.h>
 
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
@@ -24,30 +23,11 @@
 #define UNW_LOCAL_ONLY
 #include <libunwind.h>
 
+#include "BacktraceLog.h"
+#include "BacktraceThread.h"
 #include "UnwindCurrent.h"
 #include "UnwindMap.h"
 
-// Define the ucontext_t structures needed for each supported arch.
-#if defined(__arm__)
-  // The current version of the <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;
-#elif defined(__i386__)
-  #include <asm/sigcontext.h>
-  #include <asm/ucontext.h>
-  typedef struct ucontext ucontext_t;
-#elif !defined(__mips__) && !defined(__aarch64__)
-  #error Unsupported architecture.
-#endif
-
 //-------------------------------------------------------------------------
 // UnwindCurrent functions.
 //-------------------------------------------------------------------------
@@ -57,13 +37,43 @@
 UnwindCurrent::~UnwindCurrent() {
 }
 
-bool UnwindCurrent::Unwind(size_t num_ignore_frames) {
-  int ret = unw_getcontext(&context_);
-  if (ret < 0) {
-    BACK_LOGW("unw_getcontext failed %d", ret);
-    return false;
+bool UnwindCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (!ucontext) {
+    int ret = unw_getcontext(&context_);
+    if (ret < 0) {
+      BACK_LOGW("unw_getcontext failed %d", ret);
+      return false;
+    }
   }
-  return UnwindFromContext(num_ignore_frames, true);
+  else {
+    GetUnwContextFromUcontext(ucontext);
+  }
+  return UnwindFromContext(num_ignore_frames, false);
+}
+
+void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) {
+  unw_tdep_context_t* unw_context = reinterpret_cast<unw_tdep_context_t*>(&context_);
+
+#if defined(__arm__)
+  unw_context->regs[0] = ucontext->uc_mcontext.arm_r0;
+  unw_context->regs[1] = ucontext->uc_mcontext.arm_r1;
+  unw_context->regs[2] = ucontext->uc_mcontext.arm_r2;
+  unw_context->regs[3] = ucontext->uc_mcontext.arm_r3;
+  unw_context->regs[4] = ucontext->uc_mcontext.arm_r4;
+  unw_context->regs[5] = ucontext->uc_mcontext.arm_r5;
+  unw_context->regs[6] = ucontext->uc_mcontext.arm_r6;
+  unw_context->regs[7] = ucontext->uc_mcontext.arm_r7;
+  unw_context->regs[8] = ucontext->uc_mcontext.arm_r8;
+  unw_context->regs[9] = ucontext->uc_mcontext.arm_r9;
+  unw_context->regs[10] = ucontext->uc_mcontext.arm_r10;
+  unw_context->regs[11] = ucontext->uc_mcontext.arm_fp;
+  unw_context->regs[12] = ucontext->uc_mcontext.arm_ip;
+  unw_context->regs[13] = ucontext->uc_mcontext.arm_sp;
+  unw_context->regs[14] = ucontext->uc_mcontext.arm_lr;
+  unw_context->regs[15] = ucontext->uc_mcontext.arm_pc;
+#else
+  unw_context->uc_mcontext = ucontext->uc_mcontext;
+#endif
 }
 
 std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
@@ -78,12 +88,14 @@
   return "";
 }
 
-bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) {
+bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool within_handler) {
   // 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) {
-    BACK_LOGW("unw_init_local failed %d", ret);
+    if (!within_handler) {
+      BACK_LOGW("unw_init_local failed %d", ret);
+    }
     delete cursor;
     return false;
   }
@@ -95,13 +107,17 @@
     unw_word_t pc;
     ret = unw_get_reg(cursor, UNW_REG_IP, &pc);
     if (ret < 0) {
-      BACK_LOGW("Failed to read IP %d", ret);
+      if (!within_handler) {
+        BACK_LOGW("Failed to read IP %d", ret);
+      }
       break;
     }
     unw_word_t sp;
     ret = unw_get_reg(cursor, UNW_REG_SP, &sp);
     if (ret < 0) {
-      BACK_LOGW("Failed to read SP %d", ret);
+      if (!within_handler) {
+        BACK_LOGW("Failed to read SP %d", ret);
+      }
       break;
     }
 
@@ -119,7 +135,7 @@
         prev->stack_size = frame->sp - prev->sp;
       }
 
-      if (resolve) {
+      if (!within_handler) {
         frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
         frame->map = FindMap(frame->pc);
       } else {
@@ -137,47 +153,6 @@
   return true;
 }
 
-void UnwindCurrent::ExtractContext(void* sigcontext) {
-  unw_tdep_context_t* context = reinterpret_cast<unw_tdep_context_t*>(&context_);
-  const ucontext_t* uc = reinterpret_cast<const ucontext_t*>(sigcontext);
-
-#if defined(__arm__)
-  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__) || defined(__i386__)
-  context->uc_mcontext = uc->uc_mcontext;
-#endif
-}
-
-//-------------------------------------------------------------------------
-// UnwindThread functions.
-//-------------------------------------------------------------------------
-UnwindThread::UnwindThread() {
-}
-
-UnwindThread::~UnwindThread() {
-}
-
-void UnwindThread::ThreadUnwind(
-    siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) {
-  ExtractContext(sigcontext);
-  UnwindFromContext(num_ignore_frames, false);
-}
-
 //-------------------------------------------------------------------------
 // C++ object creation function.
 //-------------------------------------------------------------------------
@@ -186,6 +161,5 @@
 }
 
 Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) {
-  UnwindThread* thread_obj = new UnwindThread();
-  return new BacktraceThread(thread_obj, thread_obj, tid, map);
+  return new BacktraceThread(new UnwindCurrent(), tid, map);
 }
diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h
index acce110..2375e6e 100644
--- a/libbacktrace/UnwindCurrent.h
+++ b/libbacktrace/UnwindCurrent.h
@@ -20,7 +20,6 @@
 #include <string>
 
 #include "BacktraceImpl.h"
-#include "BacktraceThread.h"
 
 #define UNW_LOCAL_ONLY
 #include <libunwind.h>
@@ -30,25 +29,16 @@
   UnwindCurrent();
   virtual ~UnwindCurrent();
 
-  virtual bool Unwind(size_t num_ignore_frames);
+  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
 
   virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
 
-  bool UnwindFromContext(size_t num_ignore_frames, bool resolve);
+  bool UnwindFromContext(size_t num_ignore_frames, bool within_handler);
 
-  void ExtractContext(void* sigcontext);
+  void GetUnwContextFromUcontext(const ucontext_t* context);
 
 protected:
   unw_context_t context_;
 };
 
-class UnwindThread : public UnwindCurrent, public BacktraceThreadInterface {
-public:
-  UnwindThread();
-  virtual ~UnwindThread();
-
-  virtual void ThreadUnwind(
-      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
-};
-
 #endif // _LIBBACKTRACE_UNWIND_CURRENT_H
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 03bb192..387d768 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "libbacktrace"
-
 #include <pthread.h>
+#include <stdlib.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -24,6 +23,7 @@
 
 #include <libunwind.h>
 
+#include "BacktraceLog.h"
 #include "UnwindMap.h"
 
 //-------------------------------------------------------------------------
@@ -32,57 +32,21 @@
 // only update the local address space once, and keep a reference count
 // of maps using the same map cursor.
 //-------------------------------------------------------------------------
-static pthread_mutex_t g_map_mutex = PTHREAD_MUTEX_INITIALIZER;
-static unw_map_cursor_t g_map_cursor;
-static int g_map_references = 0;
-
 UnwindMap::UnwindMap(pid_t pid) : BacktraceMap(pid) {
-  map_cursor_.map_list = NULL;
 }
 
 UnwindMap::~UnwindMap() {
-  if (pid_ == getpid()) {
-    pthread_mutex_lock(&g_map_mutex);
-    if (--g_map_references == 0) {
-      // Clear the local address space map.
-      unw_map_set(unw_local_addr_space, NULL);
-      unw_map_cursor_destroy(&map_cursor_);
-    }
-    pthread_mutex_unlock(&g_map_mutex);
-  } else {
-    unw_map_cursor_destroy(&map_cursor_);
-  }
+  unw_map_cursor_destroy(&map_cursor_);
+  unw_map_cursor_clear(&map_cursor_);
 }
 
-bool UnwindMap::Build() {
-  bool return_value = true;
-  if (pid_ == getpid()) {
-    pthread_mutex_lock(&g_map_mutex);
-    if (g_map_references == 0) {
-      return_value = (unw_map_cursor_create(&map_cursor_, pid_) == 0);
-      if (return_value) {
-        // Set the local address space to this cursor map.
-        unw_map_set(unw_local_addr_space, &map_cursor_);
-        g_map_references = 1;
-        g_map_cursor = map_cursor_;
-      }
-    } else {
-      g_map_references++;
-      map_cursor_ = g_map_cursor;
-    }
-    pthread_mutex_unlock(&g_map_mutex);
-  } else {
-    return_value = (unw_map_cursor_create(&map_cursor_, pid_) == 0);
-  }
-
-  if (!return_value)
-    return false;
-
+bool UnwindMap::GenerateMap() {
   // Use the map_cursor information to construct the BacktraceMap data
   // rather than reparsing /proc/self/maps.
   unw_map_cursor_reset(&map_cursor_);
+
   unw_map_t unw_map;
-  while (unw_map_cursor_get(&map_cursor_, &unw_map)) {
+  while (unw_map_cursor_get_next(&map_cursor_, &unw_map)) {
     backtrace_map_t map;
 
     map.start = unw_map.start;
@@ -97,11 +61,86 @@
   return true;
 }
 
+bool UnwindMap::Build() {
+  return (unw_map_cursor_create(&map_cursor_, pid_) == 0) && GenerateMap();
+}
+
+UnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) {
+}
+
+UnwindMapLocal::~UnwindMapLocal() {
+  if (map_created_) {
+    unw_map_local_destroy();
+    unw_map_cursor_clear(&map_cursor_);
+  }
+}
+
+bool UnwindMapLocal::GenerateMap() {
+  // It's possible for the map to be regenerated while this loop is occurring.
+  // If that happens, get the map again, but only try at most three times
+  // before giving up.
+  for (int i = 0; i < 3; i++) {
+    maps_.clear();
+
+    unw_map_local_cursor_get(&map_cursor_);
+
+    unw_map_t unw_map;
+    int ret;
+    while ((ret = unw_map_local_cursor_get_next(&map_cursor_, &unw_map)) > 0) {
+      backtrace_map_t map;
+
+      map.start = unw_map.start;
+      map.end = unw_map.end;
+      map.flags = unw_map.flags;
+      map.name = unw_map.path;
+
+      free(unw_map.path);
+
+      // The maps are in descending order, but we want them in ascending order.
+      maps_.push_front(map);
+    }
+    // Check to see if the map changed while getting the data.
+    if (ret != -UNW_EINVAL) {
+      return true;
+    }
+  }
+
+  BACK_LOGW("Unable to generate the map.");
+  return false;
+}
+
+bool UnwindMapLocal::Build() {
+  return (map_created_ = (unw_map_local_create() == 0)) && GenerateMap();;
+}
+
+const backtrace_map_t* UnwindMapLocal::Find(uintptr_t addr) {
+  const backtrace_map_t* map = BacktraceMap::Find(addr);
+  if (!map) {
+    // Check to see if the underlying map changed and regenerate the map
+    // if it did.
+    if (unw_map_local_cursor_valid(&map_cursor_) < 0) {
+      if (GenerateMap()) {
+        map = BacktraceMap::Find(addr);
+      }
+    }
+  }
+  return map;
+}
+
 //-------------------------------------------------------------------------
 // BacktraceMap create function.
 //-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::Create(pid_t pid) {
-  BacktraceMap* map = new UnwindMap(pid);
+BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
+  BacktraceMap* map;
+
+  if (uncached) {
+    // Force use of the base class to parse the maps when this call is made.
+    map = new BacktraceMap(pid);
+  } else if (pid == getpid()) {
+    map = new UnwindMapLocal();
+  } else {
+    map = new UnwindMap(pid);
+  }
   if (!map->Build()) {
     delete map;
     return NULL;
diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h
index 5a874e8..2fdb29f 100644
--- a/libbacktrace/UnwindMap.h
+++ b/libbacktrace/UnwindMap.h
@@ -32,8 +32,25 @@
 
   unw_map_cursor_t* GetMapCursor() { return &map_cursor_; }
 
-private:
+protected:
+  virtual bool GenerateMap();
+
   unw_map_cursor_t map_cursor_;
 };
 
+class UnwindMapLocal : public UnwindMap {
+public:
+  UnwindMapLocal();
+  virtual ~UnwindMapLocal();
+
+  virtual bool Build();
+
+  virtual const backtrace_map_t* Find(uintptr_t addr);
+
+protected:
+  virtual bool GenerateMap();
+
+  bool map_created_;
+};
+
 #endif // _LIBBACKTRACE_UNWIND_MAP_H
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index 732dae8..7ba8775 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "libbacktrace"
-
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
 #include <sys/types.h>
 #include <string.h>
+#include <ucontext.h>
 
 #include <libunwind.h>
 #include <libunwind-ptrace.h>
 
+#include "BacktraceLog.h"
 #include "UnwindMap.h"
 #include "UnwindPtrace.h"
 
@@ -46,7 +46,12 @@
   }
 }
 
-bool UnwindPtrace::Unwind(size_t num_ignore_frames) {
+bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+  if (ucontext) {
+    BACK_LOGW("Unwinding from a specified context not supported yet.");
+    return false;
+  }
+
   addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
   if (!addr_space_) {
     BACK_LOGW("unw_create_addr_space failed.");
diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h
index 1e82117..2fb7967 100644
--- a/libbacktrace/UnwindPtrace.h
+++ b/libbacktrace/UnwindPtrace.h
@@ -28,7 +28,7 @@
   UnwindPtrace();
   virtual ~UnwindPtrace();
 
-  virtual bool Unwind(size_t num_ignore_frames);
+  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
 
   virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
 
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 23eaf92..ed6b211 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -16,9 +16,10 @@
 
 #include <dirent.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <pthread.h>
 #include <signal.h>
-#include <stdbool.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -32,9 +33,13 @@
 #include <backtrace/BacktraceMap.h>
 #include <UniquePtr.h>
 
+// For the THREAD_SIGNAL definition.
+#include "BacktraceThread.h"
+
 #include <cutils/atomic.h>
 #include <gtest/gtest.h>
 
+#include <algorithm>
 #include <vector>
 
 #include "thread_utils.h"
@@ -287,7 +292,7 @@
   pid_t pid;
   if ((pid = fork()) == 0) {
     ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
-    exit(1);
+    _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyLevelDump);
 
@@ -300,7 +305,7 @@
   pid_t pid;
   if ((pid = fork()) == 0) {
     ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
-    exit(1);
+    _exit(1);
   }
 
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, true, ReadyLevelBacktrace, VerifyLevelDump);
@@ -314,7 +319,7 @@
   pid_t pid;
   if ((pid = fork()) == 0) {
     ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0);
-    exit(1);
+    _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyMaxBacktrace, VerifyMaxDump);
 
@@ -339,7 +344,7 @@
   pid_t pid;
   if ((pid = fork()) == 0) {
     ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
-    exit(1);
+    _exit(1);
   }
   VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, false, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
 
@@ -384,7 +389,7 @@
       ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, NULL) == 0);
     }
     ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
-    exit(1);
+    _exit(1);
   }
 
   // Check to see that all of the threads are running before unwinding.
@@ -458,9 +463,15 @@
   // Wait up to 2 seconds for the tid to be set.
   ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
 
+  // Make sure that the thread signal used is not visible when compiled for
+  // the target.
+#if !defined(__GLIBC__)
+  ASSERT_LT(THREAD_SIGNAL, SIGRTMIN);
+#endif
+
   // Save the current signal action and make sure it is restored afterwards.
   struct sigaction cur_action;
-  ASSERT_TRUE(sigaction(SIGURG, NULL, &cur_action) == 0);
+  ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &cur_action) == 0);
 
   UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(backtrace.get() != NULL);
@@ -473,7 +484,7 @@
 
   // Verify that the old action was restored.
   struct sigaction new_action;
-  ASSERT_TRUE(sigaction(SIGURG, NULL, &new_action) == 0);
+  ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &new_action) == 0);
   EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction);
   EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
 }
@@ -604,6 +615,49 @@
   }
 }
 
+TEST(libbacktrace, thread_multiple_dump_same_thread) {
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+  thread_t runner;
+  runner.tid = 0;
+  runner.state = 0;
+  ASSERT_TRUE(pthread_create(&runner.threadId, &attr, ThreadMaxRun, &runner) == 0);
+
+  // Wait for tids to be set.
+  ASSERT_TRUE(WaitForNonZero(&runner.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;
+  // Dump the same thread NUM_THREADS simultaneously.
+  std::vector<dump_thread_t> dumpers(NUM_THREADS);
+  for (size_t i = 0; i < NUM_THREADS; i++) {
+    dumpers[i].thread.tid = runner.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, 100));
+
+    ASSERT_TRUE(dumpers[i].backtrace != NULL);
+    VerifyMaxDump(dumpers[i].backtrace);
+
+    delete dumpers[i].backtrace;
+    dumpers[i].backtrace = NULL;
+  }
+
+  // Tell the runner thread to exit its infinite loop.
+  android_atomic_acquire_store(0, &runner.state);
+}
+
 // This test is for UnwindMaps that should share the same map cursor when
 // multiple maps are created for the current process at the same time.
 TEST(libbacktrace, simultaneous_maps) {
@@ -693,3 +747,136 @@
 #endif
             backtrace->FormatFrameData(&frame));
 }
+
+struct map_test_t {
+  uintptr_t start;
+  uintptr_t end;
+};
+
+bool map_sort(map_test_t i, map_test_t j) {
+  return i.start < j.start;
+}
+
+static void VerifyMap(pid_t pid) {
+  char buffer[4096];
+  snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid);
+
+  FILE* map_file = fopen(buffer, "r");
+  ASSERT_TRUE(map_file != NULL);
+  std::vector<map_test_t> test_maps;
+  while (fgets(buffer, sizeof(buffer), map_file)) {
+    map_test_t map;
+    ASSERT_EQ(2, sscanf(buffer, "%" SCNxPTR "-%" SCNxPTR " ", &map.start, &map.end));
+    test_maps.push_back(map);
+  }
+  fclose(map_file);
+  std::sort(test_maps.begin(), test_maps.end(), map_sort);
+
+  UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
+
+  // Basic test that verifies that the map is in the expected order.
+  std::vector<map_test_t>::const_iterator test_it = test_maps.begin();
+  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
+    ASSERT_TRUE(test_it != test_maps.end());
+    ASSERT_EQ(test_it->start, it->start);
+    ASSERT_EQ(test_it->end, it->end);
+    ++test_it;
+  }
+  ASSERT_TRUE(test_it == test_maps.end());
+}
+
+TEST(libbacktrace, verify_map_remote) {
+  pid_t pid;
+
+  if ((pid = fork()) == 0) {
+    while (true) {
+    }
+    _exit(0);
+  }
+  ASSERT_LT(0, pid);
+
+  ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+
+  // Wait for the process to get to a stopping point.
+  WaitForStop(pid);
+
+  // The maps should match exactly since the forked process has been paused.
+  VerifyMap(pid);
+
+  ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+  kill(pid, SIGKILL);
+  ASSERT_EQ(waitpid(pid, NULL, 0), pid);
+}
+
+#if defined(ENABLE_PSS_TESTS)
+#include "GetPss.h"
+
+#define MAX_LEAK_BYTES 32*1024UL
+
+static void CheckForLeak(pid_t pid, pid_t tid) {
+  // Do a few runs to get the PSS stable.
+  for (size_t i = 0; i < 100; i++) {
+    Backtrace* backtrace = Backtrace::Create(pid, tid);
+    ASSERT_TRUE(backtrace != NULL);
+    ASSERT_TRUE(backtrace->Unwind(0));
+    delete backtrace;
+  }
+  size_t stable_pss = GetPssBytes();
+
+  // Loop enough that even a small leak should be detectable.
+  for (size_t i = 0; i < 4096; i++) {
+    Backtrace* backtrace = Backtrace::Create(pid, tid);
+    ASSERT_TRUE(backtrace != NULL);
+    ASSERT_TRUE(backtrace->Unwind(0));
+    delete backtrace;
+  }
+  size_t new_pss = GetPssBytes();
+  size_t abs_diff = (new_pss > stable_pss) ? new_pss - stable_pss : stable_pss - new_pss;
+  // As long as the new pss is within a certain amount, consider everything okay.
+  ASSERT_LE(abs_diff, MAX_LEAK_BYTES);
+}
+
+TEST(libbacktrace, check_for_leak_local) {
+  CheckForLeak(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD);
+}
+
+TEST(libbacktrace, check_for_leak_local_thread) {
+  thread_t thread_data = { 0, 0, 0 };
+  pthread_t thread;
+  ASSERT_TRUE(pthread_create(&thread, NULL, ThreadLevelRun, &thread_data) == 0);
+
+  // Wait up to 2 seconds for the tid to be set.
+  ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
+
+  CheckForLeak(BACKTRACE_CURRENT_PROCESS, thread_data.tid);
+
+  // Tell the thread to exit its infinite loop.
+  android_atomic_acquire_store(0, &thread_data.state);
+
+  ASSERT_TRUE(pthread_join(thread, NULL) == 0);
+}
+
+TEST(libbacktrace, check_for_leak_remote) {
+  pid_t pid;
+
+  if ((pid = fork()) == 0) {
+    while (true) {
+    }
+    _exit(0);
+  }
+  ASSERT_LT(0, pid);
+
+  ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+
+  // Wait for the process to get to a stopping point.
+  WaitForStop(pid);
+
+  CheckForLeak(pid, BACKTRACE_CURRENT_THREAD);
+
+  ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+  kill(pid, SIGKILL);
+  ASSERT_EQ(waitpid(pid, NULL, 0), pid);
+}
+#endif
diff --git a/libbacktrace/map_info.c b/libbacktrace/map_info.c
new file mode 100644
index 0000000..073b24a
--- /dev/null
+++ b/libbacktrace/map_info.c
@@ -0,0 +1,173 @@
+/*
+ * 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <log/log.h>
+#include <sys/time.h>
+
+#include <backtrace/backtrace.h>
+
+#if defined(__APPLE__)
+
+// Mac OS vmmap(1) output:
+// __TEXT                 0009f000-000a1000 [    8K     8K] r-x/rwx SM=COW  /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
+// 012345678901234567890123456789012345678901234567890123456789
+// 0         1         2         3         4         5
+static backtrace_map_info_t* parse_vmmap_line(const char* line) {
+  unsigned long int start;
+  unsigned long int end;
+  char permissions[4];
+  int name_pos;
+  if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c  %n",
+             &start, &end, permissions, &name_pos) != 3) {
+    return NULL;
+  }
+
+  const char* name = line + name_pos;
+  size_t name_len = strlen(name);
+
+  backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len);
+  if (mi != NULL) {
+    mi->start = start;
+    mi->end = end;
+    mi->is_readable = permissions[0] == 'r';
+    mi->is_writable = permissions[1] == 'w';
+    mi->is_executable = permissions[2] == 'x';
+    memcpy(mi->name, name, name_len);
+    mi->name[name_len - 1] = '\0';
+    ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
+          "is_readable=%d, is_writable=%d is_executable=%d, name=%s",
+          mi->start, mi->end,
+          mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
+  }
+  return mi;
+}
+
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid) {
+  char cmd[1024];
+  if (pid < 0) {
+    pid = getpid();
+  }
+  snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid);
+  FILE* fp = popen(cmd, "r");
+  if (fp == NULL) {
+    return NULL;
+  }
+
+  char line[1024];
+  backtrace_map_info_t* milist = NULL;
+  while (fgets(line, sizeof(line), fp) != NULL) {
+    backtrace_map_info_t* mi = parse_vmmap_line(line);
+    if (mi != NULL) {
+      mi->next = milist;
+      milist = mi;
+    }
+  }
+  pclose(fp);
+  return milist;
+}
+
+#else
+
+// Linux /proc/<pid>/maps lines:
+// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so\n
+// 012345678901234567890123456789012345678901234567890123456789
+// 0         1         2         3         4         5
+static backtrace_map_info_t* parse_maps_line(const char* line)
+{
+  unsigned long int start;
+  unsigned long int end;
+  char permissions[5];
+  int name_pos;
+  if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n", &start, &end,
+             permissions, &name_pos) != 3) {
+    return NULL;
+  }
+
+  while (isspace(line[name_pos])) {
+    name_pos += 1;
+  }
+  const char* name = line + name_pos;
+  size_t name_len = strlen(name);
+  if (name_len && name[name_len - 1] == '\n') {
+    name_len -= 1;
+  }
+
+  backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len + 1);
+  if (mi) {
+    mi->start = start;
+    mi->end = end;
+    mi->is_readable = strlen(permissions) == 4 && permissions[0] == 'r';
+    mi->is_writable = strlen(permissions) == 4 && permissions[1] == 'w';
+    mi->is_executable = strlen(permissions) == 4 && permissions[2] == 'x';
+    memcpy(mi->name, name, name_len);
+    mi->name[name_len] = '\0';
+    ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
+          "is_readable=%d, is_writable=%d, is_executable=%d, name=%s",
+          mi->start, mi->end,
+          mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
+  }
+  return mi;
+}
+
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid) {
+  char path[PATH_MAX];
+  char line[1024];
+  FILE* fp;
+  backtrace_map_info_t* milist = NULL;
+
+  if (tid < 0) {
+    tid = getpid();
+  }
+  snprintf(path, PATH_MAX, "/proc/%d/maps", tid);
+  fp = fopen(path, "r");
+  if (fp) {
+    while(fgets(line, sizeof(line), fp)) {
+      backtrace_map_info_t* mi = parse_maps_line(line);
+      if (mi) {
+        mi->next = milist;
+        milist = mi;
+      }
+    }
+    fclose(fp);
+  }
+  return milist;
+}
+
+#endif
+
+void backtrace_destroy_map_info_list(backtrace_map_info_t* milist) {
+  while (milist) {
+    backtrace_map_info_t* next = milist->next;
+    free(milist);
+    milist = next;
+  }
+}
+
+const backtrace_map_info_t* backtrace_find_map_info(
+    const backtrace_map_info_t* milist, uintptr_t addr) {
+  const backtrace_map_info_t* mi = milist;
+  while (mi && !(addr >= mi->start && addr < mi->end)) {
+    mi = mi->next;
+  }
+  return mi;
+}