am e93a0517: Set GID required to write, media_rw mount point.

* commit 'e93a0517f4c88310066ac39c6b268ebfcceef44e':
  Set GID required to write, media_rw mount point.
diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c
index 20c08d2..fa7fd98 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.c
@@ -55,13 +55,13 @@
 void framebuffer_service(int fd, void *cookie)
 {
     struct fbinfo fbinfo;
-    unsigned int i;
+    unsigned int i, bsize;
     char buf[640];
     int fd_screencap;
     int w, h, f;
     int fds[2];
 
-    if (pipe(fds) < 0) goto done;
+    if (pipe(fds) < 0) goto pipefail;
 
     pid_t pid = fork();
     if (pid < 0) goto done;
@@ -164,17 +164,19 @@
     if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done;
 
     /* write data */
-    for(i = 0; i < fbinfo.size; i += sizeof(buf)) {
-      if(readx(fd_screencap, buf, sizeof(buf))) goto done;
-      if(writex(fd, buf, sizeof(buf))) goto done;
+    for(i = 0; i < fbinfo.size; i += bsize) {
+      bsize = sizeof(buf);
+      if (i + bsize > fbinfo.size)
+        bsize = fbinfo.size - i;
+      if(readx(fd_screencap, buf, bsize)) goto done;
+      if(writex(fd, buf, bsize)) goto done;
     }
-    if(readx(fd_screencap, buf, fbinfo.size % sizeof(buf))) goto done;
-    if(writex(fd, buf, fbinfo.size % sizeof(buf))) goto done;
 
 done:
     TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
 
     close(fds[0]);
     close(fds[1]);
+pipefail:
     close(fd);
 }
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 68bb232..19b3022 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -155,7 +155,10 @@
 #define VENDOR_ID_QISDA         0x1D45
 // ECS's USB Vendor ID
 #define VENDOR_ID_ECS           0x03fc
-
+// MSI's USB Vendor ID
+#define VENDOR_ID_MSI           0x0DB0
+// Wacom's USB Vendor ID
+#define VENDOR_ID_WACOM         0x0531
 
 /** built-in vendor list */
 int builtInVendorIds[] = {
@@ -219,6 +222,8 @@
     VENDOR_ID_NOOK,
     VENDOR_ID_QISDA,
     VENDOR_ID_ECS,
+    VENDOR_ID_MSI,
+    VENDOR_ID_WACOM,
 };
 
 #define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 8621e9c..2fe7c7a 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -24,11 +24,11 @@
 endif # ARCH_ARM_HAVE_VFP_D32
 
 LOCAL_SHARED_LIBRARIES := \
+	libbacktrace \
+	libc \
 	libcutils \
 	liblog \
-	libc \
-	libcorkscrew \
-	libselinux
+	libselinux \
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c
index 67e3028..6bcd07e 100644
--- a/debuggerd/arm/machine.c
+++ b/debuggerd/arm/machine.c
@@ -42,7 +42,7 @@
 #endif
 #endif
 
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) {
+static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
     char code_buffer[64];       /* actual 8+1+((8+1)*4) + 1 == 45 */
     char ascii_buffer[32];      /* actual 16 + 1 == 17 */
     uintptr_t p, end;
@@ -102,7 +102,7 @@
             p += 4;
         }
         *asc_out = '\0';
-        _LOG(log, scopeFlags, "    %s %s\n", code_buffer, ascii_buffer);
+        _LOG(log, scope_flags, "    %s %s\n", code_buffer, ascii_buffer);
     }
 }
 
@@ -110,16 +110,13 @@
  * If configured to do so, dump memory around *all* registers
  * for the crashing thread.
  */
-void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)),
-        log_t* log, pid_t tid, bool at_fault) {
+void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
     struct pt_regs regs;
     if(ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
         return;
     }
 
-    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
-
-    if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) {
+    if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
         static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
 
         for (int reg = 0; reg < 14; reg++) {
@@ -134,39 +131,36 @@
                 continue;
             }
 
-            _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
-            dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE);
+            _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
+            dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
         }
     }
 
     /* explicitly allow upload of code dump logging */
-    _LOG(log, scopeFlags, "\ncode around pc:\n");
-    dump_memory(log, tid, (uintptr_t)regs.ARM_pc, scopeFlags);
+    _LOG(log, scope_flags, "\ncode around pc:\n");
+    dump_memory(log, tid, (uintptr_t)regs.ARM_pc, scope_flags);
 
     if (regs.ARM_pc != regs.ARM_lr) {
-        _LOG(log, scopeFlags, "\ncode around lr:\n");
-        dump_memory(log, tid, (uintptr_t)regs.ARM_lr, scopeFlags);
+        _LOG(log, scope_flags, "\ncode around lr:\n");
+        dump_memory(log, tid, (uintptr_t)regs.ARM_lr, scope_flags);
     }
 }
 
-void dump_registers(const ptrace_context_t* context __attribute((unused)),
-        log_t* log, pid_t tid, bool at_fault)
+void dump_registers(log_t* log, pid_t tid, int scope_flags)
 {
     struct pt_regs r;
-    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
-
     if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-        _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
         return;
     }
 
-    _LOG(log, scopeFlags, "    r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
+    _LOG(log, scope_flags, "    r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
             (uint32_t)r.ARM_r0, (uint32_t)r.ARM_r1, (uint32_t)r.ARM_r2, (uint32_t)r.ARM_r3);
-    _LOG(log, scopeFlags, "    r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
+    _LOG(log, scope_flags, "    r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
             (uint32_t)r.ARM_r4, (uint32_t)r.ARM_r5, (uint32_t)r.ARM_r6, (uint32_t)r.ARM_r7);
-    _LOG(log, scopeFlags, "    r8 %08x  r9 %08x  sl %08x  fp %08x\n",
+    _LOG(log, scope_flags, "    r8 %08x  r9 %08x  sl %08x  fp %08x\n",
             (uint32_t)r.ARM_r8, (uint32_t)r.ARM_r9, (uint32_t)r.ARM_r10, (uint32_t)r.ARM_fp);
-    _LOG(log, scopeFlags, "    ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
+    _LOG(log, scope_flags, "    ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
             (uint32_t)r.ARM_ip, (uint32_t)r.ARM_sp, (uint32_t)r.ARM_lr,
             (uint32_t)r.ARM_pc, (uint32_t)r.ARM_cpsr);
 
@@ -175,14 +169,14 @@
     int i;
 
     if(ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
-        _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
         return;
     }
 
     for (i = 0; i < NUM_VFP_REGS; i += 2) {
-        _LOG(log, scopeFlags, "    d%-2d %016llx  d%-2d %016llx\n",
+        _LOG(log, scope_flags, "    d%-2d %016llx  d%-2d %016llx\n",
                 i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
     }
-    _LOG(log, scopeFlags, "    scr %08lx\n", vfp_regs.fpscr);
+    _LOG(log, scope_flags, "    scr %08lx\n", vfp_regs.fpscr);
 #endif
 }
diff --git a/debuggerd/backtrace.c b/debuggerd/backtrace.c
index f42f24c..6f82792 100644
--- a/debuggerd/backtrace.c
+++ b/debuggerd/backtrace.c
@@ -27,13 +27,11 @@
 #include <sys/types.h>
 #include <sys/ptrace.h>
 
-#include <corkscrew/backtrace.h>
+#include <backtrace/backtrace.h>
 
-#include "tombstone.h"
+#include "backtrace.h"
 #include "utility.h"
 
-#define STACK_DEPTH 32
-
 static void dump_process_header(log_t* log, pid_t pid) {
     char path[PATH_MAX];
     char procnamebuf[1024];
@@ -62,7 +60,7 @@
     _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
 }
 
-static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool attached,
+static void dump_thread(log_t* log, pid_t tid, bool attached,
         bool* detach_failed, int* total_sleep_time_usec) {
     char path[PATH_MAX];
     char threadnamebuf[1024];
@@ -91,20 +89,12 @@
 
     wait_for_stop(tid, total_sleep_time_usec);
 
-    backtrace_frame_t backtrace[STACK_DEPTH];
-    ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH);
-    if (frames <= 0) {
-        _LOG(log, SCOPE_AT_FAULT, "Could not obtain stack trace for thread.\n");
+    backtrace_t backtrace;
+    if (!backtrace_get_data(&backtrace, tid)) {
+        _LOG(log, SCOPE_AT_FAULT, "Could not create backtrace context.\n");
     } else {
-        backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
-        get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols);
-        for (size_t i = 0; i < (size_t)frames; i++) {
-            char line[MAX_BACKTRACE_LINE_LENGTH];
-            format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
-                    line, MAX_BACKTRACE_LINE_LENGTH);
-            _LOG(log, SCOPE_AT_FAULT, "  %s\n", line);
-        }
-        free_backtrace_symbols(backtrace_symbols, frames);
+        dump_backtrace_to_log(&backtrace, log, SCOPE_AT_FAULT, "  ");
+        backtrace_free_data(&backtrace);
     }
 
     if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
@@ -120,9 +110,8 @@
     log.amfd = amfd;
     log.quiet = true;
 
-    ptrace_context_t* context = load_ptrace_context(tid);
     dump_process_header(&log, pid);
-    dump_thread(&log, tid, context, true, detach_failed, total_sleep_time_usec);
+    dump_thread(&log, tid, true, detach_failed, total_sleep_time_usec);
 
     char task_path[64];
     snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
@@ -140,11 +129,19 @@
                 continue;
             }
 
-            dump_thread(&log, new_tid, context, false, detach_failed, total_sleep_time_usec);
+            dump_thread(&log, new_tid, false, detach_failed, total_sleep_time_usec);
         }
         closedir(d);
     }
 
     dump_process_footer(&log, pid);
-    free_ptrace_context(context);
+}
+
+void dump_backtrace_to_log(const backtrace_t* backtrace, 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));
+        _LOG(log, scope_flags, "%s%s\n", prefix, buf);
+    }
 }
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index c5c786a..9d61e6f 100644
--- a/debuggerd/backtrace.h
+++ b/debuggerd/backtrace.h
@@ -21,11 +21,17 @@
 #include <stdbool.h>
 #include <sys/types.h>
 
-#include <corkscrew/ptrace.h>
+#include <backtrace/backtrace.h>
+
+#include "utility.h"
 
 /* Dumps a backtrace using a format similar to what Dalvik uses so that the result
  * can be intermixed in a bug report. */
 void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
         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,
+        int scope_flags, const char* prefix);
+
 #endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/machine.h b/debuggerd/machine.h
index 1619dd3..2f1e201 100644
--- a/debuggerd/machine.h
+++ b/debuggerd/machine.h
@@ -17,15 +17,11 @@
 #ifndef _DEBUGGERD_MACHINE_H
 #define _DEBUGGERD_MACHINE_H
 
-#include <stddef.h>
-#include <stdbool.h>
 #include <sys/types.h>
 
-#include <corkscrew/ptrace.h>
-
 #include "utility.h"
 
-void dump_memory_and_code(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault);
-void dump_registers(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault);
+void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags);
+void dump_registers(log_t* log, pid_t tid, int scope_flags);
 
 #endif // _DEBUGGERD_MACHINE_H
diff --git a/debuggerd/mips/machine.c b/debuggerd/mips/machine.c
index 65fdf02..e06a50c 100644
--- a/debuggerd/mips/machine.c
+++ b/debuggerd/mips/machine.c
@@ -36,7 +36,7 @@
 
 #define R(x) ((unsigned int)(x))
 
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) {
+static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
     char code_buffer[64];       /* actual 8+1+((8+1)*4) + 1 == 45 */
     char ascii_buffer[32];      /* actual 16 + 1 == 17 */
     uintptr_t p, end;
@@ -92,7 +92,7 @@
             p += 4;
         }
         *asc_out = '\0';
-        _LOG(log, scopeFlags, "    %s %s\n", code_buffer, ascii_buffer);
+        _LOG(log, scope_flags, "    %s %s\n", code_buffer, ascii_buffer);
     }
 }
 
@@ -100,15 +100,13 @@
  * If configured to do so, dump memory around *all* registers
  * for the crashing thread.
  */
-void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)),
-        log_t* log, pid_t tid, bool at_fault) {
+void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
     pt_regs_mips_t r;
     if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
         return;
     }
 
-    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
-    if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) {
+    if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
         static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
 
         for (int reg = 0; reg < 32; reg++) {
@@ -130,50 +128,47 @@
                 continue;
             }
 
-            _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
-            dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE);
+            _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
+            dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
         }
     }
 
     unsigned int pc = R(r.cp0_epc);
     unsigned int ra = R(r.regs[31]);
 
-    _LOG(log, scopeFlags, "\ncode around pc:\n");
-    dump_memory(log, tid, (uintptr_t)pc, scopeFlags);
+    _LOG(log, scope_flags, "\ncode around pc:\n");
+    dump_memory(log, tid, (uintptr_t)pc, scope_flags);
 
     if (pc != ra) {
-        _LOG(log, scopeFlags, "\ncode around ra:\n");
-        dump_memory(log, tid, (uintptr_t)ra, scopeFlags);
+        _LOG(log, scope_flags, "\ncode around ra:\n");
+        dump_memory(log, tid, (uintptr_t)ra, scope_flags);
     }
 }
 
-void dump_registers(const ptrace_context_t* context __attribute((unused)),
-        log_t* log, pid_t tid, bool at_fault)
+void dump_registers(log_t* log, pid_t tid, int scope_flags)
 {
     pt_regs_mips_t r;
-    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
-
     if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-        _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
         return;
     }
 
-    _LOG(log, scopeFlags, " zr %08x  at %08x  v0 %08x  v1 %08x\n",
+    _LOG(log, scope_flags, " zr %08x  at %08x  v0 %08x  v1 %08x\n",
      R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
-    _LOG(log, scopeFlags, " a0 %08x  a1 %08x  a2 %08x  a3 %08x\n",
+    _LOG(log, scope_flags, " a0 %08x  a1 %08x  a2 %08x  a3 %08x\n",
      R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
-    _LOG(log, scopeFlags, " t0 %08x  t1 %08x  t2 %08x  t3 %08x\n",
+    _LOG(log, scope_flags, " t0 %08x  t1 %08x  t2 %08x  t3 %08x\n",
      R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
-    _LOG(log, scopeFlags, " t4 %08x  t5 %08x  t6 %08x  t7 %08x\n",
+    _LOG(log, scope_flags, " t4 %08x  t5 %08x  t6 %08x  t7 %08x\n",
      R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
-    _LOG(log, scopeFlags, " s0 %08x  s1 %08x  s2 %08x  s3 %08x\n",
+    _LOG(log, scope_flags, " s0 %08x  s1 %08x  s2 %08x  s3 %08x\n",
      R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
-    _LOG(log, scopeFlags, " s4 %08x  s5 %08x  s6 %08x  s7 %08x\n",
+    _LOG(log, scope_flags, " s4 %08x  s5 %08x  s6 %08x  s7 %08x\n",
      R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
-    _LOG(log, scopeFlags, " t8 %08x  t9 %08x  k0 %08x  k1 %08x\n",
+    _LOG(log, scope_flags, " t8 %08x  t9 %08x  k0 %08x  k1 %08x\n",
      R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
-    _LOG(log, scopeFlags, " gp %08x  sp %08x  s8 %08x  ra %08x\n",
+    _LOG(log, scope_flags, " gp %08x  sp %08x  s8 %08x  ra %08x\n",
      R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
-    _LOG(log, scopeFlags, " hi %08x  lo %08x bva %08x epc %08x\n",
+    _LOG(log, scope_flags, " hi %08x  lo %08x bva %08x epc %08x\n",
      R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
 }
diff --git a/debuggerd/tombstone.c b/debuggerd/tombstone.c
index 7009a8e..6fb2191 100644
--- a/debuggerd/tombstone.c
+++ b/debuggerd/tombstone.c
@@ -32,8 +32,7 @@
 #include <log/logger.h>
 #include <cutils/properties.h>
 
-#include <corkscrew/demangle.h>
-#include <corkscrew/backtrace.h>
+#include <backtrace/backtrace.h>
 
 #include <sys/socket.h>
 #include <linux/un.h>
@@ -42,9 +41,8 @@
 
 #include "machine.h"
 #include "tombstone.h"
-#include "utility.h"
+#include "backtrace.h"
 
-#define STACK_DEPTH 32
 #define STACK_WORDS 16
 
 #define MAX_TOMBSTONES  10
@@ -193,7 +191,7 @@
     }
 }
 
-static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, bool at_fault) {
+static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) {
     char path[64];
     char threadnamebuf[1024];
     char* threadname = NULL;
@@ -211,7 +209,7 @@
         }
     }
 
-    if (at_fault) {
+    if (IS_AT_FAULT(scope_flags)) {
         char procnamebuf[1024];
         char* procname = NULL;
 
@@ -230,64 +228,46 @@
     }
 }
 
-static void dump_backtrace(const ptrace_context_t* context __attribute((unused)),
-        log_t* log, pid_t tid __attribute((unused)), bool at_fault,
-        const backtrace_frame_t* backtrace, size_t frames) {
-    int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
-    _LOG(log, scopeFlags, "\nbacktrace:\n");
-
-    backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
-    get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols);
-    for (size_t i = 0; i < frames; i++) {
-        char line[MAX_BACKTRACE_LINE_LENGTH];
-        format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
-                line, MAX_BACKTRACE_LINE_LENGTH);
-        _LOG(log, scopeFlags, "    %s\n", line);
-    }
-    free_backtrace_symbols(backtrace_symbols, frames);
-}
-
-static void dump_stack_segment(const ptrace_context_t* context, log_t* log, pid_t tid,
-        int scopeFlags, uintptr_t* sp, size_t words, int label) {
+static void dump_stack_segment(const backtrace_t* backtrace, 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 (!try_get_word_ptrace(tid, *sp, &stack_content)) {
+        if (!backtrace_read_word(backtrace, *sp, &stack_content)) {
             break;
         }
 
-        const map_info_t* mi;
-        const symbol_t* symbol;
-        find_symbol_ptrace(context, stack_content, &mi, &symbol);
-
-        if (symbol) {
-            char* demangled_name = demangle_symbol_name(symbol->name);
-            const char* symbol_name = demangled_name ? demangled_name : symbol->name;
-            uint32_t offset = stack_content - (mi->start + symbol->start);
+        const char* map_name = backtrace_get_map_info(backtrace, 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) {
             if (!i && label >= 0) {
                 if (offset) {
-                    _LOG(log, scopeFlags, "    #%02d  %08x  %08x  %s (%s+%u)\n",
-                            label, *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
+                    _LOG(log, scope_flags, "    #%02d  %08x  %08x  %s (%s+%u)\n",
+                            label, *sp, stack_content, map_name, proc_name, offset);
                 } else {
-                    _LOG(log, scopeFlags, "    #%02d  %08x  %08x  %s (%s)\n",
-                            label, *sp, stack_content, mi ? mi->name : "", symbol_name);
+                    _LOG(log, scope_flags, "    #%02d  %08x  %08x  %s (%s)\n",
+                            label, *sp, stack_content, map_name, proc_name);
                 }
             } else {
                 if (offset) {
-                    _LOG(log, scopeFlags, "         %08x  %08x  %s (%s+%u)\n",
-                            *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
+                    _LOG(log, scope_flags, "         %08x  %08x  %s (%s+%u)\n",
+                            *sp, stack_content, map_name, proc_name, offset);
                 } else {
-                    _LOG(log, scopeFlags, "         %08x  %08x  %s (%s)\n",
-                            *sp, stack_content, mi ? mi->name : "", symbol_name);
+                    _LOG(log, scope_flags, "         %08x  %08x  %s (%s)\n",
+                            *sp, stack_content, map_name, proc_name);
                 }
             }
-            free(demangled_name);
+            free(proc_name);
         } else {
             if (!i && label >= 0) {
-                _LOG(log, scopeFlags, "    #%02d  %08x  %08x  %s\n",
-                        label, *sp, stack_content, mi ? mi->name : "");
+                _LOG(log, scope_flags, "    #%02d  %08x  %08x  %s\n",
+                        label, *sp, stack_content, map_name);
             } else {
-                _LOG(log, scopeFlags, "         %08x  %08x  %s\n",
-                        *sp, stack_content, mi ? mi->name : "");
+                _LOG(log, scope_flags, "         %08x  %08x  %s\n",
+                        *sp, stack_content, map_name);
             }
         }
 
@@ -295,45 +275,42 @@
     }
 }
 
-static void dump_stack(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault,
-        const backtrace_frame_t* backtrace, size_t frames) {
-    bool have_first = false;
-    size_t first, last;
-    for (size_t i = 0; i < frames; i++) {
-        if (backtrace[i].stack_top) {
-            if (!have_first) {
-                have_first = true;
-                first = i;
+static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags) {
+    size_t first = 0, last;
+    for (size_t i = 0; i < backtrace->num_frames; i++) {
+        if (backtrace->frames[i].sp) {
+            if (!first) {
+                first = i+1;
             }
             last = i;
         }
     }
-    if (!have_first) {
+    if (!first) {
         return;
     }
+    first--;
 
-    int scopeFlags = SCOPE_SENSITIVE | (at_fault ? SCOPE_AT_FAULT : 0);
-    _LOG(log, scopeFlags, "\nstack:\n");
+    scope_flags |= SCOPE_SENSITIVE;
 
     // Dump a few words before the first frame.
-    uintptr_t sp = backtrace[first].stack_top - STACK_WORDS * sizeof(uint32_t);
-    dump_stack_segment(context, log, tid, scopeFlags, &sp, STACK_WORDS, -1);
+    uintptr_t sp = backtrace->frames[first].sp - STACK_WORDS * sizeof(uint32_t);
+    dump_stack_segment(backtrace, 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.
     for (size_t i = first; i <= last; i++) {
-        const backtrace_frame_t* frame = &backtrace[i];
-        if (sp != frame->stack_top) {
-            _LOG(log, scopeFlags, "         ........  ........\n");
-            sp = frame->stack_top;
+        const backtrace_frame_data_t* frame = &backtrace->frames[i];
+        if (sp != frame->sp) {
+            _LOG(log, scope_flags, "         ........  ........\n");
+            sp = frame->sp;
         }
         if (i - first == 3) {
-            scopeFlags &= (~SCOPE_AT_FAULT);
+            scope_flags &= (~SCOPE_AT_FAULT);
         }
         if (i == last) {
-            dump_stack_segment(context, log, tid, scopeFlags, &sp, STACK_WORDS, i);
-            if (sp < frame->stack_top + frame->stack_size) {
-                _LOG(log, scopeFlags, "         ........  ........\n");
+            dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, i);
+            if (sp < frame->sp + frame->stack_size) {
+                _LOG(log, scope_flags, "         ........  ........\n");
             }
         } else {
             size_t words = frame->stack_size / sizeof(uint32_t);
@@ -342,39 +319,40 @@
             } else if (words > STACK_WORDS) {
                 words = STACK_WORDS;
             }
-            dump_stack_segment(context, log, tid, scopeFlags, &sp, words, i);
+            dump_stack_segment(backtrace, log, scope_flags, &sp, words, i);
         }
     }
 }
 
-static void dump_backtrace_and_stack(const ptrace_context_t* context, log_t* log, pid_t tid,
-        bool at_fault) {
-    backtrace_frame_t backtrace[STACK_DEPTH];
-    ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH);
-    if (frames > 0) {
-        dump_backtrace(context, log, tid, at_fault, backtrace, frames);
-        dump_stack(context, log, tid, at_fault, backtrace, frames);
+static void dump_backtrace_and_stack(const backtrace_t* backtrace, log_t* log,
+        int scope_flags) {
+    if (backtrace->num_frames) {
+        _LOG(log, scope_flags, "\nbacktrace:\n");
+        dump_backtrace_to_log(backtrace, log, scope_flags, "    ");
+
+        _LOG(log, scope_flags, "\nstack:\n");
+        dump_stack(backtrace, log, scope_flags);
     }
 }
 
-static void dump_map(log_t* log, map_info_t* m, const char* what, int scopeFlags) {
+static void dump_map(log_t* log, const backtrace_map_info_t* m, const char* what, int scope_flags) {
     if (m != NULL) {
-        _LOG(log, scopeFlags, "    %08x-%08x %c%c%c %s\n", m->start, m->end,
+        _LOG(log, scope_flags, "    %08x-%08x %c%c%c %s\n", m->start, m->end,
              m->is_readable ? 'r' : '-',
              m->is_writable ? 'w' : '-',
              m->is_executable ? 'x' : '-',
              m->name);
     } else {
-        _LOG(log, scopeFlags, "    (no %s)\n", what);
+        _LOG(log, scope_flags, "    (no %s)\n", what);
     }
 }
 
-static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault) {
-    int scopeFlags = SCOPE_SENSITIVE | (at_fault ? SCOPE_AT_FAULT : 0);
+static void dump_nearby_maps(const backtrace_map_info_t* map_info_list, log_t* log, pid_t tid, int scope_flags) {
+    scope_flags |= SCOPE_SENSITIVE;
     siginfo_t si;
     memset(&si, 0, sizeof(si));
     if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
-        _LOG(log, scopeFlags, "cannot get siginfo for %d: %s\n",
+        _LOG(log, scope_flags, "cannot get siginfo for %d: %s\n",
                 tid, strerror(errno));
         return;
     }
@@ -388,15 +366,15 @@
         return;
     }
 
-    _LOG(log, scopeFlags, "\nmemory map around fault addr %08x:\n", (int)si.si_addr);
+    _LOG(log, scope_flags, "\nmemory map around fault addr %08x:\n", (int)si.si_addr);
 
     /*
      * Search for a match, or for a hole where the match would be.  The list
      * is backward from the file content, so it starts at high addresses.
      */
-    map_info_t* map = context->map_info_list;
-    map_info_t *next = NULL;
-    map_info_t *prev = NULL;
+    const backtrace_map_info_t* map = map_info_list;
+    const backtrace_map_info_t* next = NULL;
+    const backtrace_map_info_t* prev = NULL;
     while (map != NULL) {
         if (addr >= map->start && addr < map->end) {
             next = map->next;
@@ -416,31 +394,31 @@
      * Show "next" then "match" then "prev" so that the addresses appear in
      * ascending order (like /proc/pid/maps).
      */
-    dump_map(log, next, "map below", scopeFlags);
-    dump_map(log, map, "map for address", scopeFlags);
-    dump_map(log, prev, "map above", scopeFlags);
+    dump_map(log, next, "map below", scope_flags);
+    dump_map(log, map, "map for address", scope_flags);
+    dump_map(log, prev, "map above", scope_flags);
 }
 
-static void dump_thread(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault,
+static void dump_thread(const backtrace_t* backtrace, log_t* log, int scope_flags,
         int* total_sleep_time_usec) {
-    wait_for_stop(tid, total_sleep_time_usec);
+    wait_for_stop(backtrace->tid, total_sleep_time_usec);
 
-    dump_registers(context, log, tid, at_fault);
-    dump_backtrace_and_stack(context, log, tid, at_fault);
-    if (at_fault) {
-        dump_memory_and_code(context, log, tid, at_fault);
-        dump_nearby_maps(context, log, tid, at_fault);
+    dump_registers(log, backtrace->tid, scope_flags);
+    dump_backtrace_and_stack(backtrace, 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);
     }
 }
 
 /* Return true if some thread is not detached cleanly */
-static bool dump_sibling_thread_report(const ptrace_context_t* context,
+static bool dump_sibling_thread_report(
         log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec) {
     char task_path[64];
     snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
 
     DIR* d = opendir(task_path);
-    /* Bail early if cannot open the task directory */
+    /* Bail early if the task directory cannot be opened */
     if (d == NULL) {
         XLOG("Cannot open /proc/%d/task\n", pid);
         return false;
@@ -467,8 +445,12 @@
         }
 
         _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
-        dump_thread_info(log, pid, new_tid, false);
-        dump_thread(context, log, new_tid, false, total_sleep_time_usec);
+        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_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));
@@ -624,7 +606,7 @@
     dump_log_file(log, pid, "/dev/log/main", tailOnly);
 }
 
-static void dump_abort_message(log_t* log, pid_t tid, uintptr_t address) {
+static void dump_abort_message(const backtrace_t* backtrace, log_t* log, uintptr_t address) {
   if (address == 0) {
     return;
   }
@@ -636,9 +618,10 @@
   char* p = &msg[0];
   while (p < &msg[sizeof(msg)]) {
     uint32_t data;
-    if (!try_get_word_ptrace(tid, address, &data)) {
+    if (!backtrace_read_word(backtrace, address, &data)) {
       break;
     }
+    data = 0;
     address += sizeof(uint32_t);
 
     if ((*p++ = (data >>  0) & 0xff) == 0) {
@@ -686,14 +669,17 @@
             "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
     dump_build_info(log);
     dump_revision_info(log);
-    dump_thread_info(log, pid, tid, true);
+    dump_thread_info(log, pid, tid, SCOPE_AT_FAULT);
     if (signal) {
         dump_fault_addr(log, tid, signal);
     }
-    dump_abort_message(log, tid, abort_msg_address);
 
-    ptrace_context_t* context = load_ptrace_context(tid);
-    dump_thread(context, log, tid, true, total_sleep_time_usec);
+    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);
+    }
 
     if (want_logs) {
         dump_logs(log, pid, true);
@@ -701,11 +687,9 @@
 
     bool detach_failed = false;
     if (dump_sibling_threads) {
-        detach_failed = dump_sibling_thread_report(context, log, pid, tid, total_sleep_time_usec);
+        detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec);
     }
 
-    free_ptrace_context(context);
-
     if (want_logs) {
         dump_logs(log, pid, false);
     }
diff --git a/debuggerd/x86/machine.c b/debuggerd/x86/machine.c
index af79092..e00208d 100644
--- a/debuggerd/x86/machine.c
+++ b/debuggerd/x86/machine.c
@@ -31,28 +31,24 @@
 #include "../utility.h"
 #include "../machine.h"
 
-void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)),
-        log_t* log, pid_t tid, bool at_fault) {
+void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
 }
 
-void dump_registers(const ptrace_context_t* context __attribute((unused)),
-        log_t* log, pid_t tid, bool at_fault) {
+void dump_registers(log_t* log, pid_t tid, int scope_flags) {
     struct pt_regs_x86 r;
-    int scopeFlags = (at_fault ? SCOPE_AT_FAULT : 0);
-
     if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-        _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
+        _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
         return;
     }
     //if there is no stack, no print just like arm
     if(!r.ebp)
         return;
-    _LOG(log, scopeFlags, "    eax %08x  ebx %08x  ecx %08x  edx %08x\n",
+    _LOG(log, scope_flags, "    eax %08x  ebx %08x  ecx %08x  edx %08x\n",
          r.eax, r.ebx, r.ecx, r.edx);
-    _LOG(log, scopeFlags, "    esi %08x  edi %08x\n",
+    _LOG(log, scope_flags, "    esi %08x  edi %08x\n",
          r.esi, r.edi);
-    _LOG(log, scopeFlags, "    xcs %08x  xds %08x  xes %08x  xfs %08x  xss %08x\n",
+    _LOG(log, scope_flags, "    xcs %08x  xds %08x  xes %08x  xfs %08x  xss %08x\n",
          r.xcs, r.xds, r.xes, r.xfs, r.xss);
-    _LOG(log, scopeFlags, "    eip %08x  ebp %08x  esp %08x  flags %08x\n",
+    _LOG(log, scope_flags, "    eip %08x  ebp %08x  esp %08x  flags %08x\n",
          r.eip, r.ebp, r.esp, r.eflags);
 }
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index b7a9ca3..9153c8d 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -75,10 +75,18 @@
     unsigned char ep_out;
 };
 
+/* True if name isn't a valid name for a USB device in /sys/bus/usb/devices.
+ * Device names are made up of numbers, dots, and dashes, e.g., '7-1.5'.
+ * We reject interfaces (e.g., '7-1.5:1.0') and host controllers (e.g. 'usb1').
+ * The name must also start with a digit, to disallow '.' and '..'
+ */
 static inline int badname(const char *name)
 {
-    while(*name) {
-        if(!isdigit(*name++)) return 1;
+    if (!isdigit(*name))
+      return 1;
+    while(*++name) {
+        if(!isdigit(*name) && *name != '.' && *name != '-')
+            return 1;
     }
     return 0;
 }
@@ -95,7 +103,8 @@
     return 0;
 }
 
-static int filter_usb_device(int fd, char *ptr, int len, int writable,
+static int filter_usb_device(int fd, char* sysfs_name,
+                             char *ptr, int len, int writable,
                              ifc_match_func callback,
                              int *ept_in_id, int *ept_out_id, int *ifc_id)
 {
@@ -131,69 +140,35 @@
     info.dev_protocol = dev->bDeviceProtocol;
     info.writable = writable;
 
-    // read device serial number (if there is one)
-    info.serial_number[0] = 0;
-    if (dev->iSerialNumber) {
-        struct usbdevfs_ctrltransfer  ctrl;
-        // Keep it short enough because some bootloaders are borked if the URB len is > 255
-        // 128 is too big by 1.
-        __u16 buffer[127];
+    snprintf(info.device_path, sizeof(info.device_path), "usb:%s", sysfs_name);
 
-        memset(buffer, 0, sizeof(buffer));
-
-        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-        ctrl.wValue = (USB_DT_STRING << 8) | dev->iSerialNumber;
-        //language ID (en-us) for serial number string
-        ctrl.wIndex = 0x0409;
-        ctrl.wLength = sizeof(buffer);
-        ctrl.data = buffer;
-        ctrl.timeout = 50;
-
-        result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
-        if (result > 0) {
-            int i;
-            // skip first word, and copy the rest to the serial string, changing shorts to bytes.
-            result /= 2;
-            for (i = 1; i < result; i++)
-                info.serial_number[i - 1] = buffer[i];
-            info.serial_number[i - 1] = 0;
-        }
-    }
-
-    /* We need to get a path that represents a particular port on a particular
-     * hub.  We are passed an fd that was obtained by opening an entry under
-     * /dev/bus/usb.  Unfortunately, the names of those entries change each
-     * time devices are plugged and unplugged.  So how to get a repeatable
-     * path?  udevadm provided the inspiration.  We can get the major and
-     * minor of the device file, read the symlink that can be found here:
-     *   /sys/dev/char/<major>:<minor>
-     * and then use the last element of that path.  As a concrete example, I
-     * have an Android device at /dev/bus/usb/001/027 so working with bash:
-     *   $ ls -l /dev/bus/usb/001/027
-     *   crw-rw-r-- 1 root plugdev 189, 26 Apr  9 11:03 /dev/bus/usb/001/027
-     *   $ ls -l /sys/dev/char/189:26
-     *   lrwxrwxrwx 1 root root 0 Apr  9 11:03 /sys/dev/char/189:26 ->
-     *           ../../devices/pci0000:00/0000:00:1a.7/usb1/1-4/1-4.2/1-4.2.3
-     * So our device_path would be 1-4.2.3 which says my device is connected
-     * to port 3 of a hub on port 2 of a hub on port 4 of bus 1 (per
-     * http://www.linux-usb.org/FAQ.html).
+    /* Read device serial number (if there is one).
+     * We read the serial number from sysfs, since it's faster and more
+     * reliable than issuing a control pipe read, and also won't
+     * cause problems for devices which don't like getting descriptor
+     * requests while they're in the middle of flashing.
      */
-    info.device_path[0] = '\0';
-    result = fstat(fd, &st);
-    if (!result && S_ISCHR(st.st_mode)) {
-        char cdev[128];
-        char link[256];
-        char *slash;
-        ssize_t link_len;
-        snprintf(cdev, sizeof(cdev), "/sys/dev/char/%d:%d",
-                 major(st.st_rdev), minor(st.st_rdev));
-        link_len = readlink(cdev, link, sizeof(link) - 1);
-        if (link_len > 0) {
-            link[link_len] = '\0';
-            slash = strrchr(link, '/');
-            if (slash)
-                snprintf(info.device_path, sizeof(info.device_path), "usb:%s", slash+1);
+    info.serial_number[0] = '\0';
+    if (dev->iSerialNumber) {
+        char path[80];
+        int fd;
+
+        snprintf(path, sizeof(path),
+                 "/sys/bus/usb/devices/%s/serial", sysfs_name);
+        path[sizeof(path) - 1] = '\0';
+
+        fd = open(path, O_RDONLY);
+        if (fd >= 0) {
+            int chars_read = read(fd, info.serial_number,
+                                  sizeof(info.serial_number) - 1);
+            close(fd);
+
+            if (chars_read <= 0)
+                info.serial_number[0] = '\0';
+            else if (info.serial_number[chars_read - 1] == '\n') {
+                // strip trailing newline
+                info.serial_number[chars_read - 1] = '\0';
+            }
         }
     }
 
@@ -241,14 +216,73 @@
     return -1;
 }
 
+static int read_sysfs_string(const char *sysfs_name, const char *sysfs_node,
+                             char* buf, int bufsize)
+{
+    char path[80];
+    int fd, n;
+
+    snprintf(path, sizeof(path),
+             "/sys/bus/usb/devices/%s/%s", sysfs_name, sysfs_node);
+    path[sizeof(path) - 1] = '\0';
+
+    fd = open(path, O_RDONLY);
+    if (fd < 0)
+        return -1;
+
+    n = read(fd, buf, bufsize - 1);
+    close(fd);
+
+    if (n < 0)
+        return -1;
+
+    buf[n] = '\0';
+
+    return n;
+}
+
+static int read_sysfs_number(const char *sysfs_name, const char *sysfs_node)
+{
+    char buf[16];
+    int value;
+
+    if (read_sysfs_string(sysfs_name, sysfs_node, buf, sizeof(buf)) < 0)
+        return -1;
+
+    if (sscanf(buf, "%d", &value) != 1)
+        return -1;
+
+    return value;
+}
+
+/* Given the name of a USB device in sysfs, get the name for the same
+ * device in devfs. Returns 0 for success, -1 for failure.
+ */
+static int convert_to_devfs_name(const char* sysfs_name,
+                                 char* devname, int devname_size)
+{
+    int busnum, devnum;
+
+    busnum = read_sysfs_number(sysfs_name, "busnum");
+    if (busnum < 0)
+        return -1;
+
+    devnum = read_sysfs_number(sysfs_name, "devnum");
+    if (devnum < 0)
+        return -1;
+
+    snprintf(devname, devname_size, "/dev/bus/usb/%03d/%03d", busnum, devnum);
+    return 0;
+}
+
 static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
 {
     usb_handle *usb = 0;
-    char busname[64], devname[64];
+    char devname[64];
     char desc[1024];
     int n, in, out, ifc;
 
-    DIR *busdir, *devdir;
+    DIR *busdir;
     struct dirent *de;
     int fd;
     int writable;
@@ -259,15 +293,7 @@
     while((de = readdir(busdir)) && (usb == 0)) {
         if(badname(de->d_name)) continue;
 
-        sprintf(busname, "%s/%s", base, de->d_name);
-        devdir = opendir(busname);
-        if(devdir == 0) continue;
-
-//        DBG("[ scanning %s ]\n", busname);
-        while((de = readdir(devdir)) && (usb == 0)) {
-
-            if(badname(de->d_name)) continue;
-            sprintf(devname, "%s/%s", busname, de->d_name);
+        if(!convert_to_devfs_name(de->d_name, devname, sizeof(devname))) {
 
 //            DBG("[ scanning %s ]\n", devname);
             writable = 1;
@@ -282,7 +308,7 @@
 
             n = read(fd, desc, sizeof(desc));
 
-            if(filter_usb_device(fd, desc, n, writable, callback,
+            if(filter_usb_device(fd, de->d_name, desc, n, writable, callback,
                                  &in, &out, &ifc) == 0) {
                 usb = calloc(1, sizeof(usb_handle));
                 strcpy(usb->fname, devname);
@@ -301,7 +327,6 @@
                 close(fd);
             }
         }
-        closedir(devdir);
     }
     closedir(busdir);
 
@@ -431,5 +456,5 @@
 
 usb_handle *usb_open(ifc_match_func callback)
 {
-    return find_usb_device("/dev/bus/usb", callback);
+    return find_usb_device("/sys/bus/usb/devices", callback);
 }
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index f432f6a..13b71ee 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -238,74 +238,16 @@
     return f;
 }
 
-/* Read a line of text till the next newline character.
- * If no newline is found before the buffer is full, continue reading till a new line is seen,
- * then return an empty buffer.  This effectively ignores lines that are too long.
- * On EOF, return null.
- */
-static char *fs_getline(char *buf, int size, FILE *file)
-{
-    int cnt = 0;
-    int eof = 0;
-    int eol = 0;
-    int c;
-
-    if (size < 1) {
-        return NULL;
-    }
-
-    while (cnt < (size - 1)) {
-        c = getc(file);
-        if (c == EOF) {
-            eof = 1;
-            break;
-        }
-
-        *(buf + cnt) = c;
-        cnt++;
-
-        if (c == '\n') {
-            eol = 1;
-            break;
-        }
-    }
-
-    /* Null terminate what we've read */
-    *(buf + cnt) = '\0';
-
-    if (eof) {
-        if (cnt) {
-            return buf;
-        } else {
-            return NULL;
-        }
-    } else if (eol) {
-        return buf;
-    } else {
-        /* The line is too long.  Read till a newline or EOF.
-         * If EOF, return null, if newline, return an empty buffer.
-         */
-        while(1) {
-            c = getc(file);
-            if (c == EOF) {
-                return NULL;
-            } else if (c == '\n') {
-                *buf = '\0';
-                return buf;
-            }
-        }
-    }
-}
-
 struct fstab *fs_mgr_read_fstab(const char *fstab_path)
 {
     FILE *fstab_file;
     int cnt, entries;
-    int len;
-    char line[256];
+    ssize_t len;
+    size_t alloc_len = 0;
+    char *line = NULL;
     const char *delim = " \t";
     char *save_ptr, *p;
-    struct fstab *fstab;
+    struct fstab *fstab = NULL;
     struct fstab_rec *recs;
     struct fs_mgr_flag_values flag_vals;
 #define FS_OPTIONS_LEN 1024
@@ -318,9 +260,8 @@
     }
 
     entries = 0;
-    while (fs_getline(line, sizeof(line), fstab_file)) {
+    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
         /* if the last character is a newline, shorten the string by 1 byte */
-        len = strlen(line);
         if (line[len - 1] == '\n') {
             line[len - 1] = '\0';
         }
@@ -337,7 +278,7 @@
 
     if (!entries) {
         ERROR("No entries found in fstab\n");
-        return 0;
+        goto err;
     }
 
     /* Allocate and init the fstab structure */
@@ -349,9 +290,8 @@
     fseek(fstab_file, 0, SEEK_SET);
 
     cnt = 0;
-    while (fs_getline(line, sizeof(line), fstab_file)) {
+    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
         /* if the last character is a newline, shorten the string by 1 byte */
-        len = strlen(line);
         if (line[len - 1] == '\n') {
             line[len - 1] = '\0';
         }
@@ -376,25 +316,25 @@
 
         if (!(p = strtok_r(line, delim, &save_ptr))) {
             ERROR("Error parsing mount source\n");
-            return 0;
+            goto err;
         }
         fstab->recs[cnt].blk_device = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing mount_point\n");
-            return 0;
+            goto err;
         }
         fstab->recs[cnt].mount_point = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing fs_type\n");
-            return 0;
+            goto err;
         }
         fstab->recs[cnt].fs_type = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing mount_flags\n");
-            return 0;
+            goto err;
         }
         tmp_fs_options[0] = '\0';
         fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
@@ -409,7 +349,7 @@
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing fs_mgr_options\n");
-            return 0;
+            goto err;
         }
         fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
                                                     &flag_vals, NULL, 0);
@@ -422,8 +362,15 @@
         cnt++;
     }
     fclose(fstab_file);
-
+    free(line);
     return fstab;
+
+err:
+    fclose(fstab_file);
+    free(line);
+    if (fstab)
+        fs_mgr_free_fstab(fstab);
+    return NULL;
 }
 
 void fs_mgr_free_fstab(struct fstab *fstab)
@@ -442,7 +389,6 @@
         free(fstab->recs[i].fs_options);
         free(fstab->recs[i].key_loc);
         free(fstab->recs[i].label);
-        i++;
     }
 
     /* Free the fstab_recs array created by calloc(3) */
diff --git a/include/backtrace/backtrace.h b/include/backtrace/backtrace.h
new file mode 100644
index 0000000..b6bff38
--- /dev/null
+++ b/include/backtrace/backtrace.h
@@ -0,0 +1,104 @@
+/*
+ * 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_H
+#define _BACKTRACE_H
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_BACKTRACE_FRAMES 64
+
+typedef struct backtrace_map_info {
+  struct backtrace_map_info* next;
+  uintptr_t start;
+  uintptr_t end;
+  bool is_readable;
+  bool is_writable;
+  bool is_executable;
+  char name[];
+} backtrace_map_info_t;
+
+typedef struct {
+  uintptr_t pc;           /* The absolute pc. */
+  uintptr_t sp;           /* The top of the stack. */
+  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. */
+} backtrace_frame_data_t;
+
+typedef struct {
+  backtrace_frame_data_t frames[MAX_BACKTRACE_FRAMES];
+  size_t num_frames;
+
+  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);
+
+/* Free any memory associated with the backtrace structure. */
+void backtrace_free_data(backtrace_t* backtrace);
+
+/* Read data at a specific address for a process. */
+bool backtrace_read_word(
+    const backtrace_t* backtrace, uintptr_t ptr, uint32_t* value);
+
+/* Get information about the map 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);
+
+/* 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
+ * malloc and must be freed by the caller.
+ */
+char* backtrace_get_proc_name(
+    const backtrace_t* backtrace, uintptr_t pc, uintptr_t* proc_offset);
+
+/* Loads memory map from /proc/<tid>/maps. If tid < 0, then load the memory
+ * map for the current process.
+ */
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid);
+
+/* Frees memory associated with the map list. */
+void backtrace_destroy_map_info_list(backtrace_map_info_t* map_info_list);
+
+/* Finds the memory map that contains the specified pc. */
+const backtrace_map_info_t* backtrace_find_map_info(
+    const backtrace_map_info_t* map_info_list, uintptr_t pc);
+
+/* 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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BACKTRACE_H */
diff --git a/include/cutils/list.h b/include/cutils/list.h
index 3881fc9..72395f4 100644
--- a/include/cutils/list.h
+++ b/include/cutils/list.h
@@ -44,6 +44,11 @@
 #define list_for_each_reverse(node, list) \
     for (node = (list)->prev; node != (list); node = node->prev)
 
+#define list_for_each_safe(node, next, list) \
+    for (node = (list)->next, next = node->next; \
+         node != (list); \
+         node = next, next = node->next)
+
 void list_init(struct listnode *list);
 void list_add_tail(struct listnode *list, struct listnode *item);
 void list_remove(struct listnode *item);
diff --git a/init/devices.c b/init/devices.c
index 1893642..af88c5f 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -33,6 +33,7 @@
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 #include <selinux/android.h>
+#include <selinux/avc.h>
 
 #include <private/android_filesystem_config.h>
 #include <sys/time.h>
@@ -830,6 +831,15 @@
         struct uevent uevent;
         parse_event(msg, &uevent);
 
+        if (sehandle && selinux_status_updated() > 0) {
+            struct selabel_handle *sehandle2;
+            sehandle2 = selinux_android_file_context_handle();
+            if (sehandle2) {
+                selabel_close(sehandle);
+                sehandle = sehandle2;
+            }
+        }
+
         handle_device_event(&uevent);
         handle_firmware_event(&uevent);
     }
@@ -896,6 +906,7 @@
     sehandle = NULL;
     if (is_selinux_enabled() > 0) {
         sehandle = selinux_android_file_context_handle();
+        selinux_status_open(true);
     }
 
     /* is 256K enough? udev uses 16MB! */
diff --git a/init/init.c b/init/init.c
index 94a2011..feac8ad 100644
--- a/init/init.c
+++ b/init/init.c
@@ -250,14 +250,12 @@
         for (ei = svc->envvars; ei; ei = ei->next)
             add_environment(ei->name, ei->value);
 
-        setsockcreatecon(scon);
-
         for (si = svc->sockets; si; si = si->next) {
             int socket_type = (
                     !strcmp(si->type, "stream") ? SOCK_STREAM :
                         (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
             int s = create_socket(si->name, socket_type,
-                                  si->perm, si->uid, si->gid);
+                                  si->perm, si->uid, si->gid, si->socketcon ?: scon);
             if (s >= 0) {
                 publish_socket(si->name, s);
             }
@@ -265,7 +263,6 @@
 
         freecon(scon);
         scon = NULL;
-        setsockcreatecon(NULL);
 
         if (svc->ioprio_class != IoSchedClass_NONE) {
             if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
diff --git a/init/init.h b/init/init.h
index aa6a4ab..3928d52 100644
--- a/init/init.h
+++ b/init/init.h
@@ -55,6 +55,7 @@
     uid_t uid;
     gid_t gid;
     int perm;
+    const char *socketcon;
 };
 
 struct svcenvinfo {
diff --git a/init/init_parser.c b/init/init_parser.c
index 776c699..667c7ab 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -552,12 +552,14 @@
                 if (length > PROP_NAME_MAX) {
                     ERROR("property name too long in trigger %s", act->name);
                 } else {
+                    int ret;
                     memcpy(prop_name, name, length);
                     prop_name[length] = 0;
 
                     /* does the property exist, and match the trigger value? */
-                    property_get(prop_name, value);
-                    if (!strcmp(equals + 1, value) ||!strcmp(equals + 1, "*")) {
+                    ret = property_get(prop_name, value);
+                    if (ret > 0 && (!strcmp(equals + 1, value) ||
+                                    !strcmp(equals + 1, "*"))) {
                         action_add_queue_tail(act);
                     }
                 }
@@ -771,7 +773,7 @@
         svc->envvars = ei;
         break;
     }
-    case K_socket: {/* name type perm [ uid gid ] */
+    case K_socket: {/* name type perm [ uid gid context ] */
         struct socketinfo *si;
         if (nargs < 4) {
             parse_error(state, "socket option requires name, type, perm arguments\n");
@@ -794,6 +796,8 @@
             si->uid = decode_uid(args[4]);
         if (nargs > 5)
             si->gid = decode_uid(args[5]);
+        if (nargs > 6)
+            si->socketcon = args[6];
         si->next = svc->sockets;
         svc->sockets = si;
         break;
diff --git a/init/property_service.c b/init/property_service.c
index 9ac2781..c370769 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -81,6 +81,7 @@
     { "sys.powerctl",     AID_SHELL,    0 },
     { "service.",         AID_SYSTEM,   0 },
     { "wlan.",            AID_SYSTEM,   0 },
+    { "gps.",             AID_GPS,      0 },
     { "bluetooth.",       AID_BLUETOOTH,   0 },
     { "dhcp.",            AID_SYSTEM,   0 },
     { "dhcp.",            AID_DHCP,     0 },
@@ -92,6 +93,7 @@
     { "persist.sys.",     AID_SYSTEM,   0 },
     { "persist.service.", AID_SYSTEM,   0 },
     { "persist.security.", AID_SYSTEM,   0 },
+    { "persist.gps.",      AID_GPS,      0 },
     { "persist.service.bdroid.", AID_BLUETOOTH,   0 },
     { "selinux."         , AID_SYSTEM,   0 },
     { NULL, 0, 0 }
@@ -437,10 +439,13 @@
     *sz = pa_workspace.size;
 }
 
-static void load_properties(char *data)
+static void load_properties(char *data, char *prefix)
 {
     char *key, *value, *eol, *sol, *tmp;
+    size_t plen;
 
+    if (prefix)
+        plen = strlen(prefix);
     sol = data;
     while((eol = strchr(sol, '\n'))) {
         key = sol;
@@ -456,6 +461,9 @@
         tmp = value - 2;
         while((tmp > key) && isspace(*tmp)) *tmp-- = 0;
 
+        if (prefix && strncmp(key, prefix, plen))
+            continue;
+
         while(isspace(*value)) value++;
         tmp = eol - 2;
         while((tmp > value) && isspace(*tmp)) *tmp-- = 0;
@@ -464,7 +472,7 @@
     }
 }
 
-static void load_properties_from_file(const char *fn)
+static void load_properties_from_file(const char *fn, char *prefix)
 {
     char *data;
     unsigned sz;
@@ -472,7 +480,7 @@
     data = read_file(fn, &sz);
 
     if(data != 0) {
-        load_properties(data);
+        load_properties(data, prefix);
         free(data);
     }
 }
@@ -545,7 +553,7 @@
 
 void property_load_boot_defaults(void)
 {
-    load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
+    load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);
 }
 
 int properties_inited(void)
@@ -560,7 +568,7 @@
 
     ret = property_get("ro.debuggable", debuggable);
     if (ret && (strcmp(debuggable, "1") == 0)) {
-        load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
+        load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL);
     }
 #endif /* ALLOW_LOCAL_PROP_OVERRIDE */
 }
@@ -582,13 +590,14 @@
 {
     int fd;
 
-    load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
-    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
+    load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
+    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
+    load_properties_from_file(PROP_PATH_FACTORY, "ro.");
     load_override_properties();
     /* Read persistent properties after all default values have been loaded. */
     load_persistent_properties();
 
-    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
+    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
     if(fd < 0) return;
     fcntl(fd, F_SETFD, FD_CLOEXEC);
     fcntl(fd, F_SETFL, O_NONBLOCK);
diff --git a/init/readme.txt b/init/readme.txt
index 7a5997d..1e8c392 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -70,10 +70,13 @@
 setenv <name> <value>
    Set the environment variable <name> to <value> in the launched process.
 
-socket <name> <type> <perm> [ <user> [ <group> ] ]
+socket <name> <type> <perm> [ <user> [ <group> [ <context> ] ] ]
    Create a unix domain socket named /dev/socket/<name> and pass
    its fd to the launched process.  <type> must be "dgram", "stream" or "seqpacket".
    User and group default to 0.
+   Context is the SELinux security context for the socket.
+   It defaults to the service security context, as specified by seclabel or
+   computed based on the service executable file security context.
 
 user <username>
    Change to username before exec'ing this service.
diff --git a/init/util.c b/init/util.c
index 1908b3a..9aaa77d 100644
--- a/init/util.c
+++ b/init/util.c
@@ -84,11 +84,15 @@
  * daemon. We communicate the file descriptor's value via the environment
  * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
  */
-int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
+int create_socket(const char *name, int type, mode_t perm, uid_t uid,
+                  gid_t gid, const char *socketcon)
 {
     struct sockaddr_un addr;
     int fd, ret;
-    char *secon;
+    char *filecon;
+
+    if (socketcon)
+        setsockcreatecon(socketcon);
 
     fd = socket(PF_UNIX, type, 0);
     if (fd < 0) {
@@ -96,6 +100,9 @@
         return -1;
     }
 
+    if (socketcon)
+        setsockcreatecon(NULL);
+
     memset(&addr, 0 , sizeof(addr));
     addr.sun_family = AF_UNIX;
     snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
@@ -107,11 +114,11 @@
         goto out_close;
     }
 
-    secon = NULL;
+    filecon = NULL;
     if (sehandle) {
-        ret = selabel_lookup(sehandle, &secon, addr.sun_path, S_IFSOCK);
+        ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK);
         if (ret == 0)
-            setfscreatecon(secon);
+            setfscreatecon(filecon);
     }
 
     ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
@@ -121,7 +128,7 @@
     }
 
     setfscreatecon(NULL);
-    freecon(secon);
+    freecon(filecon);
 
     chown(addr.sun_path, uid, gid);
     chmod(addr.sun_path, perm);
@@ -398,7 +405,9 @@
 
 void get_hardware_name(char *hardware, unsigned int *revision)
 {
-    char data[1024];
+    const char *cpuinfo = "/proc/cpuinfo";
+    char *data = NULL;
+    size_t len = 0, limit = 1024;
     int fd, n;
     char *x, *hw, *rev;
 
@@ -406,14 +415,32 @@
     if (hardware[0])
         return;
 
-    fd = open("/proc/cpuinfo", O_RDONLY);
+    fd = open(cpuinfo, O_RDONLY);
     if (fd < 0) return;
 
-    n = read(fd, data, 1023);
-    close(fd);
-    if (n < 0) return;
+    for (;;) {
+        x = realloc(data, limit);
+        if (!x) {
+            ERROR("Failed to allocate memory to read %s\n", cpuinfo);
+            goto done;
+        }
+        data = x;
 
-    data[n] = 0;
+        n = read(fd, data + len, limit - len);
+        if (n < 0) {
+            ERROR("Failed reading %s: %s (%d)\n", cpuinfo, strerror(errno), errno);
+            goto done;
+        }
+        len += n;
+
+        if (len < limit)
+            break;
+
+        /* We filled the buffer, so increase size and loop to read more */
+        limit *= 2;
+    }
+
+    data[len] = 0;
     hw = strstr(data, "\nHardware");
     rev = strstr(data, "\nRevision");
 
@@ -438,18 +465,22 @@
             *revision = strtoul(x + 2, 0, 16);
         }
     }
+
+done:
+    close(fd);
+    free(data);
 }
 
 void import_kernel_cmdline(int in_qemu,
                            void (*import_kernel_nv)(char *name, int in_qemu))
 {
-    char cmdline[1024];
+    char cmdline[2048];
     char *ptr;
     int fd;
 
     fd = open("/proc/cmdline", O_RDONLY);
     if (fd >= 0) {
-        int n = read(fd, cmdline, 1023);
+        int n = read(fd, cmdline, sizeof(cmdline) - 1);
         if (n < 0) n = 0;
 
         /* get rid of trailing newline, it happens */
diff --git a/init/util.h b/init/util.h
index 6bca4e6..04b8129 100644
--- a/init/util.h
+++ b/init/util.h
@@ -26,7 +26,7 @@
 
 int mtd_name_to_number(const char *name);
 int create_socket(const char *name, int type, mode_t perm,
-                  uid_t uid, gid_t gid);
+                  uid_t uid, gid_t gid, const char *socketcon);
 void *read_file(const char *fn, unsigned *_sz);
 time_t gettime(void);
 unsigned int decode_uid(const char *s);
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
new file mode 100644
index 0000000..4197bbb
--- /dev/null
+++ b/libbacktrace/Android.mk
@@ -0,0 +1,176 @@
+LOCAL_PATH:= $(call my-dir)
+
+#----------------------------------------------------------------------------
+# The libbacktrace library using libunwind
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	unwind.c \
+	unwind_remote.c \
+	unwind_local.c \
+	common.c \
+	demangle.c \
+	map_info.c \
+
+LOCAL_CFLAGS := \
+	-Wall \
+	-Wno-unused-parameter \
+	-Werror \
+	-std=gnu99 \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := \
+	liblog \
+	libunwind \
+	libunwind-ptrace \
+	libgccdemangle \
+
+LOCAL_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)
+
+#----------------------------------------------------------------------------
+# The libbacktrace library using libcorkscrew
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	corkscrew.c \
+	common.c \
+	demangle.c \
+	map_info.c \
+
+LOCAL_CFLAGS := \
+	-Wall \
+	-Wno-unused-parameter \
+	-Werror \
+	-std=gnu99 \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := \
+	libcorkscrew \
+	libdl \
+	libgccdemangle \
+	liblog \
+
+include $(BUILD_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# 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 \
+
+include $(BUILD_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# libbacktrace test executable
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := backtrace_test
+LOCAL_MODULE_FLAGS := debug
+
+LOCAL_SRC_FILES := \
+	backtrace_test.c \
+
+LOCAL_CFLAGS += \
+	-std=gnu99 \
+
+LOCAL_SHARED_LIBRARIES := \
+	libbacktrace_test \
+	libbacktrace \
+
+include $(BUILD_EXECUTABLE)
+
+#----------------------------------------------------------------------------
+# Only linux-x86 host versions of libbacktrace supported.
+#----------------------------------------------------------------------------
+ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
+
+#----------------------------------------------------------------------------
+# The host libbacktrace library using libcorkscrew
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES += \
+	corkscrew.c \
+	common.c \
+	demangle.c \
+	map_info.c \
+
+LOCAL_CFLAGS += \
+	-Wall \
+	-Wno-unused-parameter \
+	-Werror \
+	-std=gnu99 \
+
+LOCAL_SHARED_LIBRARIES := \
+	liblog \
+	libcorkscrew \
+	libgccdemangle \
+	liblog \
+
+LOCAL_LDLIBS += \
+	-ldl \
+	-lrt \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# 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 \
+
+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.c \
+
+LOCAL_CFLAGS += \
+	-std=gnu99 \
+
+LOCAL_SHARED_LIBRARIES := \
+	libbacktrace_test \
+	libbacktrace \
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif # HOST_OS-HOST_ARCH == linux-x86
diff --git a/libbacktrace/backtrace_test.c b/libbacktrace/backtrace_test.c
new file mode 100644
index 0000000..6155c9b
--- /dev/null
+++ b/libbacktrace/backtrace_test.c
@@ -0,0 +1,239 @@
+/*
+ * 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_testlib.c b/libbacktrace/backtrace_testlib.c
new file mode 100644
index 0000000..9400549
--- /dev/null
+++ b/libbacktrace/backtrace_testlib.c
@@ -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.
+ */
+
+#include <stdbool.h>
+#include <unistd.h>
+
+int test_level_four(int one, int two, int three, int four,
+                    bool (*callback_func)(pid_t)) {
+  if (callback_func != NULL) {
+    callback_func(-1);
+  } else {
+    while (1) {
+    }
+  }
+  return one + two + three + four;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+int test_recursive_call(int level, bool (*callback_func)(pid_t)) {
+  if (level > 0) {
+    return test_recursive_call(level - 1, callback_func) + level;
+  } else if (callback_func != NULL) {
+    callback_func(-1);
+  } else {
+    while (1) {
+    }
+  }
+  return 0;
+}
diff --git a/libbacktrace/common.c b/libbacktrace/common.c
new file mode 100644
index 0000000..20786f4
--- /dev/null
+++ b/libbacktrace/common.c
@@ -0,0 +1,113 @@
+/*
+ * 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/common.h b/libbacktrace/common.h
new file mode 100644
index 0000000..9eef964
--- /dev/null
+++ b/libbacktrace/common.h
@@ -0,0 +1,25 @@
+/*
+ * 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 _COMMON_H
+#define _COMMON_H
+
+#include <backtrace/backtrace.h>
+
+/* Common routine to free any data allocated to store frame information. */
+void free_frame_data(backtrace_t* backtrace);
+
+#endif /* _COMMON_H */
diff --git a/libbacktrace/corkscrew.c b/libbacktrace/corkscrew.c
new file mode 100644
index 0000000..899409a
--- /dev/null
+++ b/libbacktrace/corkscrew.c
@@ -0,0 +1,130 @@
+/*
+ * 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
new file mode 100644
index 0000000..de9a460
--- /dev/null
+++ b/libbacktrace/demangle.c
@@ -0,0 +1,33 @@
+/*
+ * 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
new file mode 100644
index 0000000..a5318ac
--- /dev/null
+++ b/libbacktrace/demangle.h
@@ -0,0 +1,25 @@
+/*
+ * 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/map_info.c b/libbacktrace/map_info.c
new file mode 100644
index 0000000..9cc6e01
--- /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 <cutils/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;
+}
diff --git a/libbacktrace/stubs.c b/libbacktrace/stubs.c
new file mode 100644
index 0000000..1741601
--- /dev/null
+++ b/libbacktrace/stubs.c
@@ -0,0 +1,53 @@
+/*
+ * 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/unwind.c b/libbacktrace/unwind.c
new file mode 100644
index 0000000..f75e518
--- /dev/null
+++ b/libbacktrace/unwind.c
@@ -0,0 +1,57 @@
+/*
+ * 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
new file mode 100644
index 0000000..9ba96a4
--- /dev/null
+++ b/libbacktrace/unwind.h
@@ -0,0 +1,34 @@
+/*
+ * 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
new file mode 100644
index 0000000..d467d8a
--- /dev/null
+++ b/libbacktrace/unwind_local.c
@@ -0,0 +1,130 @@
+/*
+ * 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
new file mode 100644
index 0000000..1c624d7
--- /dev/null
+++ b/libbacktrace/unwind_remote.c
@@ -0,0 +1,158 @@
+/*
+ * 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;
+}
diff --git a/libcorkscrew/Android.mk b/libcorkscrew/Android.mk
index d62c2d5..e275317 100644
--- a/libcorkscrew/Android.mk
+++ b/libcorkscrew/Android.mk
@@ -51,7 +51,7 @@
 
 LOCAL_SHARED_LIBRARIES += libdl libcutils liblog libgccdemangle
 
-LOCAL_CFLAGS += -std=gnu99 -Werror
+LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
 LOCAL_MODULE := libcorkscrew
 LOCAL_MODULE_TAGS := optional
 
@@ -81,7 +81,7 @@
   LOCAL_SHARED_LIBRARIES += libgccdemangle # TODO: is this even needed on Linux?
   LOCAL_LDLIBS += -lrt
 endif
-LOCAL_CFLAGS += -std=gnu99 -Werror
+LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
 LOCAL_MODULE := libcorkscrew
 LOCAL_MODULE_TAGS := optional
 include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
index e133ab6..ef22821 100755
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ b/libcorkscrew/arch-x86/backtrace-x86.c
@@ -380,7 +380,7 @@
         case DW_CFA_offset_extended: // probably we don't have it on x86.
             if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
             if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
-            if (reg > DWARF_REGISTERS) {
+            if (reg >= DWARF_REGISTERS) {
                 ALOGE("DW_CFA_offset_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
                 return false;
             }
@@ -390,39 +390,39 @@
             break;
         case DW_CFA_restore_extended: // probably we don't have it on x86.
             if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
-            dstate->regs[reg].rule = stack->regs[reg].rule;
-            dstate->regs[reg].value = stack->regs[reg].value;
-            if (reg > DWARF_REGISTERS) {
+            if (reg >= DWARF_REGISTERS) {
                 ALOGE("DW_CFA_restore_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
                 return false;
             }
+            dstate->regs[reg].rule = stack->regs[reg].rule;
+            dstate->regs[reg].value = stack->regs[reg].value;
             ALOGV("DW_CFA_restore: r%d = %c(%d)", reg, dstate->regs[reg].rule, dstate->regs[reg].value);
             break;
         case DW_CFA_undefined: // probably we don't have it on x86.
             if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
-            dstate->regs[reg].rule = 'u';
-            dstate->regs[reg].value = 0;
-            if (reg > DWARF_REGISTERS) {
+            if (reg >= DWARF_REGISTERS) {
                 ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
                 return false;
             }
+            dstate->regs[reg].rule = 'u';
+            dstate->regs[reg].value = 0;
             ALOGV("DW_CFA_undefined: r%d", reg);
             break;
         case DW_CFA_same_value: // probably we don't have it on x86.
             if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
-            dstate->regs[reg].rule = 's';
-            dstate->regs[reg].value = 0;
-            if (reg > DWARF_REGISTERS) {
+            if (reg >= DWARF_REGISTERS) {
                 ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
                 return false;
             }
+            dstate->regs[reg].rule = 's';
+            dstate->regs[reg].value = 0;
             ALOGV("DW_CFA_same_value: r%d", reg);
             break;
         case DW_CFA_register: // probably we don't have it on x86.
             if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
             /* that's new register actually, not offset */
             if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
-            if (reg > DWARF_REGISTERS || offset > DWARF_REGISTERS) {
+            if (reg >= DWARF_REGISTERS || offset >= DWARF_REGISTERS) {
                 ALOGE("DW_CFA_register: r%d or r%d exceeds supported number of registers (%d)", reg, offset, DWARF_REGISTERS);
                 return false;
             }
@@ -520,7 +520,7 @@
 
 /* Updaing state based on dwarf state. */
 static bool update_state(const memory_t* memory, unwind_state_t* state,
-                         dwarf_state_t* dstate, cie_info_t* cie_info) {
+                         dwarf_state_t* dstate) {
     unwind_state_t newstate;
     /* We can restore more registers here if we need them. Meanwile doing minimal work here. */
     /* Getting CFA. */
@@ -550,7 +550,6 @@
 
 /* Execute CIE and FDE instructions for FDE found with find_fde. */
 static bool execute_fde(const memory_t* memory,
-                        const map_info_t* map_info_list,
                         uintptr_t fde,
                         unwind_state_t* state) {
     uint32_t fde_length = 0;
@@ -753,7 +752,7 @@
         ALOGV("IP: %x, LOC: %x", state->reg[DWARF_EIP], dstate->loc);
     }
 
-    return update_state(memory, state, dstate, cie_info);
+    return update_state(memory, state, dstate);
 }
 
 static ssize_t unwind_backtrace_common(const memory_t* memory,
@@ -805,7 +804,7 @@
 
         uint32_t stack_top = state->reg[DWARF_ESP];
 
-        if (!execute_fde(memory, map_info_list, fde, state)) break;
+        if (!execute_fde(memory, fde, state)) break;
 
         if (frame) {
             frame->stack_top = stack_top;
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 0fd5a57..62f4290 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -115,18 +115,22 @@
         uevent.c
 
 ifeq ($(TARGET_ARCH),arm)
-LOCAL_SRC_FILES += arch-arm/memset32.S
+    LOCAL_SRC_FILES += arch-arm/memset32.S
 else  # !arm
-ifeq ($(TARGET_ARCH_VARIANT),x86-atom)
-LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
-else # !x86-atom
-ifeq ($(TARGET_ARCH),mips)
-LOCAL_SRC_FILES += arch-mips/android_memset.c
-else # !mips
-LOCAL_SRC_FILES += memory.c
-endif # !mips
-endif # !x86-atom
+    ifeq ($(TARGET_ARCH),x86)
+        ifeq ($(ARCH_X86_HAVE_SSE2),true)
+            LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -DUSE_SSE2
+            LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
+        else # !ARCH_X86_HAVE_SSE2
+            LOCAL_SRC_FILES += memory.c
+        endif # !ARCH_X86_HAVE_SSE2
+    else # !x86
+        ifeq ($(TARGET_ARCH),mips)
+            LOCAL_SRC_FILES += arch-mips/android_memset.c
+        else # !mips
+            LOCAL_SRC_FILES += memory.c
+        endif # !mips
+    endif # !x86
 endif # !arm
 
 LOCAL_C_INCLUDES := $(libcutils_c_includes) $(KERNEL_HEADERS)
diff --git a/libcutils/ashmem-dev.c b/libcutils/ashmem-dev.c
index 8b71f87..3089a94 100644
--- a/libcutils/ashmem-dev.c
+++ b/libcutils/ashmem-dev.c
@@ -48,7 +48,7 @@
 		return fd;
 
 	if (name) {
-		char buf[ASHMEM_NAME_LEN];
+		char buf[ASHMEM_NAME_LEN] = {0};
 
 		strlcpy(buf, name, sizeof(buf));
 		ret = ioctl(fd, ASHMEM_SET_NAME, buf);
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index 5014e4a..2428022 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -46,15 +46,6 @@
 #define off64_t off_t
 #endif
 
-#ifdef __BIONIC__
-extern void*  __mmap2(void *, size_t, int, int, int, off_t);
-static inline void *mmap64(void *addr, size_t length, int prot, int flags,
-        int fd, off64_t offset)
-{
-    return __mmap2(addr, length, prot, flags, fd, offset >> 12);
-}
-#endif
-
 #define min(a, b) \
 	({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
 
diff --git a/mkbootimg/bootimg.h b/mkbootimg/bootimg.h
index 242ab35..9171d85 100644
--- a/mkbootimg/bootimg.h
+++ b/mkbootimg/bootimg.h
@@ -24,6 +24,7 @@
 #define BOOT_MAGIC_SIZE 8
 #define BOOT_NAME_SIZE 16
 #define BOOT_ARGS_SIZE 512
+#define BOOT_EXTRA_ARGS_SIZE 1024
 
 struct boot_img_hdr
 {
@@ -43,10 +44,14 @@
     unsigned unused[2];    /* future expansion: should be 0 */
 
     unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
-    
+
     unsigned char cmdline[BOOT_ARGS_SIZE];
 
     unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+
+    /* Supplemental command line data; kept here to maintain
+     * binary compatibility with older versions of mkbootimg */
+    unsigned char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
 };
 
 /*
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
index 34a879b..d598f03 100644
--- a/mkbootimg/mkbootimg.c
+++ b/mkbootimg/mkbootimg.c
@@ -114,6 +114,7 @@
     unsigned ramdisk_offset = 0x01000000;
     unsigned second_offset  = 0x00f00000;
     unsigned tags_offset    = 0x00000100;
+    size_t cmdlen;
 
     argc--;
     argv++;
@@ -192,11 +193,19 @@
 
     memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
 
-    if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) {
+    cmdlen = strlen(cmdline);
+    if(cmdlen > (BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 2)) {
         fprintf(stderr,"error: kernel commandline too large\n");
         return 1;
     }
-    strcpy((char*)hdr.cmdline, cmdline);
+    /* Even if we need to use the supplemental field, ensure we
+     * are still NULL-terminated */
+    strncpy((char *)hdr.cmdline, cmdline, BOOT_ARGS_SIZE - 1);
+    hdr.cmdline[BOOT_ARGS_SIZE - 1] = '\0';
+    if (cmdlen >= (BOOT_ARGS_SIZE - 1)) {
+        cmdline += (BOOT_ARGS_SIZE - 1);
+        strncpy((char *)hdr.extra_cmdline, cmdline, BOOT_EXTRA_ARGS_SIZE);
+    }
 
     kernel_data = load_file(kernel_fn, &hdr.kernel_size);
     if(kernel_data == 0) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 86e124f..7a189e3 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -17,6 +17,9 @@
     # This should occur before anything else (e.g. ueventd) is started.
     setcon u:r:init:s0
 
+    # Set the security context of /adb_keys if present.
+    restorecon /adb_keys
+
     start ueventd
 
 # create mountpoints
@@ -219,6 +222,10 @@
     mkdir /data/local 0751 root root
     mkdir /data/misc/media 0700 media media
 
+    # Set security context of any pre-existing /data/misc/adb/adb_keys file.
+    restorecon /data/misc/adb
+    restorecon /data/misc/adb/adb_keys
+
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp
     mkdir /data/local/tmp 0771 shell shell
@@ -256,6 +263,9 @@
     # Separate location for storing security policy files on data
     mkdir /data/security 0711 system system
 
+    # Reload policy from /data/security if present.
+    setprop selinux.reload_policy 1
+
     # If there is no fs-post-data action in the init.<device>.rc file, you
     # must uncomment this line, otherwise encrypted filesystems
     # won't work.
@@ -350,7 +360,6 @@
     chown root radio /proc/cmdline
 
 # Set these so we can remotely update SELinux policy
-    chown system system /sys/fs/selinux/load
     chown system system /sys/fs/selinux/enforce
 
 # Define TCP buffer sizes for various networks
@@ -420,10 +429,6 @@
     critical
     seclabel u:r:healthd:s0
 
-on property:selinux.reload_policy=1
-    restart ueventd
-    restart installd
-
 service console /system/bin/sh
     class core
     console
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 2cf0265..a60cfc5 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -5,6 +5,8 @@
 /dev/tty                  0666   root       root
 /dev/random               0666   root       root
 /dev/urandom              0666   root       root
+# Make HW RNG readable by group system to let EntropyMixer read it.
+/dev/hw_random            0440   root       system
 /dev/ashmem               0666   root       root
 /dev/binder               0666   root       root