am 1b84e0a3: Merge "utils: Add ProcessCallStack to collect stack traces for all threads in a process" into klp-dev

* commit '1b84e0a3145f1497fc2259608d8830f371526ece':
  utils: Add ProcessCallStack to collect stack traces for all threads in a process
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 8340738..f7823a8 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -278,7 +278,9 @@
         return 0;
 
     fd = _adb_connect(service);
-    if(fd == -2) {
+    if(fd == -1) {
+        fprintf(stderr,"error: %s\n", __adb_error);
+    } else if(fd == -2) {
         fprintf(stderr,"** daemon still not running\n");
     }
     D("adb_connect: return fd %d\n", fd);
diff --git a/adb/commandline.c b/adb/commandline.c
index 27a1754..c9bb437 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -767,7 +767,7 @@
 
     fd = adb_connect("restore:");
     if (fd < 0) {
-        fprintf(stderr, "adb: unable to connect for backup\n");
+        fprintf(stderr, "adb: unable to connect for restore\n");
         adb_close(tarFd);
         return -1;
     }
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index 354d0fb..9fec081 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -642,8 +642,8 @@
             ci = mkcopyinfo(lpath, rpath, name, 0);
             if(lstat(ci->src, &st)) {
                 fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
+                free(ci);
                 closedir(d);
-
                 return -1;
             }
             if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index d3e841b..f24f14c 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -110,6 +110,7 @@
 
             if(writex(s, &msg.dent, sizeof(msg.dent)) ||
                writex(s, de->d_name, len)) {
+                closedir(d);
                 return -1;
             }
         }
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/cpio/mkbootfs.c b/cpio/mkbootfs.c
index 3569e27..7d3740c 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -220,6 +220,8 @@
         free(names[i]);
     }
     free(names);
+
+    closedir(d);
 }
 
 static void _archive(char *in, char *out, int ilen, int olen)
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..aa7a3c2 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_context_t context;
+    if (!backtrace_create_context(&context, tid, -1, 0)) {
+        _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(&context, log, SCOPE_AT_FAULT, "  ");
+        backtrace_destroy_context(&context);
     }
 
     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_context_t* context, log_t* log,
+                           int scope_flags, const char* prefix) {
+    char buf[512];
+    for (size_t i = 0; i < context->backtrace->num_frames; i++) {
+        backtrace_format_frame_data(context, i, buf, sizeof(buf));
+        _LOG(log, scope_flags, "%s%s\n", prefix, buf);
+    }
 }
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index c5c786a..54a60b2 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_context_t* context, 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..aa63547 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_context_t* context, log_t* log,
+        int scope_flags, uintptr_t *sp, size_t words, int label) {
     for (size_t i = 0; i < words; i++) {
         uint32_t stack_content;
-        if (!try_get_word_ptrace(tid, *sp, &stack_content)) {
+        if (!backtrace_read_word(context, *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_name(context, stack_content, NULL);
+        if (!map_name) {
+            map_name = "";
+        }
+        uintptr_t offset = 0;
+        char* func_name = backtrace_get_func_name(context, stack_content, &offset);
+        if (func_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, func_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, func_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, func_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, func_name);
                 }
             }
-            free(demangled_name);
+            free(func_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,43 @@
     }
 }
 
-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_context_t* context, log_t* log, int scope_flags) {
+    const backtrace_t* backtrace = context->backtrace;
+    size_t first = 0, last;
+    for (size_t i = 0; i < backtrace->num_frames; i++) {
+        if (backtrace->frames[i].sp) {
+            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(context, log, scope_flags, &sp, STACK_WORDS, -1);
 
     // Dump a few words from all successive frames.
     // Only log the first 3 frames, put the rest in the tombstone.
     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(context, 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 +320,40 @@
             } else if (words > STACK_WORDS) {
                 words = STACK_WORDS;
             }
-            dump_stack_segment(context, log, tid, scopeFlags, &sp, words, i);
+            dump_stack_segment(context, 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_context_t* context,
+        log_t* log, int scope_flags) {
+    if (context->backtrace->num_frames) {
+        _LOG(log, scope_flags, "\nbacktrace:\n");
+        dump_backtrace_to_log(context, log, scope_flags, "    ");
+
+        _LOG(log, scope_flags, "\nstack:\n");
+        dump_stack(context, 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 +367,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 +395,32 @@
      * 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,
-        int* total_sleep_time_usec) {
-    wait_for_stop(tid, total_sleep_time_usec);
+static void dump_thread(const backtrace_context_t* context, log_t* log,
+        int scope_flags, int* total_sleep_time_usec) {
+    const backtrace_t* backtrace = context->backtrace;
+    wait_for_stop(backtrace->tid, total_sleep_time_usec);
 
-    dump_registers(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(context, log, scope_flags);
+    if (IS_AT_FAULT(scope_flags)) {
+        dump_memory_and_code(log, backtrace->tid, scope_flags);
+        dump_nearby_maps(backtrace->map_info_list, log, backtrace->tid, scope_flags);
     }
 }
 
 /* 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 +447,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_context_t new_context;
+        if (backtrace_create_context(&new_context, pid, new_tid, 0)) {
+            dump_thread(&new_context, log, 0, total_sleep_time_usec);
+            backtrace_destroy_context(&new_context);
+        }
 
         if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
             LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
@@ -624,7 +608,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_context_t* context, log_t* log, uintptr_t address) {
   if (address == 0) {
     return;
   }
@@ -636,7 +620,7 @@
   char* p = &msg[0];
   while (p < &msg[sizeof(msg)]) {
     uint32_t data;
-    if (!try_get_word_ptrace(tid, address, &data)) {
+    if (!backtrace_read_word(context, address, &data)) {
       break;
     }
     address += sizeof(uint32_t);
@@ -686,14 +670,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_context_t context;
+    if (backtrace_create_context(&context, pid, tid, 0)) {
+        dump_abort_message(&context, log, abort_msg_address);
+        dump_thread(&context, log, SCOPE_AT_FAULT, total_sleep_time_usec);
+        backtrace_destroy_context(&context);
+    }
 
     if (want_logs) {
         dump_logs(log, pid, true);
@@ -701,11 +688,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/Android.mk b/fastboot/Android.mk
index 1189e1f..b9b3c92 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -18,9 +18,10 @@
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
   $(LOCAL_PATH)/../../extras/ext4_utils
-LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c
+LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
+LOCAL_CFLAGS += -std=gnu99
 
 ifeq ($(HOST_OS),linux)
   LOCAL_SRC_FILES += usb_linux.c util_linux.c
@@ -69,7 +70,7 @@
 
 ifeq ($(HOST_OS),linux)
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := usbtest.c usb_linux.c
+LOCAL_SRC_FILES := usbtest.c usb_linux.c util.c
 LOCAL_MODULE := usbtest
 include $(BUILD_HOST_EXECUTABLE)
 endif
diff --git a/fastboot/engine.c b/fastboot/engine.c
index b07e742..972c4ed 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -36,7 +36,6 @@
 #include <stdbool.h>
 #include <string.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -48,34 +47,13 @@
 
 #define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
 
-double now()
-{
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
-}
-
-char *mkmsg(const char *fmt, ...)
-{
-    char buf[256];
-    char *s;
-    va_list ap;
-
-    va_start(ap, fmt);
-    vsprintf(buf, fmt, ap);
-    va_end(ap);
-
-    s = strdup(buf);
-    if (s == 0) die("out of memory");
-    return s;
-}
-
 #define OP_DOWNLOAD   1
 #define OP_COMMAND    2
 #define OP_QUERY      3
 #define OP_NOTICE     4
 #define OP_FORMAT     5
 #define OP_DOWNLOAD_SPARSE 6
+#define OP_WAIT_FOR_DISCONNECT 7
 
 typedef struct Action Action;
 
@@ -573,6 +551,11 @@
     a->data = (void*) notice;
 }
 
+void fb_queue_wait_for_disconnect(void)
+{
+    queue_action(OP_WAIT_FOR_DISCONNECT, "");
+}
+
 int fb_execute_queue(usb_handle *usb)
 {
     Action *a;
@@ -614,6 +597,8 @@
             status = fb_download_data_sparse(usb, a->data);
             status = a->func(a, status, status ? fb_get_error() : "");
             if (status) break;
+        } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
+            usb_wait_for_disconnect(usb);
         } else {
             die("bogus action");
         }
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index f186c93..73a6e56 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -30,7 +30,6 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdarg.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <string.h>
@@ -106,17 +105,6 @@
     {"system.img", "system.sig", "system", false},
 };
 
-void die(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    fprintf(stderr,"error: ");
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr,"\n");
-    va_end(ap);
-    exit(1);
-}
-
 void get_my_path(char *path);
 
 char *find_item(const char *item, const char *product)
@@ -503,7 +491,13 @@
 
     for(n = 0; n < count; n++) {
         out[n] = strdup(strip(val[n]));
-        if (out[n] == 0) return -1;
+        if (out[n] == 0) {
+            for(size_t i = 0; i < n; ++i) {
+                free((char*) out[i]);
+            }
+            free(out);
+            return -1;
+        }
     }
 
     fb_queue_require(prod, name, invert, n, out);
@@ -1102,6 +1096,7 @@
         fb_queue_reboot();
     } else if (wants_reboot_bootloader) {
         fb_queue_command("reboot-bootloader", "rebooting into bootloader");
+        fb_queue_wait_for_disconnect();
     }
 
     if (fb_queue_is_empty())
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index c1b2964..976c397 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -58,10 +58,13 @@
 void fb_queue_command(const char *cmd, const char *msg);
 void fb_queue_download(const char *name, void *data, unsigned size);
 void fb_queue_notice(const char *notice);
+void fb_queue_wait_for_disconnect(void);
 int fb_execute_queue(usb_handle *usb);
 int fb_queue_is_empty(void);
 
 /* util stuff */
+double now();
+char *mkmsg(const char *fmt, ...);
 void die(const char *fmt, ...);
 
 /* Current product */
diff --git a/fastboot/usb.h b/fastboot/usb.h
index d504ee2..17cf0a9 100644
--- a/fastboot/usb.h
+++ b/fastboot/usb.h
@@ -62,6 +62,6 @@
 int usb_close(usb_handle *h);
 int usb_read(usb_handle *h, void *_data, int len);
 int usb_write(usb_handle *h, const void *_data, int len);
-
+int usb_wait_for_disconnect(usb_handle *h);
 
 #endif
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index b7a9ca3..f2ce226 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -50,10 +50,17 @@
 #endif
 #include <asm/byteorder.h>
 
+#include "fastboot.h"
 #include "usb.h"
 
 #define MAX_RETRIES 5
 
+/* Timeout in seconds for usb_wait_for_disconnect.
+ * It doesn't usually take long for a device to disconnect (almost always
+ * under 2 seconds) but we'll time out after 3 seconds just in case.
+ */
+#define WAIT_FOR_DISCONNECT_TIMEOUT  3
+
 #ifdef TRACE_USB
 #define DBG1(x...) fprintf(stderr, x)
 #define DBG(x...) fprintf(stderr, x)
@@ -75,10 +82,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 +110,8 @@
     return 0;
 }
 
-static int filter_usb_device(int fd, char *ptr, int len, int writable,
+static int filter_usb_device(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 +147,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 +223,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 +300,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 +315,7 @@
 
             n = read(fd, desc, sizeof(desc));
 
-            if(filter_usb_device(fd, desc, n, writable, callback,
+            if(filter_usb_device(de->d_name, desc, n, writable, callback,
                                  &in, &out, &ifc) == 0) {
                 usb = calloc(1, sizeof(usb_handle));
                 strcpy(usb->fname, devname);
@@ -301,7 +334,6 @@
                 close(fd);
             }
         }
-        closedir(devdir);
     }
     closedir(busdir);
 
@@ -315,26 +347,11 @@
     struct usbdevfs_bulktransfer bulk;
     int n;
 
-    if(h->ep_out == 0) {
+    if(h->ep_out == 0 || h->desc == -1) {
         return -1;
     }
 
-    if(len == 0) {
-        bulk.ep = h->ep_out;
-        bulk.len = 0;
-        bulk.data = data;
-        bulk.timeout = 0;
-
-        n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
-        if(n != 0) {
-            fprintf(stderr,"ERROR: n = %d, errno = %d (%s)\n",
-                    n, errno, strerror(errno));
-            return -1;
-        }
-        return 0;
-    }
-
-    while(len > 0) {
+    do {
         int xfer;
         xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
 
@@ -353,7 +370,7 @@
         count += xfer;
         len -= xfer;
         data += xfer;
-    }
+    } while(len > 0);
 
     return count;
 }
@@ -365,7 +382,7 @@
     struct usbdevfs_bulktransfer bulk;
     int n, retry;
 
-    if(h->ep_in == 0) {
+    if(h->ep_in == 0 || h->desc == -1) {
         return -1;
     }
 
@@ -431,5 +448,20 @@
 
 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);
+}
+
+/* Wait for the system to notice the device is gone, so that a subsequent
+ * fastboot command won't try to access the device before it's rebooted.
+ * Returns 0 for success, -1 for timeout.
+ */
+int usb_wait_for_disconnect(usb_handle *usb)
+{
+  double deadline = now() + WAIT_FOR_DISCONNECT_TIMEOUT;
+  while (now() < deadline) {
+    if (access(usb->fname, F_OK))
+      return 0;
+    usleep(50000);
+  }
+  return -1;
 }
diff --git a/fastboot/usb_osx.c b/fastboot/usb_osx.c
index 1548ba8..0f55e0d 100644
--- a/fastboot/usb_osx.c
+++ b/fastboot/usb_osx.c
@@ -467,6 +467,11 @@
     return 0;
 }
 
+int usb_wait_for_disconnect(usb_handle *usb) {
+    /* TODO: Punt for now */
+    return 0;
+}
+
 int usb_read(usb_handle *h, void *data, int len) {
     IOReturn result;
     UInt32 numBytes = len;
diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.c
index 7aa36b2..07f7be2 100644
--- a/fastboot/usb_windows.c
+++ b/fastboot/usb_windows.c
@@ -269,6 +269,11 @@
     return 0;
 }
 
+int usb_wait_for_disconnect(usb_handle *usb) {
+    /* TODO: Punt for now */
+    return 0;
+}
+
 int recognized_device(usb_handle* handle, ifc_match_func callback) {
     struct usb_ifc_info info;
     USB_DEVICE_DESCRIPTOR device_desc;
diff --git a/fastboot/util.c b/fastboot/util.c
new file mode 100644
index 0000000..f2bbd34
--- /dev/null
+++ b/fastboot/util.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/time.h>
+
+#include "fastboot.h"
+
+double now()
+{
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
+}
+
+char *mkmsg(const char *fmt, ...)
+{
+    char buf[256];
+    char *s;
+    va_list ap;
+
+    va_start(ap, fmt);
+    vsprintf(buf, fmt, ap);
+    va_end(ap);
+
+    s = strdup(buf);
+    if (s == 0) die("out of memory");
+    return s;
+}
+
+void die(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    fprintf(stderr,"error: ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr,"\n");
+    va_end(ap);
+    exit(1);
+}
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/gpttool/gpttool.c b/gpttool/gpttool.c
index 05d5177..d3f08fe 100644
--- a/gpttool/gpttool.c
+++ b/gpttool/gpttool.c
@@ -161,7 +161,7 @@
 {
 	struct efi_entry *entry = ptbl->entry;
 	unsigned n, m;
-	char name[EFI_NAMELEN];
+	char name[EFI_NAMELEN + 1];
 
 	fprintf(stderr,"ptn  start block   end block     name\n");
 	fprintf(stderr,"---- ------------- ------------- --------------------\n");
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
new file mode 100644
index 0000000..0b75e83
--- /dev/null
+++ b/include/backtrace/Backtrace.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BACKTRACE_BACKTRACE_H
+#define _BACKTRACE_BACKTRACE_H
+
+#include <backtrace/backtrace.h>
+
+#include <string>
+
+class BacktraceImpl;
+
+class Backtrace {
+public:
+  Backtrace(BacktraceImpl* impl);
+  virtual ~Backtrace();
+
+  // Get the current stack trace and store in the backtrace_ structure.
+  virtual bool Unwind(size_t num_ignore_frames);
+
+  // Get the function name and offset into the function given the pc.
+  // If the string is empty, then no valid function name was found.
+  virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset);
+
+  // Get the name of the map associated with the given pc. If NULL is returned,
+  // then map_start is not set. Otherwise, map_start is the beginning of this
+  // map.
+  virtual const char* GetMapName(uintptr_t pc, uintptr_t* map_start);
+
+  // Finds the memory map associated with the given ptr.
+  virtual const backtrace_map_info_t* FindMapInfo(uintptr_t ptr);
+
+  // Read the data at a specific address.
+  virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0;
+
+  // Create a string representing the formatted line of backtrace information
+  // for a single frame.
+  virtual std::string FormatFrameData(size_t frame_num);
+
+  pid_t Pid() { return backtrace_.pid; }
+  pid_t Tid() { return backtrace_.tid; }
+  size_t NumFrames() { return backtrace_.num_frames; }
+
+  const backtrace_t* GetBacktrace() { return &backtrace_; }
+
+  const backtrace_frame_data_t* GetFrame(size_t frame_num) {
+    return &backtrace_.frames[frame_num];
+  }
+
+  // Create the correct Backtrace object based on what is to be unwound.
+  // If pid < 0 or equals the current pid, then the Backtrace object
+  // corresponds to the current process.
+  // If pid < 0 or equals the current pid and tid >= 0, then the Backtrace
+  // object corresponds to a thread in the current process.
+  // If pid >= 0 and tid < 0, then the Backtrace object corresponds to a
+  // different process.
+  // Tracing a thread in a different process is not supported.
+  static Backtrace* Create(pid_t pid, pid_t tid);
+
+protected:
+  virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value);
+
+  BacktraceImpl* impl_;
+
+  backtrace_map_info_t* map_info_;
+
+  backtrace_t backtrace_;
+
+  friend class BacktraceImpl;
+};
+
+#endif // _BACKTRACE_BACKTRACE_H
diff --git a/include/backtrace/backtrace.h b/include/backtrace/backtrace.h
new file mode 100644
index 0000000..b35a6d5
--- /dev/null
+++ b/include/backtrace/backtrace.h
@@ -0,0 +1,114 @@
+/*
+ * 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>
+
+__BEGIN_DECLS
+
+#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* func_name;        /* The function name associated with this pc, NULL if not found. */
+  uintptr_t func_offset;  /* pc relative to the start of the function, only valid if func_name is not NULL. */
+} backtrace_frame_data_t;
+
+typedef struct {
+  backtrace_frame_data_t frames[MAX_BACKTRACE_FRAMES];
+  size_t num_frames;
+
+  pid_t pid;
+  pid_t tid;
+  backtrace_map_info_t* map_info_list;
+} backtrace_t;
+
+typedef struct {
+  void* data;
+  const backtrace_t* backtrace;
+} backtrace_context_t;
+
+/* Create a context for the backtrace data and gather the backtrace.
+ * If pid < 0, then gather the backtrace for the current process.
+ */
+bool backtrace_create_context(
+    backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames);
+
+/* Gather the backtrace data for a pthread instead of a process. */
+bool backtrace_create_thread_context(
+    backtrace_context_t* context, pid_t tid, size_t num_ignore_frames);
+
+/* Free any memory allocated during the context create. */
+void backtrace_destroy_context(backtrace_context_t* context);
+
+/* Read data at a specific address for a process. */
+bool backtrace_read_word(
+    const backtrace_context_t* context, uintptr_t ptr, uint32_t* value);
+
+/* Get information about the map name associated with a pc. If NULL is
+ * returned, then map_start is not set.
+ */
+const char* backtrace_get_map_name(
+    const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start);
+
+/* Get the function name and offset given the pc. If NULL is returned,
+ * then func_offset is not set. The returned string is allocated using
+ * malloc and must be freed by the caller.
+ */
+char* backtrace_get_func_name(
+    const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset);
+
+/* Loads memory map from /proc/<pid>/maps. If pid < 0, then load the memory
+ * map for the current process.
+ */
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid);
+
+/* 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_context_t* context, size_t frame_num, char* buf,
+    size_t buf_size);
+
+/* Get the backtrace data structure associated with the context. */
+const backtrace_t* backtrace_get_data(backtrace_context_t* context);
+
+__END_DECLS
+
+#endif /* _BACKTRACE_H */
diff --git a/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/include/mincrypt/dsa_sig.h b/include/mincrypt/dsa_sig.h
new file mode 100644
index 0000000..b0d91cd
--- /dev/null
+++ b/include/mincrypt/dsa_sig.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google Inc. nor the names of its contributors may
+ *       be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
+
+#include "mincrypt/p256.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Returns 0 if input sig is not a valid ASN.1 sequence
+int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ */
diff --git a/include/mincrypt/hash-internal.h b/include/mincrypt/hash-internal.h
index 96806f7..c813b44 100644
--- a/include/mincrypt/hash-internal.h
+++ b/include/mincrypt/hash-internal.h
@@ -1,8 +1,31 @@
-// Copyright 2007 Google Inc. All Rights Reserved.
-// Author: mschilder@google.com (Marius Schilder)
+/*
+ * Copyright 2007 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google Inc. nor the names of its contributors may
+ *       be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 
-#ifndef SECURITY_UTIL_LITE_HASH_INTERNAL_H__
-#define SECURITY_UTIL_LITE_HASH_INTERNAL_H__
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
 
 #include <stdint.h>
 
@@ -37,4 +60,4 @@
 }
 #endif  // __cplusplus
 
-#endif  // SECURITY_UTIL_LITE_HASH_INTERNAL_H__
+#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
diff --git a/include/mincrypt/p256.h b/include/mincrypt/p256.h
new file mode 100644
index 0000000..465a1b9
--- /dev/null
+++ b/include/mincrypt/p256.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google Inc. nor the names of its contributors may
+ *       be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
+
+// Collection of routines manipulating 256 bit unsigned integers.
+// Just enough to implement ecdsa-p256 and related algorithms.
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define P256_BITSPERDIGIT 32
+#define P256_NDIGITS 8
+#define P256_NBYTES 32
+
+typedef int p256_err;
+typedef uint32_t p256_digit;
+typedef int32_t p256_sdigit;
+typedef uint64_t p256_ddigit;
+typedef int64_t p256_sddigit;
+
+// Defining p256_int as struct to leverage struct assigment.
+typedef struct {
+  p256_digit a[P256_NDIGITS];
+} p256_int;
+
+extern const p256_int SECP256r1_n;  // Curve order
+extern const p256_int SECP256r1_p;  // Curve prime
+extern const p256_int SECP256r1_b;  // Curve param
+
+// Initialize a p256_int to zero.
+void p256_init(p256_int* a);
+
+// Clear a p256_int to zero.
+void p256_clear(p256_int* a);
+
+// Return bit. Index 0 is least significant.
+int p256_get_bit(const p256_int* a, int index);
+
+// b := a % MOD
+void p256_mod(
+    const p256_int* MOD,
+    const p256_int* a,
+    p256_int* b);
+
+// c := a * (top_b | b) % MOD
+void p256_modmul(
+    const p256_int* MOD,
+    const p256_int* a,
+    const p256_digit top_b,
+    const p256_int* b,
+    p256_int* c);
+
+// b := 1 / a % MOD
+// MOD best be SECP256r1_n
+void p256_modinv(
+    const p256_int* MOD,
+    const p256_int* a,
+    p256_int* b);
+
+// b := 1 / a % MOD
+// MOD best be SECP256r1_n
+// Faster than p256_modinv()
+void p256_modinv_vartime(
+    const p256_int* MOD,
+    const p256_int* a,
+    p256_int* b);
+
+// b := a << (n % P256_BITSPERDIGIT)
+// Returns the bits shifted out of most significant digit.
+p256_digit p256_shl(const p256_int* a, int n, p256_int* b);
+
+// b := a >> (n % P256_BITSPERDIGIT)
+void p256_shr(const p256_int* a, int n, p256_int* b);
+
+int p256_is_zero(const p256_int* a);
+int p256_is_odd(const p256_int* a);
+int p256_is_even(const p256_int* a);
+
+// Returns -1, 0 or 1.
+int p256_cmp(const p256_int* a, const p256_int *b);
+
+// c: = a - b
+// Returns -1 on borrow.
+int p256_sub(const p256_int* a, const p256_int* b, p256_int* c);
+
+// c := a + b
+// Returns 1 on carry.
+int p256_add(const p256_int* a, const p256_int* b, p256_int* c);
+
+// c := a + (single digit)b
+// Returns carry 1 on carry.
+int p256_add_d(const p256_int* a, p256_digit b, p256_int* c);
+
+// ec routines.
+
+// {out_x,out_y} := nG
+void p256_base_point_mul(const p256_int *n,
+                         p256_int *out_x,
+                         p256_int *out_y);
+
+// {out_x,out_y} := n{in_x,in_y}
+void p256_point_mul(const p256_int *n,
+                    const p256_int *in_x,
+                    const p256_int *in_y,
+                    p256_int *out_x,
+                    p256_int *out_y);
+
+// {out_x,out_y} := n1G + n2{in_x,in_y}
+void p256_points_mul_vartime(
+    const p256_int *n1, const p256_int *n2,
+    const p256_int *in_x, const p256_int *in_y,
+    p256_int *out_x, p256_int *out_y);
+
+// Return whether point {x,y} is on curve.
+int p256_is_valid_point(const p256_int* x, const p256_int* y);
+
+// Outputs big-endian binary form. No leading zero skips.
+void p256_to_bin(const p256_int* src, uint8_t dst[P256_NBYTES]);
+
+// Reads from big-endian binary form,
+// thus pre-pad with leading zeros if short.
+void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst);
+
+#define P256_DIGITS(x) ((x)->a)
+#define P256_DIGIT(x,y) ((x)->a[y])
+
+#define P256_ZERO {{0}}
+#define P256_ONE {{1}}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
diff --git a/include/mincrypt/p256_ecdsa.h b/include/mincrypt/p256_ecdsa.h
new file mode 100644
index 0000000..da339fa
--- /dev/null
+++ b/include/mincrypt/p256_ecdsa.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google Inc. nor the names of its contributors may
+ *       be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
+
+// Using current directory as relative include path here since
+// this code typically gets lifted into a variety of build systems
+// and directory structures.
+#include "p256.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Returns 0 if {r,s} is not a signature on message for
+// public key {key_x,key_y}.
+//
+// Note: message is a p256_int.
+// Convert from a binary string using p256_from_bin().
+int p256_ecdsa_verify(const p256_int* key_x,
+                      const p256_int* key_y,
+                      const p256_int* message,
+                      const p256_int* r, const p256_int* s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
diff --git a/include/mincrypt/rsa.h b/include/mincrypt/rsa.h
index cc0e800..3d0556b 100644
--- a/include/mincrypt/rsa.h
+++ b/include/mincrypt/rsa.h
@@ -25,8 +25,8 @@
 ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
-#ifndef _EMBEDDED_RSA_H_
-#define _EMBEDDED_RSA_H_
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
 
 #include <inttypes.h>
 
@@ -55,4 +55,4 @@
 }
 #endif
 
-#endif
+#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
diff --git a/include/mincrypt/sha.h b/include/mincrypt/sha.h
index 120ddcb..ef60aab 100644
--- a/include/mincrypt/sha.h
+++ b/include/mincrypt/sha.h
@@ -1,8 +1,30 @@
-// Copyright 2005 Google Inc. All Rights Reserved.
-// Author: mschilder@google.com (Marius Schilder)
-
-#ifndef SECURITY_UTIL_LITE_SHA1_H__
-#define SECURITY_UTIL_LITE_SHA1_H__
+/*
+ * Copyright 2005 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google Inc. nor the names of its contributors may
+ *       be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
 
 #include <stdint.h>
 #include "hash-internal.h"
@@ -27,4 +49,4 @@
 }
 #endif // __cplusplus
 
-#endif  // SECURITY_UTIL_LITE_SHA1_H__
+#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
diff --git a/include/mincrypt/sha256.h b/include/mincrypt/sha256.h
index 0f3efb7..3a87c31 100644
--- a/include/mincrypt/sha256.h
+++ b/include/mincrypt/sha256.h
@@ -1,8 +1,31 @@
-// Copyright 2011 Google Inc. All Rights Reserved.
-// Author: mschilder@google.com (Marius Schilder)
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google Inc. nor the names of its contributors may
+ *       be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 
-#ifndef SECURITY_UTIL_LITE_SHA256_H__
-#define SECURITY_UTIL_LITE_SHA256_H__
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
 
 #include <stdint.h>
 #include "hash-internal.h"
@@ -26,4 +49,4 @@
 }
 #endif // __cplusplus
 
-#endif  // SECURITY_UTIL_LITE_SHA256_H__
+#endif  // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
diff --git a/init/Android.mk b/init/Android.mk
index abfc68a..1f43ba6 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -10,7 +10,6 @@
 	property_service.c \
 	util.c \
 	parser.c \
-	logo.c \
 	keychords.c \
 	signal_handler.c \
 	init_parser.c \
diff --git a/init/builtins.c b/init/builtins.c
index e8c8f91..e2932d5 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -797,12 +797,24 @@
 
 int do_restorecon(int nargs, char **args) {
     int i;
+    int ret = 0;
 
     for (i = 1; i < nargs; i++) {
         if (restorecon(args[i]) < 0)
-            return -errno;
+            ret = -errno;
     }
-    return 0;
+    return ret;
+}
+
+int do_restorecon_recursive(int nargs, char **args) {
+    int i;
+    int ret = 0;
+
+    for (i = 1; i < nargs; i++) {
+        if (restorecon_recursive(args[i]) < 0)
+            ret = -errno;
+    }
+    return ret;
 }
 
 int do_setsebool(int nargs, char **args) {
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..864fc6c 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)) {
@@ -657,29 +654,28 @@
         have_console = 1;
     close(fd);
 
-    if( load_565rle_image(INIT_IMAGE_FILE) ) {
-        fd = open("/dev/tty0", O_WRONLY);
-        if (fd >= 0) {
-            const char *msg;
-                msg = "\n"
-            "\n"
-            "\n"
-            "\n"
-            "\n"
-            "\n"
-            "\n"  // console is 40 cols x 30 lines
-            "\n"
-            "\n"
-            "\n"
-            "\n"
-            "\n"
-            "\n"
-            "\n"
-            "             A N D R O I D ";
-            write(fd, msg, strlen(msg));
-            close(fd);
-        }
+    fd = open("/dev/tty0", O_WRONLY);
+    if (fd >= 0) {
+        const char *msg;
+            msg = "\n"
+        "\n"
+        "\n"
+        "\n"
+        "\n"
+        "\n"
+        "\n"  // console is 40 cols x 30 lines
+        "\n"
+        "\n"
+        "\n"
+        "\n"
+        "\n"
+        "\n"
+        "\n"
+        "             A N D R O I D ";
+        write(fd, msg, strlen(msg));
+        close(fd);
     }
+
     return 0;
 }
 
diff --git a/init/init.h b/init/init.h
index aa6a4ab..736b75b 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 {
@@ -132,10 +133,6 @@
 void service_start(struct service *svc, const char *dynamic_args);
 void property_changed(const char *name, const char *value);
 
-#define INIT_IMAGE_FILE	"/initlogo.rle"
-
-int load_565rle_image( char *file_name );
-
 extern struct selabel_handle *sehandle;
 extern struct selabel_handle *sehandle_prop;
 extern int selinux_reload_policy(void);
diff --git a/init/init_parser.c b/init/init_parser.c
index 776c699..3f0838f 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -135,6 +135,7 @@
     case 'r':
         if (!strcmp(s, "estart")) return K_restart;
         if (!strcmp(s, "estorecon")) return K_restorecon;
+        if (!strcmp(s, "estorecon_recursive")) return K_restorecon_recursive;
         if (!strcmp(s, "mdir")) return K_rmdir;
         if (!strcmp(s, "m")) return K_rm;
         break;
@@ -552,12 +553,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 +774,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 +797,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/keywords.h b/init/keywords.h
index 5a44df3..97fe50c 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -17,6 +17,7 @@
 int do_powerctl(int nargs, char **args);
 int do_restart(int nargs, char **args);
 int do_restorecon(int nargs, char **args);
+int do_restorecon_recursive(int nargs, char **args);
 int do_rm(int nargs, char **args);
 int do_rmdir(int nargs, char **args);
 int do_setcon(int nargs, char **args);
@@ -71,6 +72,7 @@
     KEYWORD(powerctl,    COMMAND, 1, do_powerctl)
     KEYWORD(restart,     COMMAND, 1, do_restart)
     KEYWORD(restorecon,  COMMAND, 1, do_restorecon)
+    KEYWORD(restorecon_recursive,  COMMAND, 1, do_restorecon_recursive)
     KEYWORD(rm,          COMMAND, 1, do_rm)
     KEYWORD(rmdir,       COMMAND, 1, do_rmdir)
     KEYWORD(seclabel,    OPTION,  0, 0)
diff --git a/init/logo.c b/init/logo.c
deleted file mode 100644
index 614224c..0000000
--- a/init/logo.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2008 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 <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <linux/fb.h>
-#include <linux/kd.h>
-
-#include "log.h"
-
-#ifdef ANDROID
-#include <cutils/memory.h>
-#else
-void android_memset16(void *_ptr, unsigned short val, unsigned count)
-{
-    unsigned short *ptr = _ptr;
-    count >>= 1;
-    while(count--)
-        *ptr++ = val;
-}
-#endif
-
-struct FB {
-    unsigned short *bits;
-    unsigned size;
-    int fd;
-    struct fb_fix_screeninfo fi;
-    struct fb_var_screeninfo vi;
-};
-
-#define fb_width(fb) ((fb)->vi.xres)
-#define fb_height(fb) ((fb)->vi.yres)
-#define fb_size(fb) ((fb)->vi.xres * (fb)->vi.yres * 2)
-
-static int fb_open(struct FB *fb)
-{
-    fb->fd = open("/dev/graphics/fb0", O_RDWR);
-    if (fb->fd < 0)
-        return -1;
-
-    if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0)
-        goto fail;
-    if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0)
-        goto fail;
-
-    fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE, 
-                    MAP_SHARED, fb->fd, 0);
-    if (fb->bits == MAP_FAILED)
-        goto fail;
-
-    return 0;
-
-fail:
-    close(fb->fd);
-    return -1;
-}
-
-static void fb_close(struct FB *fb)
-{
-    munmap(fb->bits, fb_size(fb));
-    close(fb->fd);
-}
-
-/* there's got to be a more portable way to do this ... */
-static void fb_update(struct FB *fb)
-{
-    fb->vi.yoffset = 1;
-    ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);
-    fb->vi.yoffset = 0;
-    ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);
-}
-
-static int vt_set_mode(int graphics)
-{
-    int fd, r;
-    fd = open("/dev/tty0", O_RDWR | O_SYNC);
-    if (fd < 0)
-        return -1;
-    r = ioctl(fd, KDSETMODE, (void*) (graphics ? KD_GRAPHICS : KD_TEXT));
-    close(fd);
-    return r;
-}
-
-/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
-
-int load_565rle_image(char *fn)
-{
-    struct FB fb;
-    struct stat s;
-    unsigned short *data, *bits, *ptr;
-    unsigned count, max;
-    int fd;
-
-    if (vt_set_mode(1)) 
-        return -1;
-
-    fd = open(fn, O_RDONLY);
-    if (fd < 0) {
-        ERROR("cannot open '%s'\n", fn);
-        goto fail_restore_text;
-    }
-
-    if (fstat(fd, &s) < 0) {
-        goto fail_close_file;
-    }
-
-    data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
-    if (data == MAP_FAILED)
-        goto fail_close_file;
-
-    if (fb_open(&fb))
-        goto fail_unmap_data;
-
-    max = fb_width(&fb) * fb_height(&fb);
-    ptr = data;
-    count = s.st_size;
-    bits = fb.bits;
-    while (count > 3) {
-        unsigned n = ptr[0];
-        if (n > max)
-            break;
-        android_memset16(bits, ptr[1], n << 1);
-        bits += n;
-        max -= n;
-        ptr += 2;
-        count -= 4;
-    }
-
-    munmap(data, s.st_size);
-    fb_update(&fb);
-    fb_close(&fb);
-    close(fd);
-    unlink(fn);
-    return 0;
-
-fail_unmap_data:
-    munmap(data, s.st_size);    
-fail_close_file:
-    close(fd);
-fail_restore_text:
-    vt_set_mode(0);
-    return -1;
-}
-
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..42a09cb 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.
@@ -189,12 +192,18 @@
    device by name.
    <mountoption>s include "ro", "rw", "remount", "noatime", ...
 
-restorecon <path>
+restorecon <path> [ <path> ]*
    Restore the file named by <path> to the security context specified
    in the file_contexts configuration.
    Not required for directories created by the init.rc as these are
    automatically labeled correctly by init.
 
+restorecon_recursive <path> [ <path> ]*
+   Recursively restore the directory tree named by <path> to the
+   security contexts specified in the file_contexts configuration.
+   Do NOT use this with paths leading to shell-writable or app-writable
+   directories, e.g. /data/local/tmp, /data/data or any prefix thereof.
+
 setcon <securitycontext>
    Set the current process security context to the specified string.
    This is typically only used from early-init to set the init context
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..66d7e62
--- /dev/null
+++ b/libbacktrace/Android.mk
@@ -0,0 +1,265 @@
+LOCAL_PATH:= $(call my-dir)
+
+common_src := \
+	Backtrace.cpp \
+	BacktraceThread.cpp \
+	map_info.c \
+	thread_utils.c \
+
+common_cflags := \
+	-Wall \
+	-Wno-unused-parameter \
+	-Werror \
+
+common_conlyflags := \
+	-std=gnu99 \
+
+common_cppflags := \
+	-std=gnu++11 \
+
+common_shared_libs := \
+	libcutils \
+	libgccdemangle \
+	liblog \
+
+# To enable using libunwind on each arch, add it to the list below.
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),))
+
+#----------------------------------------------------------------------------
+# The native libbacktrace library with libunwind.
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	$(common_src) \
+	UnwindCurrent.cpp \
+	UnwindPtrace.cpp \
+
+LOCAL_CFLAGS := \
+	$(common_cflags) \
+
+LOCAL_CONLYFLAGS += \
+	$(common_conlyflags) \
+
+LOCAL_CPPFLAGS += \
+	$(common_cppflags) \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_C_INCLUDES := \
+	$(common_c_includes) \
+	external/libunwind/include \
+
+LOCAL_SHARED_LIBRARIES := \
+	$(common_shared_libs) \
+	libunwind \
+	libunwind-ptrace \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
+include external/stlport/libstlport.mk
+
+include $(BUILD_SHARED_LIBRARY)
+
+else
+
+#----------------------------------------------------------------------------
+# The native libbacktrace library with libcorkscrew.
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	$(common_src) \
+	Corkscrew.cpp \
+
+LOCAL_CFLAGS := \
+	$(common_cflags) \
+
+LOCAL_CONLYFLAGS += \
+	$(common_conlyflags) \
+
+LOCAL_CPPFLAGS += \
+	$(common_cppflags) \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_C_INCLUDES := \
+	$(common_c_includes) \
+	system/core/libcorkscrew \
+
+LOCAL_SHARED_LIBRARIES := \
+	$(common_shared_libs) \
+	libcorkscrew \
+	libdl \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
+include external/stlport/libstlport.mk
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
+
+#----------------------------------------------------------------------------
+# libbacktrace test library, all optimizations turned off
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbacktrace_test
+LOCAL_MODULE_FLAGS := debug
+
+LOCAL_SRC_FILES := \
+	backtrace_testlib.c
+
+LOCAL_CFLAGS += \
+	-std=gnu99 \
+	-O0 \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
+include $(BUILD_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# libbacktrace test executable
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := backtrace_test
+LOCAL_MODULE_FLAGS := debug
+
+LOCAL_SRC_FILES := \
+	backtrace_test.cpp \
+	thread_utils.c \
+
+LOCAL_CFLAGS += \
+	-fno-builtin \
+	-fstack-protector-all \
+	-O0 \
+	-g \
+	-DGTEST_OS_LINUX_ANDROID \
+	-DGTEST_HAS_STD_STRING \
+
+LOCAL_CONLYFLAGS += \
+	$(common_conlyflags) \
+
+LOCAL_CPPFLAGS += \
+	$(common_cppflags) \
+	-fpermissive \
+
+LOCAL_SHARED_LIBRARIES += \
+	libcutils \
+	libbacktrace_test \
+	libbacktrace \
+
+LOCAL_LDLIBS := \
+	-lpthread \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
+include $(BUILD_NATIVE_TEST)
+
+#----------------------------------------------------------------------------
+# 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 += \
+	$(common_src) \
+	Corkscrew.cpp \
+
+LOCAL_CFLAGS += \
+	$(common_cflags) \
+
+LOCAL_CONLYFLAGS += \
+	$(common_conlyflags) \
+
+LOCAL_CPPFLAGS += \
+	$(common_cppflags) \
+
+LOCAL_C_INCLUDES := \
+	$(common_c_includes) \
+	system/core/libcorkscrew \
+
+LOCAL_SHARED_LIBRARIES := \
+	libgccdemangle \
+	liblog \
+	libcorkscrew \
+
+LOCAL_LDLIBS += \
+	-ldl \
+	-lrt \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
+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 \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# libbacktrace host test executable
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := backtrace_test
+LOCAL_MODULE_FLAGS := debug
+
+LOCAL_SRC_FILES := \
+	backtrace_test.cpp \
+	thread_utils.c \
+
+LOCAL_CFLAGS += \
+	-fno-builtin \
+	-fstack-protector-all \
+	-O0 \
+	-g \
+	-DGTEST_HAS_STD_STRING \
+
+LOCAL_SHARED_LIBRARIES := \
+	libbacktrace_test \
+	libbacktrace \
+
+LOCAL_CPPFLAGS += \
+	-fpermissive \
+
+LOCAL_LDLIBS := \
+	-lpthread \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+	$(LOCAL_PATH)/Android.mk
+
+include $(BUILD_HOST_NATIVE_TEST)
+
+endif # HOST_OS-HOST_ARCH == linux-x86
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
new file mode 100644
index 0000000..eca1c3d
--- /dev/null
+++ b/libbacktrace/Backtrace.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <string>
+
+#include <backtrace/Backtrace.h>
+#include <cutils/log.h>
+
+#include "Backtrace.h"
+#include "thread_utils.h"
+
+//-------------------------------------------------------------------------
+// BacktraceImpl functions.
+//-------------------------------------------------------------------------
+backtrace_t* BacktraceImpl::GetBacktraceData() {
+  return &backtrace_obj_->backtrace_;
+}
+
+//-------------------------------------------------------------------------
+// Backtrace functions.
+//-------------------------------------------------------------------------
+Backtrace::Backtrace(BacktraceImpl* impl) : impl_(impl), map_info_(NULL) {
+  impl_->SetParent(this);
+  backtrace_.num_frames = 0;
+  backtrace_.pid = -1;
+  backtrace_.tid = -1;
+}
+
+Backtrace::~Backtrace() {
+  for (size_t i = 0; i < NumFrames(); i++) {
+    if (backtrace_.frames[i].func_name) {
+      free(backtrace_.frames[i].func_name);
+      backtrace_.frames[i].func_name = NULL;
+    }
+  }
+
+  if (map_info_) {
+    backtrace_destroy_map_info_list(map_info_);
+    map_info_ = NULL;
+  }
+
+  if (impl_) {
+    delete impl_;
+    impl_ = NULL;
+  }
+}
+
+bool Backtrace::Unwind(size_t num_ignore_frames) {
+  return impl_->Unwind(num_ignore_frames);
+}
+
+__BEGIN_DECLS
+extern char* __cxa_demangle (const char* mangled, char* buf, size_t* len,
+                             int* status);
+__END_DECLS
+
+std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
+  std::string func_name = impl_->GetFunctionNameRaw(pc, offset);
+  if (!func_name.empty()) {
+#if defined(__APPLE__)
+    // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
+    if (symbol_name[0] != '_') {
+      return func_name;
+    }
+#endif
+    char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0);
+    if (name) {
+      func_name = name;
+      free(name);
+    }
+  }
+  return func_name;
+}
+
+bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) {
+  if (ptr & 3) {
+    ALOGW("Backtrace::verifyReadWordArgs: invalid pointer %p", (void*)ptr);
+    *out_value = (uint32_t)-1;
+    return false;
+  }
+  return true;
+}
+
+const char* Backtrace::GetMapName(uintptr_t pc, uintptr_t* map_start) {
+  const backtrace_map_info_t* map_info = FindMapInfo(pc);
+  if (map_info) {
+    if (map_start) {
+      *map_start = map_info->start;
+    }
+    return map_info->name;
+  }
+  return NULL;
+}
+
+const backtrace_map_info_t* Backtrace::FindMapInfo(uintptr_t ptr) {
+  return backtrace_find_map_info(map_info_, ptr);
+}
+
+std::string Backtrace::FormatFrameData(size_t frame_num) {
+  backtrace_frame_data_t* frame = &backtrace_.frames[frame_num];
+  const char* map_name;
+  if (frame->map_name) {
+    map_name = frame->map_name;
+  } else {
+    map_name = "<unknown>";
+  }
+  uintptr_t relative_pc;
+  if (frame->map_offset) {
+    relative_pc = frame->map_offset;
+  } else {
+    relative_pc = frame->pc;
+  }
+
+  char buf[512];
+  if (frame->func_name && frame->func_offset) {
+    snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR "  %s (%s+%" PRIuPTR ")",
+             frame_num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
+             frame->func_name, frame->func_offset);
+  } else if (frame->func_name) {
+    snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR "  %s (%s)", frame_num,
+             (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name);
+  } else {
+    snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR "  %s", frame_num,
+             (int)sizeof(uintptr_t)*2, relative_pc, map_name);
+  }
+
+  return buf;
+}
+
+//-------------------------------------------------------------------------
+// BacktraceCurrent functions.
+//-------------------------------------------------------------------------
+BacktraceCurrent::BacktraceCurrent(BacktraceImpl* impl) : Backtrace(impl) {
+  map_info_ = backtrace_create_map_info_list(-1);
+
+  backtrace_.pid = getpid();
+}
+
+BacktraceCurrent::~BacktraceCurrent() {
+}
+
+bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) {
+  if (!VerifyReadWordArgs(ptr, out_value)) {
+    return false;
+  }
+
+  const backtrace_map_info_t* map_info = FindMapInfo(ptr);
+  if (map_info && map_info->is_readable) {
+    *out_value = *reinterpret_cast<uint32_t*>(ptr);
+    return true;
+  } else {
+    ALOGW("BacktraceCurrent::readWord: pointer %p not in a readbale map", reinterpret_cast<void*>(ptr));
+    *out_value = static_cast<uint32_t>(-1);
+    return false;
+  }
+}
+
+//-------------------------------------------------------------------------
+// BacktracePtrace functions.
+//-------------------------------------------------------------------------
+BacktracePtrace::BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid)
+    : Backtrace(impl) {
+  map_info_ = backtrace_create_map_info_list(tid);
+
+  backtrace_.pid = pid;
+  backtrace_.tid = tid;
+}
+
+BacktracePtrace::~BacktracePtrace() {
+}
+
+bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) {
+  if (!VerifyReadWordArgs(ptr, out_value)) {
+    return false;
+  }
+
+#if defined(__APPLE__)
+  ALOGW("BacktracePtrace::readWord: MacOS does not support reading from another pid.\n");
+  return false;
+#else
+  // ptrace() returns -1 and sets errno when the operation fails.
+  // To disambiguate -1 from a valid result, we clear errno beforehand.
+  errno = 0;
+  *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
+  if (*out_value == static_cast<uint32_t>(-1) && errno) {
+    ALOGW("BacktracePtrace::readWord: invalid pointer 0x%08x reading from tid %d, "
+          "ptrace() errno=%d", ptr, Tid(), errno);
+    return false;
+  }
+  return true;
+#endif
+}
+
+Backtrace* Backtrace::Create(pid_t pid, pid_t tid) {
+  if (pid < 0 || pid == getpid()) {
+    if (tid < 0 || tid == gettid()) {
+      return CreateCurrentObj();
+    } else {
+      return CreateThreadObj(tid);
+    }
+  } else if (tid < 0) {
+    return CreatePtraceObj(pid, pid);
+  } else {
+    return CreatePtraceObj(pid, tid);
+  }
+}
+
+//-------------------------------------------------------------------------
+// Common interface functions.
+//-------------------------------------------------------------------------
+bool backtrace_create_context(
+    backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames) {
+  Backtrace* backtrace = Backtrace::Create(pid, tid);
+  if (!backtrace) {
+    return false;
+  }
+  if (!backtrace->Unwind(num_ignore_frames)) {
+    delete backtrace;
+    return false;
+  }
+
+  context->data = backtrace;
+  context->backtrace = backtrace->GetBacktrace();
+  return true;
+}
+
+void backtrace_destroy_context(backtrace_context_t* context) {
+  if (context->data) {
+    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+    delete backtrace;
+    context->data = NULL;
+  }
+  context->backtrace = NULL;
+}
+
+const backtrace_t* backtrace_get_data(backtrace_context_t* context) {
+  if (context && context->data) {
+    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+    return backtrace->GetBacktrace();
+  }
+  return NULL;
+}
+
+bool backtrace_read_word(const backtrace_context_t* context, uintptr_t ptr, uint32_t* value) {
+  if (context->data) {
+    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+    return backtrace->ReadWord(ptr, value);
+  }
+  return true;
+}
+
+const char* backtrace_get_map_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start) {
+  if (context->data) {
+    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+    return backtrace->GetMapName(pc, map_start);
+  }
+  return NULL;
+}
+
+char* backtrace_get_func_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset) {
+  if (context->data) {
+    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+    std::string func_name = backtrace->GetFunctionName(pc, func_offset);
+    if (!func_name.empty()) {
+      return strdup(func_name.c_str());
+    }
+  }
+  return NULL;
+}
+
+void backtrace_format_frame_data(
+    const backtrace_context_t* context, size_t frame_num, char* buf,
+    size_t buf_size) {
+  if (buf_size == 0 || buf == NULL) {
+    ALOGW("backtrace_format_frame_data: bad call buf %p buf_size %zu\n",
+          buf, buf_size);
+    return;
+  }
+  if (context->data) {
+    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+    std::string line = backtrace->FormatFrameData(frame_num);
+    if (line.size() > buf_size) {
+      memcpy(buf, line.c_str(), buf_size-1);
+      buf[buf_size] = '\0';
+    } else {
+      memcpy(buf, line.c_str(), line.size()+1);
+    }
+  }
+}
diff --git a/libbacktrace/Backtrace.h b/libbacktrace/Backtrace.h
new file mode 100644
index 0000000..b89bc89
--- /dev/null
+++ b/libbacktrace/Backtrace.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_BACKTRACE_H
+#define _LIBBACKTRACE_BACKTRACE_H
+
+#include <backtrace/Backtrace.h>
+
+#include <sys/types.h>
+
+class BacktraceImpl {
+public:
+  virtual ~BacktraceImpl() { }
+
+  virtual bool Unwind(size_t num_ignore_frames) = 0;
+
+  // The name returned is not demangled, Backtrace::GetFunctionName()
+  // takes care of demangling the name.
+  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0;
+
+  void SetParent(Backtrace* backtrace) { backtrace_obj_ = backtrace; }
+
+protected:
+  backtrace_t* GetBacktraceData();
+
+  Backtrace* backtrace_obj_;
+};
+
+class BacktraceCurrent : public Backtrace {
+public:
+  BacktraceCurrent(BacktraceImpl* impl);
+  virtual ~BacktraceCurrent();
+
+  bool ReadWord(uintptr_t ptr, uint32_t* out_value);
+};
+
+class BacktracePtrace : public Backtrace {
+public:
+  BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid);
+  virtual ~BacktracePtrace();
+
+  bool ReadWord(uintptr_t ptr, uint32_t* out_value);
+};
+
+Backtrace* CreateCurrentObj();
+Backtrace* CreatePtraceObj(pid_t pid, pid_t tid);
+Backtrace* CreateThreadObj(pid_t tid);
+
+#endif // _LIBBACKTRACE_BACKTRACE_H
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp
new file mode 100644
index 0000000..6c3641e
--- /dev/null
+++ b/libbacktrace/BacktraceThread.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <cutils/atomic.h>
+#include <cutils/log.h>
+
+#include "BacktraceThread.h"
+#include "thread_utils.h"
+
+//-------------------------------------------------------------------------
+// ThreadEntry implementation.
+//-------------------------------------------------------------------------
+static ThreadEntry* g_list = NULL;
+static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+ThreadEntry::ThreadEntry(
+    BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames)
+    : thread_intf_(intf), pid_(pid), tid_(tid), next_(NULL), prev_(NULL),
+      state_(STATE_WAITING), num_ignore_frames_(num_ignore_frames) {
+}
+
+ThreadEntry::~ThreadEntry() {
+  pthread_mutex_lock(&g_mutex);
+  if (g_list == this) {
+    g_list = next_;
+  } else {
+    if (next_) {
+      next_->prev_ = prev_;
+    }
+    prev_->next_ = next_;
+  }
+  pthread_mutex_unlock(&g_mutex);
+
+  next_ = NULL;
+  prev_ = NULL;
+}
+
+ThreadEntry* ThreadEntry::AddThreadToUnwind(
+    BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) {
+  ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames);
+
+  pthread_mutex_lock(&g_mutex);
+  ThreadEntry* cur_entry = g_list;
+  while (cur_entry != NULL) {
+    if (cur_entry->Match(pid, tid)) {
+      // There is already an entry for this pid/tid, this is bad.
+      ALOGW("%s::%s(): Entry for pid %d tid %d already exists.\n",
+            __FILE__, __FUNCTION__, pid, tid);
+
+      pthread_mutex_unlock(&g_mutex);
+      return NULL;
+    }
+    cur_entry = cur_entry->next_;
+  }
+
+  // Add the entry to the list.
+  entry->next_ = g_list;
+  if (g_list) {
+    g_list->prev_ = entry;
+  }
+  g_list = entry;
+  pthread_mutex_unlock(&g_mutex);
+
+  return entry;
+}
+
+//-------------------------------------------------------------------------
+// BacktraceThread functions.
+//-------------------------------------------------------------------------
+static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
+                          void* sigcontext) {
+  if (pthread_mutex_lock(&g_mutex) == 0) {
+    pid_t pid = getpid();
+    pid_t tid = gettid();
+    ThreadEntry* cur_entry = g_list;
+    while (cur_entry) {
+      if (cur_entry->Match(pid, tid)) {
+        break;
+      }
+      cur_entry = cur_entry->next_;
+    }
+    pthread_mutex_unlock(&g_mutex);
+    if (!cur_entry) {
+      ALOGW("%s::%s(): Unable to find pid %d tid %d information\n",
+            __FILE__, __FUNCTION__, pid, tid);
+      return;
+    }
+
+    if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state_) == 0) {
+      cur_entry->thread_intf_->ThreadUnwind(siginfo, sigcontext,
+                                            cur_entry->num_ignore_frames_);
+    }
+    android_atomic_release_store(STATE_DONE, &cur_entry->state_);
+  }
+}
+
+BacktraceThread::BacktraceThread(
+    BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid)
+    : BacktraceCurrent(impl), thread_intf_(thread_intf) {
+  backtrace_.tid = tid;
+}
+
+BacktraceThread::~BacktraceThread() {
+}
+
+void BacktraceThread::FinishUnwind() {
+  for (size_t i = 0; i < NumFrames(); i++) {
+    backtrace_frame_data_t* frame = &backtrace_.frames[i];
+
+    frame->map_offset = 0;
+    uintptr_t map_start;
+    frame->map_name = GetMapName(frame->pc, &map_start);
+    if (frame->map_name) {
+      frame->map_offset = frame->pc - map_start;
+    }
+
+    frame->func_offset = 0;
+    std::string func_name = GetFunctionName(frame->pc, &frame->func_offset);
+    if (!func_name.empty()) {
+      frame->func_name = strdup(func_name.c_str());
+    }
+  }
+}
+
+bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
+  entry->state_ = STATE_WAITING;
+
+  if (tgkill(Pid(), Tid(), SIGURG) != 0) {
+    ALOGW("%s::%s(): tgkill failed %s\n", __FILE__, __FUNCTION__, strerror(errno));
+    return false;
+  }
+
+  // Allow up to a second for the dump to occur.
+  int wait_millis = 1000;
+  int32_t state;
+  while (true) {
+    state = android_atomic_acquire_load(&entry->state_);
+    if (state != STATE_WAITING) {
+      break;
+    }
+    if (wait_millis--) {
+      usleep(1000);
+    } else {
+      break;
+    }
+  }
+
+  bool cancelled = false;
+  if (state == STATE_WAITING) {
+    if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state_) == 0) {
+      ALOGW("%s::%s(): Cancelled dump of thread %d\n", __FILE__, __FUNCTION__,
+            entry->tid_);
+      state = STATE_CANCEL;
+      cancelled = true;
+    } else {
+      state = android_atomic_acquire_load(&entry->state_);
+    }
+  }
+
+  // Wait for at most one minute for the dump to finish.
+  wait_millis = 60000;
+  while (android_atomic_acquire_load(&entry->state_) != STATE_DONE) {
+    if (wait_millis--) {
+      usleep(1000);
+    } else {
+      ALOGW("%s::%s(): Didn't finish thread unwind in 60 seconds.\n",
+            __FILE__, __FUNCTION__);
+      break;
+    }
+  }
+  return !cancelled;
+}
+
+bool BacktraceThread::Unwind(size_t num_ignore_frames) {
+  if (!thread_intf_->Init()) {
+    return false;
+  }
+
+  ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
+      thread_intf_, Pid(), Tid(), num_ignore_frames);
+  if (!entry) {
+    return false;
+  }
+
+  bool retval = false;
+  struct sigaction act, oldact;
+  memset(&act, 0, sizeof(act));
+  act.sa_sigaction = SignalHandler;
+  act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+  sigemptyset(&act.sa_mask);
+  if (sigaction(SIGURG, &act, &oldact) == 0) {
+    retval = TriggerUnwindOnThread(entry);
+    sigaction(SIGURG, &oldact, NULL);
+  } else {
+    ALOGW("%s::%s(): sigaction failed %s\n", __FILE__, __FUNCTION__, strerror(errno));
+  }
+
+  if (retval) {
+    FinishUnwind();
+  }
+  delete entry;
+
+  return retval;
+}
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h
new file mode 100644
index 0000000..afea771
--- /dev/null
+++ b/libbacktrace/BacktraceThread.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_BACKTRACE_THREAD_H
+#define _LIBBACKTRACE_BACKTRACE_THREAD_H
+
+#include <inttypes.h>
+#include <pthread.h>
+#include <sys/types.h>
+
+#include "Backtrace.h"
+
+typedef enum {
+  STATE_WAITING = 0,
+  STATE_DUMPING,
+  STATE_DONE,
+  STATE_CANCEL,
+} state_e;
+
+class BacktraceThreadInterface;
+
+class ThreadEntry {
+public:
+  ThreadEntry(
+      BacktraceThreadInterface* impl, pid_t pid, pid_t tid,
+      size_t num_ignore_frames);
+  ~ThreadEntry();
+
+  bool Match(pid_t pid, pid_t tid) { return (pid == pid_ && tid == tid_); }
+
+  static ThreadEntry* AddThreadToUnwind(
+      BacktraceThreadInterface* thread_intf, pid_t pid, pid_t tid,
+      size_t num_ignored_frames);
+
+  BacktraceThreadInterface* thread_intf_;
+  pid_t pid_;
+  pid_t tid_;
+  ThreadEntry* next_;
+  ThreadEntry* prev_;
+  int32_t state_;
+  int num_ignore_frames_;
+};
+
+// Interface class that does not contain any local storage, only defines
+// virtual functions to be defined by subclasses.
+class BacktraceThreadInterface {
+public:
+  virtual ~BacktraceThreadInterface() { }
+
+  virtual bool Init() = 0;
+
+  virtual void ThreadUnwind(
+      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) = 0;
+};
+
+class BacktraceThread : public BacktraceCurrent {
+public:
+  // impl and thread_intf should point to the same object, this allows
+  // the compiler to catch if an implementation does not properly
+  // subclass both.
+  BacktraceThread(
+      BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid);
+  virtual ~BacktraceThread();
+
+  virtual bool Unwind(size_t num_ignore_frames);
+
+  virtual void ThreadUnwind(
+      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
+    thread_intf_->ThreadUnwind(siginfo, sigcontext, num_ignore_frames);
+  }
+
+private:
+  virtual bool TriggerUnwindOnThread(ThreadEntry* entry);
+
+  virtual void FinishUnwind();
+
+  BacktraceThreadInterface* thread_intf_;
+};
+
+#endif // _LIBBACKTRACE_BACKTRACE_THREAD_H
diff --git a/libbacktrace/Corkscrew.cpp b/libbacktrace/Corkscrew.cpp
new file mode 100644
index 0000000..8ba1e80
--- /dev/null
+++ b/libbacktrace/Corkscrew.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libbacktrace"
+
+#include <backtrace/backtrace.h>
+
+#include <string.h>
+
+#include <backtrace-arch.h>
+#include <cutils/log.h>
+#include <corkscrew/backtrace.h>
+
+#ifndef __USE_GNU
+#define __USE_GNU
+#endif
+#include <dlfcn.h>
+
+#include "Corkscrew.h"
+
+//-------------------------------------------------------------------------
+// CorkscrewCommon functions.
+//-------------------------------------------------------------------------
+bool CorkscrewCommon::GenerateFrameData(
+    backtrace_frame_t* cork_frames, ssize_t num_frames) {
+  if (num_frames < 0) {
+    ALOGW("CorkscrewCommon::GenerateFrameData: libcorkscrew unwind failed.\n");
+    return false;
+  }
+
+  backtrace_t* data = GetBacktraceData();
+  data->num_frames = num_frames;
+  for (size_t i = 0; i < data->num_frames; i++) {
+    backtrace_frame_data_t* frame = &data->frames[i];
+    frame->pc = cork_frames[i].absolute_pc;
+    frame->sp = cork_frames[i].stack_top;
+    frame->stack_size = cork_frames[i].stack_size;
+    frame->map_name = NULL;
+    frame->map_offset = 0;
+    frame->func_name = NULL;
+    frame->func_offset = 0;
+
+    uintptr_t map_start;
+    frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
+    if (frame->map_name) {
+      frame->map_offset = frame->pc - map_start;
+    }
+
+    std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
+    if (!func_name.empty()) {
+      frame->func_name = strdup(func_name.c_str());
+    }
+  }
+  return true;
+}
+
+//-------------------------------------------------------------------------
+// CorkscrewCurrent functions.
+//-------------------------------------------------------------------------
+CorkscrewCurrent::CorkscrewCurrent() {
+}
+
+CorkscrewCurrent::~CorkscrewCurrent() {
+}
+
+bool CorkscrewCurrent::Unwind(size_t num_ignore_frames) {
+  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
+  ssize_t num_frames = unwind_backtrace(frames, num_ignore_frames, MAX_BACKTRACE_FRAMES);
+
+  return GenerateFrameData(frames, num_frames);
+}
+
+std::string CorkscrewCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  *offset = 0;
+
+  // Get information about the current thread.
+  Dl_info info;
+  const backtrace_map_info_t* map_info = backtrace_obj_->FindMapInfo(pc);
+  const char* symbol_name = NULL;
+  if (map_info && dladdr((const void*)pc, &info) && info.dli_sname) {
+    *offset = pc - map_info->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase;
+    symbol_name = info.dli_sname;
+
+    return symbol_name;
+  }
+  return "";
+}
+
+//-------------------------------------------------------------------------
+// CorkscrewThread functions.
+//-------------------------------------------------------------------------
+CorkscrewThread::CorkscrewThread() {
+}
+
+CorkscrewThread::~CorkscrewThread() {
+  if (corkscrew_map_info_) {
+    free_map_info_list(corkscrew_map_info_);
+    corkscrew_map_info_ = NULL;
+  }
+}
+
+bool CorkscrewThread::Init() {
+  corkscrew_map_info_ = load_map_info_list(backtrace_obj_->Pid());
+  return corkscrew_map_info_ != NULL;
+}
+
+void CorkscrewThread::ThreadUnwind(
+    siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
+  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
+  ssize_t num_frames = unwind_backtrace_signal_arch(
+      siginfo, sigcontext, corkscrew_map_info_, frames, num_ignore_frames,
+      MAX_BACKTRACE_FRAMES);
+  if (num_frames > 0) {
+    backtrace_t* data = GetBacktraceData();
+    data->num_frames = num_frames;
+    for (size_t i = 0; i < data->num_frames; i++) {
+      backtrace_frame_data_t* frame = &data->frames[i];
+      frame->pc = frames[i].absolute_pc;
+      frame->sp = frames[i].stack_top;
+      frame->stack_size = frames[i].stack_size;
+
+      frame->map_offset = 0;
+      frame->map_name = NULL;
+      frame->map_offset = 0;
+
+      frame->func_offset = 0;
+      frame->func_name = NULL;
+    }
+  }
+}
+
+//-------------------------------------------------------------------------
+// CorkscrewPtrace functions.
+//-------------------------------------------------------------------------
+CorkscrewPtrace::CorkscrewPtrace() : ptrace_context_(NULL) {
+}
+
+CorkscrewPtrace::~CorkscrewPtrace() {
+  if (ptrace_context_) {
+    free_ptrace_context(ptrace_context_);
+    ptrace_context_ = NULL;
+  }
+}
+
+bool CorkscrewPtrace::Unwind(size_t num_ignore_frames) {
+  ptrace_context_ = load_ptrace_context(backtrace_obj_->Tid());
+
+  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
+  ssize_t num_frames = unwind_backtrace_ptrace(
+      backtrace_obj_->Tid(), ptrace_context_, frames, num_ignore_frames,
+      MAX_BACKTRACE_FRAMES);
+
+  return GenerateFrameData(frames, num_frames);
+}
+
+std::string CorkscrewPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  // Get information about a different process.
+  const map_info_t* map_info;
+  const symbol_t* symbol;
+  find_symbol_ptrace(ptrace_context_, pc, &map_info, &symbol);
+  char* symbol_name = NULL;
+  if (symbol) {
+    if (map_info) {
+      *offset = pc - map_info->start - symbol->start;
+    }
+    symbol_name = symbol->name;
+    return symbol_name;
+  }
+
+  return "";
+}
+
+//-------------------------------------------------------------------------
+// C++ object createion functions.
+//-------------------------------------------------------------------------
+Backtrace* CreateCurrentObj() {
+  return new BacktraceCurrent(new CorkscrewCurrent());
+}
+
+Backtrace* CreatePtraceObj(pid_t pid, pid_t tid) {
+  return new BacktracePtrace(new CorkscrewPtrace(), pid, tid);
+}
+
+Backtrace* CreateThreadObj(pid_t tid) {
+  CorkscrewThread* thread_obj = new CorkscrewThread();
+  return new BacktraceThread(thread_obj, thread_obj, tid);
+}
diff --git a/libbacktrace/Corkscrew.h b/libbacktrace/Corkscrew.h
new file mode 100644
index 0000000..7cb125c
--- /dev/null
+++ b/libbacktrace/Corkscrew.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_CORKSCREW_H
+#define _LIBBACKTRACE_CORKSCREW_H
+
+#include <inttypes.h>
+
+#include <string>
+
+#include <backtrace/backtrace.h>
+#include <backtrace/Backtrace.h>
+
+#include <corkscrew/backtrace.h>
+
+#include "Backtrace.h"
+#include "BacktraceThread.h"
+
+class CorkscrewCommon : public BacktraceImpl {
+public:
+  bool GenerateFrameData(backtrace_frame_t* cork_frames, ssize_t num_frames);
+};
+
+class CorkscrewCurrent : public CorkscrewCommon {
+public:
+  CorkscrewCurrent();
+  virtual ~CorkscrewCurrent();
+
+  virtual bool Unwind(size_t num_ignore_threads);
+
+  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+};
+
+class CorkscrewThread : public CorkscrewCurrent, public BacktraceThreadInterface {
+public:
+  CorkscrewThread();
+  virtual ~CorkscrewThread();
+
+  virtual bool Init();
+
+  virtual void ThreadUnwind(
+      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
+
+private:
+  map_info_t* corkscrew_map_info_;
+};
+
+class CorkscrewPtrace : public CorkscrewCommon {
+public:
+  CorkscrewPtrace();
+  virtual ~CorkscrewPtrace();
+
+  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+  virtual bool Unwind(size_t num_ignore_threads);
+
+private:
+  ptrace_context_t* ptrace_context_;
+};
+
+#endif // _LIBBACKTRACE_CORKSCREW_H
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
new file mode 100644
index 0000000..0280e93
--- /dev/null
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libbacktrace"
+
+#include <sys/types.h>
+
+#include <cutils/log.h>
+
+#include <backtrace/backtrace.h>
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+
+#include "UnwindCurrent.h"
+
+#if defined(__arm__)
+  #if !defined(__BIONIC_HAVE_UCONTEXT_T)
+  // The Current version of the Android <signal.h> doesn't define ucontext_t.
+  #include <asm/sigcontext.h> // Ensure 'struct sigcontext' is defined.
+
+  // Machine context at the time a signal was raised.
+  typedef struct ucontext {
+    uint32_t uc_flags;
+    struct ucontext* uc_link;
+    stack_t uc_stack;
+    struct sigcontext uc_mcontext;
+    uint32_t uc_sigmask;
+  } ucontext_t;
+  #endif // !__BIONIC_HAVE_UCONTEXT_T
+#endif // defined(__arm__)
+
+//-------------------------------------------------------------------------
+// UnwindCurrent functions.
+//-------------------------------------------------------------------------
+UnwindCurrent::UnwindCurrent() {
+}
+
+UnwindCurrent::~UnwindCurrent() {
+}
+
+bool UnwindCurrent::Unwind(size_t num_ignore_frames) {
+  int ret = unw_getcontext(&context_);
+  if (ret < 0) {
+    ALOGW("UnwindCurrent::Unwind: unw_getcontext failed %d\n", ret);
+    return false;
+  }
+  return UnwindFromContext(num_ignore_frames, true);
+}
+
+std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  *offset = 0;
+  char buf[512];
+  unw_word_t value;
+  if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
+                              &value, &context_) >= 0 && buf[0] != '\0') {
+    *offset = static_cast<uintptr_t>(value);
+    return buf;
+  }
+  return "";
+}
+
+bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) {
+  backtrace_t* backtrace = GetBacktraceData();
+  backtrace->num_frames = 0;
+
+  // The cursor structure is pretty large, do not put it on the stack.
+  unw_cursor_t* cursor = new unw_cursor_t;
+  int ret = unw_init_local(cursor, &context_);
+  if (ret < 0) {
+    ALOGW("UnwindCurrent::UnwindWithContext: unw_init_local failed %d\n", ret);
+    return false;
+  }
+
+  do {
+    unw_word_t pc;
+    ret = unw_get_reg(cursor, UNW_REG_IP, &pc);
+    if (ret < 0) {
+      ALOGW("UnwindCurrent::UnwindWithContext: Failed to read IP %d\n", ret);
+      break;
+    }
+    unw_word_t sp;
+    ret = unw_get_reg(cursor, UNW_REG_SP, &sp);
+    if (ret < 0) {
+      ALOGW("UnwindCurrent::UnwindWithContext: Failed to read SP %d\n", ret);
+      break;
+    }
+
+    if (num_ignore_frames == 0) {
+      size_t num_frames = backtrace->num_frames;
+      backtrace_frame_data_t* frame = &backtrace->frames[num_frames];
+      frame->pc = static_cast<uintptr_t>(pc);
+      frame->sp = static_cast<uintptr_t>(sp);
+      frame->stack_size = 0;
+      frame->map_name = NULL;
+      frame->map_offset = 0;
+      frame->func_name = NULL;
+      frame->func_offset = 0;
+
+      if (num_frames > 0) {
+        // Set the stack size for the previous frame.
+        backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1];
+        prev->stack_size = frame->sp - prev->sp;
+      }
+
+      if (resolve) {
+        std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
+        if (!func_name.empty()) {
+          frame->func_name = strdup(func_name.c_str());
+        }
+
+        uintptr_t map_start;
+        frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
+        if (frame->map_name) {
+          frame->map_offset = frame->pc - map_start;
+        }
+      }
+
+      backtrace->num_frames++;
+    } else {
+      num_ignore_frames--;
+    }
+    ret = unw_step (cursor);
+  } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
+
+  delete cursor;
+  return true;
+}
+
+void UnwindCurrent::ExtractContext(void* sigcontext) {
+  unw_tdep_context_t* context = reinterpret_cast<unw_tdep_context_t*>(&context_);
+
+#if defined(__arm__)
+  const ucontext_t* uc = reinterpret_cast<const ucontext_t*>(sigcontext);
+
+  context->regs[0] = uc->uc_mcontext.arm_r0;
+  context->regs[1] = uc->uc_mcontext.arm_r1;
+  context->regs[2] = uc->uc_mcontext.arm_r2;
+  context->regs[3] = uc->uc_mcontext.arm_r3;
+  context->regs[4] = uc->uc_mcontext.arm_r4;
+  context->regs[5] = uc->uc_mcontext.arm_r5;
+  context->regs[6] = uc->uc_mcontext.arm_r6;
+  context->regs[7] = uc->uc_mcontext.arm_r7;
+  context->regs[8] = uc->uc_mcontext.arm_r8;
+  context->regs[9] = uc->uc_mcontext.arm_r9;
+  context->regs[10] = uc->uc_mcontext.arm_r10;
+  context->regs[11] = uc->uc_mcontext.arm_fp;
+  context->regs[12] = uc->uc_mcontext.arm_ip;
+  context->regs[13] = uc->uc_mcontext.arm_sp;
+  context->regs[14] = uc->uc_mcontext.arm_lr;
+  context->regs[15] = uc->uc_mcontext.arm_pc;
+
+#elif defined(__mips__)
+
+  typedef struct ucontext {
+    uint32_t sp;
+    uint32_t ra;
+    uint32_t pc;
+  } ucontext_t;
+
+  const ucontext_t* uc = (const ucontext_t*)sigcontext;
+
+  context->uc_mcontext.sp = uc->sp;
+  context->uc_mcontext.pc = uc->pc;
+  context->uc_mcontext.ra = uc->ra;
+#elif defined(__x86__)
+
+  #include <asm/sigcontext.h>
+  #include <asm/ucontext.h>
+  typedef struct ucontext ucontext_t;
+
+  const ucontext_t* uc = (const ucontext_t*)sigcontext;
+
+  context->uc_mcontext.gregs[REG_EBP] = uc->uc_mcontext.gregs[REG_EBP];
+  context->uc_mcontext.gregs[REG_ESP] = uc->uc_mcontext.gregs[REG_ESP];
+  context->uc_mcontext.gregs[REG_EIP] = uc->uc_mcontext.gregs[REG_EIP];
+#endif
+}
+
+//-------------------------------------------------------------------------
+// UnwindThread functions.
+//-------------------------------------------------------------------------
+UnwindThread::UnwindThread() {
+}
+
+UnwindThread::~UnwindThread() {
+}
+
+bool UnwindThread::Init() {
+  return true;
+}
+
+void UnwindThread::ThreadUnwind(
+    siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) {
+  ExtractContext(sigcontext);
+  UnwindFromContext(num_ignore_frames, false);
+}
+
+//-------------------------------------------------------------------------
+// C++ object creation function.
+//-------------------------------------------------------------------------
+Backtrace* CreateCurrentObj() {
+  return new BacktraceCurrent(new UnwindCurrent());
+}
+
+Backtrace* CreateThreadObj(pid_t tid) {
+  UnwindThread* thread_obj = new UnwindThread();
+  return new BacktraceThread(thread_obj, thread_obj, tid);
+}
diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h
new file mode 100644
index 0000000..7dc977d
--- /dev/null
+++ b/libbacktrace/UnwindCurrent.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_UNWIND_CURRENT_H
+#define _LIBBACKTRACE_UNWIND_CURRENT_H
+
+#include <string>
+
+#include "Backtrace.h"
+#include "BacktraceThread.h"
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+
+class UnwindCurrent : public BacktraceImpl {
+public:
+  UnwindCurrent();
+  virtual ~UnwindCurrent();
+
+  virtual bool Unwind(size_t num_ignore_frames);
+
+  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+  bool UnwindFromContext(size_t num_ignore_frames, bool resolve);
+
+  void ExtractContext(void* sigcontext);
+
+protected:
+  unw_context_t context_;
+};
+
+class UnwindThread : public UnwindCurrent, public BacktraceThreadInterface {
+public:
+  UnwindThread();
+  virtual ~UnwindThread();
+
+  virtual bool Init();
+
+  virtual void ThreadUnwind(
+      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
+};
+
+#endif // _LIBBACKTRACE_UNWIND_CURRENT_H
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
new file mode 100644
index 0000000..628caa0
--- /dev/null
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libbacktrace"
+
+#include <backtrace/backtrace.h>
+
+#include <sys/types.h>
+#include <string.h>
+
+#include <cutils/log.h>
+
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+
+#include "UnwindPtrace.h"
+
+UnwindPtrace::UnwindPtrace() : addr_space_(NULL), upt_info_(NULL) {
+}
+
+UnwindPtrace::~UnwindPtrace() {
+  if (upt_info_) {
+    _UPT_destroy(upt_info_);
+    upt_info_ = NULL;
+  }
+  if (addr_space_) {
+    unw_destroy_addr_space(addr_space_);
+    addr_space_ = NULL;
+  }
+}
+
+bool UnwindPtrace::Unwind(size_t num_ignore_frames) {
+  addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
+  if (!addr_space_) {
+    ALOGW("UnwindPtrace::Unwind: unw_create_addr_space failed.\n");
+    return false;
+  }
+
+  upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(backtrace_obj_->Tid()));
+  if (!upt_info_) {
+    ALOGW("UnwindPtrace::Unwind: Failed to create upt info.\n");
+    return false;
+  }
+
+  backtrace_t* backtrace = GetBacktraceData();
+  backtrace->num_frames = 0;
+
+  unw_cursor_t cursor;
+  int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
+  if (ret < 0) {
+    ALOGW("UnwindPtrace::Unwind: unw_init_remote failed %d\n", ret);
+    return false;
+  }
+
+  do {
+    unw_word_t pc;
+    ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
+    if (ret < 0) {
+      ALOGW("UnwindPtrace::Unwind: Failed to read IP %d\n", ret);
+      break;
+    }
+    unw_word_t sp;
+    ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
+    if (ret < 0) {
+      ALOGW("UnwindPtrace::Unwind: Failed to read SP %d\n", ret);
+      break;
+    }
+
+    if (num_ignore_frames == 0) {
+      size_t num_frames = backtrace->num_frames;
+      backtrace_frame_data_t* frame = &backtrace->frames[num_frames];
+      frame->pc = static_cast<uintptr_t>(pc);
+      frame->sp = static_cast<uintptr_t>(sp);
+      frame->stack_size = 0;
+      frame->map_name = NULL;
+      frame->map_offset = 0;
+      frame->func_name = NULL;
+      frame->func_offset = 0;
+
+      if (num_frames > 0) {
+        backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1];
+        prev->stack_size = frame->sp - prev->sp;
+      }
+
+      std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
+      if (!func_name.empty()) {
+        frame->func_name = strdup(func_name.c_str());
+      }
+
+      uintptr_t map_start;
+      frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
+      if (frame->map_name) {
+        frame->map_offset = frame->pc - map_start;
+      }
+
+      backtrace->num_frames++;
+    } else {
+      num_ignore_frames--;
+    }
+    ret = unw_step (&cursor);
+  } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
+
+  return true;
+}
+
+std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+  *offset = 0;
+  char buf[512];
+  unw_word_t value;
+  if (unw_get_proc_name_by_ip(addr_space_, pc, buf, sizeof(buf), &value,
+                              upt_info_) >= 0 && buf[0] != '\0') {
+    *offset = static_cast<uintptr_t>(value);
+    return buf;
+  }
+  return "";
+}
+
+//-------------------------------------------------------------------------
+// C++ object creation function.
+//-------------------------------------------------------------------------
+Backtrace* CreatePtraceObj(pid_t pid, pid_t tid) {
+  return new BacktracePtrace(new UnwindPtrace(), pid, tid);
+}
diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h
new file mode 100644
index 0000000..781405b
--- /dev/null
+++ b/libbacktrace/UnwindPtrace.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_UNWIND_PTRACE_H
+#define _LIBBACKTRACE_UNWIND_PTRACE_H
+
+#include <string>
+
+#include "Backtrace.h"
+
+#include <libunwind.h>
+
+class UnwindPtrace : public BacktraceImpl {
+public:
+  UnwindPtrace();
+  virtual ~UnwindPtrace();
+
+  virtual bool Unwind(size_t num_ignore_frames);
+
+  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+private:
+  unw_addr_space_t addr_space_;
+  struct UPT_info* upt_info_;
+};
+
+#endif // _LIBBACKTRACE_UNWIND_PTRACE_H
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
new file mode 100644
index 0000000..48e2bdc
--- /dev/null
+++ b/libbacktrace/backtrace_test.cpp
@@ -0,0 +1,660 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <backtrace/backtrace.h>
+
+#include <cutils/atomic.h>
+#include <gtest/gtest.h>
+
+#include <vector>
+
+#include "thread_utils.h"
+
+// Number of microseconds per milliseconds.
+#define US_PER_MSEC             1000
+
+// Number of nanoseconds in a second.
+#define NS_PER_SEC              1000000000ULL
+
+// Number of simultaneous dumping operations to perform.
+#define NUM_THREADS  20
+
+// Number of simultaneous threads running in our forked process.
+#define NUM_PTRACE_THREADS 5
+
+typedef struct {
+  pid_t tid;
+  int32_t state;
+  pthread_t threadId;
+} thread_t;
+
+typedef struct {
+  thread_t thread;
+  backtrace_context_t context;
+  int32_t* now;
+  int32_t done;
+} dump_thread_t;
+
+extern "C" {
+// Prototypes for functions in the test library.
+int test_level_one(int, int, int, int, void (*)(void*), void*);
+
+int test_recursive_call(int, void (*)(void*), void*);
+}
+
+uint64_t NanoTime() {
+  struct timespec t = { 0, 0 };
+  clock_gettime(CLOCK_MONOTONIC, &t);
+  return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec);
+}
+
+void DumpFrames(const backtrace_context_t* context) {
+  if (context->backtrace->num_frames == 0) {
+    printf("    No frames to dump\n");
+  } else {
+    char line[512];
+    for (size_t i = 0; i < context->backtrace->num_frames; i++) {
+      backtrace_format_frame_data(context, i, line, sizeof(line));
+      printf("    %s\n", line);
+    }
+  }
+}
+
+void WaitForStop(pid_t pid) {
+  uint64_t start = NanoTime();
+
+  siginfo_t si;
+  while (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) < 0 && (errno == EINTR || errno == ESRCH)) {
+    if ((NanoTime() - start) > NS_PER_SEC) {
+      printf("The process did not get to a stopping point in 1 second.\n");
+      break;
+    }
+    usleep(US_PER_MSEC);
+  }
+}
+
+bool ReadyLevelBacktrace(const backtrace_t* backtrace) {
+  // See if test_level_four is in the backtrace.
+  bool found = false;
+  for (size_t i = 0; i < backtrace->num_frames; i++) {
+    if (backtrace->frames[i].func_name != NULL &&
+        strcmp(backtrace->frames[i].func_name, "test_level_four") == 0) {
+      found = true;
+      break;
+    }
+  }
+
+  return found;
+}
+
+void VerifyLevelDump(const backtrace_t* backtrace) {
+  ASSERT_GT(backtrace->num_frames, static_cast<size_t>(0));
+  ASSERT_LT(backtrace->num_frames, static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+
+  // Look through the frames starting at the highest to find the
+  // frame we want.
+  size_t frame_num = 0;
+  for (size_t i = backtrace->num_frames-1; i > 2; i--) {
+    if (backtrace->frames[i].func_name != NULL &&
+        strcmp(backtrace->frames[i].func_name, "test_level_one") == 0) {
+      frame_num = i;
+      break;
+    }
+  }
+  ASSERT_GT(frame_num, static_cast<size_t>(0));
+
+  ASSERT_TRUE(NULL != backtrace->frames[frame_num].func_name);
+  ASSERT_STREQ(backtrace->frames[frame_num].func_name, "test_level_one");
+  ASSERT_TRUE(NULL != backtrace->frames[frame_num-1].func_name);
+  ASSERT_STREQ(backtrace->frames[frame_num-1].func_name, "test_level_two");
+  ASSERT_TRUE(NULL != backtrace->frames[frame_num-2].func_name);
+  ASSERT_STREQ(backtrace->frames[frame_num-2].func_name, "test_level_three");
+  ASSERT_TRUE(NULL != backtrace->frames[frame_num-3].func_name);
+  ASSERT_STREQ(backtrace->frames[frame_num-3].func_name, "test_level_four");
+}
+
+void VerifyLevelBacktrace(void*) {
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, -1, -1, 0));
+
+  VerifyLevelDump(context.backtrace);
+
+  backtrace_destroy_context(&context);
+}
+
+bool ReadyMaxBacktrace(const backtrace_t* backtrace) {
+  return (backtrace->num_frames == MAX_BACKTRACE_FRAMES);
+}
+
+void VerifyMaxDump(const backtrace_t* backtrace) {
+  ASSERT_EQ(backtrace->num_frames, static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+  // Verify that the last frame is our recursive call.
+  ASSERT_TRUE(NULL != backtrace->frames[MAX_BACKTRACE_FRAMES-1].func_name);
+  ASSERT_STREQ(backtrace->frames[MAX_BACKTRACE_FRAMES-1].func_name,
+               "test_recursive_call");
+}
+
+void VerifyMaxBacktrace(void*) {
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, -1, -1, 0));
+
+  VerifyMaxDump(context.backtrace);
+
+  backtrace_destroy_context(&context);
+}
+
+void ThreadSetState(void* data) {
+  thread_t* thread = reinterpret_cast<thread_t*>(data);
+  android_atomic_acquire_store(1, &thread->state);
+  volatile int i = 0;
+  while (thread->state) {
+    i++;
+  }
+}
+
+void VerifyThreadTest(pid_t tid, void (*VerifyFunc)(const backtrace_t*)) {
+  backtrace_context_t context;
+
+  backtrace_create_context(&context, getpid(), tid, 0);
+
+  VerifyFunc(context.backtrace);
+
+  backtrace_destroy_context(&context);
+}
+
+bool WaitForNonZero(int32_t* value, uint64_t seconds) {
+  uint64_t start = NanoTime();
+  do {
+    if (android_atomic_acquire_load(value)) {
+      return true;
+    }
+  } while ((NanoTime() - start) < seconds * NS_PER_SEC);
+  return false;
+}
+
+TEST(libbacktrace, local_trace) {
+  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, NULL), 0);
+}
+
+void VerifyIgnoreFrames(
+    const backtrace_t* bt_all, const backtrace_t* bt_ign1,
+    const backtrace_t* bt_ign2, const char* cur_proc) {
+  EXPECT_EQ(bt_all->num_frames, bt_ign1->num_frames + 1);
+  EXPECT_EQ(bt_all->num_frames, bt_ign2->num_frames + 2);
+
+  // Check all of the frames are the same > the current frame.
+  bool check = (cur_proc == NULL);
+  for (size_t i = 0; i < bt_ign2->num_frames; i++) {
+    if (check) {
+      EXPECT_EQ(bt_ign2->frames[i].pc, bt_ign1->frames[i+1].pc);
+      EXPECT_EQ(bt_ign2->frames[i].sp, bt_ign1->frames[i+1].sp);
+      EXPECT_EQ(bt_ign2->frames[i].stack_size, bt_ign1->frames[i+1].stack_size);
+
+      EXPECT_EQ(bt_ign2->frames[i].pc, bt_all->frames[i+2].pc);
+      EXPECT_EQ(bt_ign2->frames[i].sp, bt_all->frames[i+2].sp);
+      EXPECT_EQ(bt_ign2->frames[i].stack_size, bt_all->frames[i+2].stack_size);
+    }
+    if (!check && bt_ign2->frames[i].func_name &&
+        strcmp(bt_ign2->frames[i].func_name, cur_proc) == 0) {
+      check = true;
+    }
+  }
+}
+
+void VerifyLevelIgnoreFrames(void*) {
+  backtrace_context_t all;
+  ASSERT_TRUE(backtrace_create_context(&all, -1, -1, 0));
+  ASSERT_TRUE(all.backtrace != NULL);
+
+  backtrace_context_t ign1;
+  ASSERT_TRUE(backtrace_create_context(&ign1, -1, -1, 1));
+  ASSERT_TRUE(ign1.backtrace != NULL);
+
+  backtrace_context_t ign2;
+  ASSERT_TRUE(backtrace_create_context(&ign2, -1, -1, 2));
+  ASSERT_TRUE(ign2.backtrace != NULL);
+
+  VerifyIgnoreFrames(all.backtrace, ign1.backtrace, ign2.backtrace,
+                     "VerifyLevelIgnoreFrames");
+
+  backtrace_destroy_context(&all);
+  backtrace_destroy_context(&ign1);
+  backtrace_destroy_context(&ign2);
+}
+
+TEST(libbacktrace, local_trace_ignore_frames) {
+  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, NULL), 0);
+}
+
+TEST(libbacktrace, local_max_trace) {
+  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, NULL), 0);
+}
+
+void VerifyProcTest(pid_t pid, pid_t tid,
+                    bool (*ReadyFunc)(const backtrace_t*),
+                    void (*VerifyFunc)(const backtrace_t*)) {
+  pid_t ptrace_tid;
+  if (tid < 0) {
+    ptrace_tid = pid;
+  } else {
+    ptrace_tid = tid;
+  }
+  uint64_t start = NanoTime();
+  bool verified = false;
+  do {
+    usleep(US_PER_MSEC);
+    if (ptrace(PTRACE_ATTACH, ptrace_tid, 0, 0) == 0) {
+      // Wait for the process to get to a stopping point.
+      WaitForStop(ptrace_tid);
+
+      backtrace_context_t context;
+      ASSERT_TRUE(backtrace_create_context(&context, pid, tid, 0));
+      if (ReadyFunc(context.backtrace)) {
+        VerifyFunc(context.backtrace);
+        verified = true;
+      }
+      backtrace_destroy_context(&context);
+      ASSERT_TRUE(ptrace(PTRACE_DETACH, ptrace_tid, 0, 0) == 0);
+    }
+    // If 5 seconds have passed, then we are done.
+  } while (!verified && (NanoTime() - start) <= 5 * NS_PER_SEC);
+  ASSERT_TRUE(verified);
+}
+
+TEST(libbacktrace, ptrace_trace) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    exit(1);
+  }
+  VerifyProcTest(pid, -1, ReadyLevelBacktrace, VerifyLevelDump);
+
+  kill(pid, SIGKILL);
+  int status;
+  ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+TEST(libbacktrace, ptrace_max_trace) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0);
+    exit(1);
+  }
+  VerifyProcTest(pid, -1, ReadyMaxBacktrace, VerifyMaxDump);
+
+  kill(pid, SIGKILL);
+  int status;
+  ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+void VerifyProcessIgnoreFrames(const backtrace_t* bt_all) {
+  pid_t pid = bt_all->pid;
+
+  backtrace_context_t ign1;
+  ASSERT_TRUE(backtrace_create_context(&ign1, pid, -1, 1));
+  ASSERT_TRUE(ign1.backtrace != NULL);
+
+  backtrace_context_t ign2;
+  ASSERT_TRUE(backtrace_create_context(&ign2, pid, -1, 2));
+  ASSERT_TRUE(ign2.backtrace != NULL);
+
+  VerifyIgnoreFrames(bt_all, ign1.backtrace, ign2.backtrace, NULL);
+
+  backtrace_destroy_context(&ign1);
+  backtrace_destroy_context(&ign2);
+}
+
+TEST(libbacktrace, ptrace_ignore_frames) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    exit(1);
+  }
+  VerifyProcTest(pid, -1, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
+
+  kill(pid, SIGKILL);
+  int status;
+  ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+// Create a process with multiple threads and dump all of the threads.
+void* PtraceThreadLevelRun(void*) {
+  EXPECT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+  return NULL;
+}
+
+void GetThreads(pid_t pid, std::vector<pid_t>* threads) {
+  // Get the list of tasks.
+  char task_path[128];
+  snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
+
+  DIR* tasks_dir = opendir(task_path);
+  ASSERT_TRUE(tasks_dir != NULL);
+  struct dirent* entry;
+  while ((entry = readdir(tasks_dir)) != NULL) {
+    char* end;
+    pid_t tid = strtoul(entry->d_name, &end, 10);
+    if (*end == '\0') {
+      threads->push_back(tid);
+    }
+  }
+  closedir(tasks_dir);
+}
+
+TEST(libbacktrace, ptrace_threads) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) {
+      pthread_attr_t attr;
+      pthread_attr_init(&attr);
+      pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+      pthread_t thread;
+      ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, NULL) == 0);
+    }
+    ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+    exit(1);
+  }
+
+  // Check to see that all of the threads are running before unwinding.
+  std::vector<pid_t> threads;
+  uint64_t start = NanoTime();
+  do {
+    usleep(US_PER_MSEC);
+    threads.clear();
+    GetThreads(pid, &threads);
+  } while ((threads.size() != NUM_PTRACE_THREADS + 1) &&
+      ((NanoTime() - start) <= 5 * NS_PER_SEC));
+  ASSERT_EQ(threads.size(), static_cast<size_t>(NUM_PTRACE_THREADS + 1));
+
+  ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+  WaitForStop(pid);
+  for (std::vector<int>::const_iterator it = threads.begin(); it != threads.end(); ++it) {
+    // Skip the current forked process, we only care about the threads.
+    if (pid == *it) {
+      continue;
+    }
+    VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump);
+  }
+  ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+  kill(pid, SIGKILL);
+  int status;
+  ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+void VerifyLevelThread(void*) {
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, getpid(), gettid(), 0));
+
+  VerifyLevelDump(context.backtrace);
+
+  backtrace_destroy_context(&context);
+}
+
+TEST(libbacktrace, thread_current_level) {
+  ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, NULL), 0);
+}
+
+void VerifyMaxThread(void*) {
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, getpid(), gettid(), 0));
+
+  VerifyMaxDump(context.backtrace);
+
+  backtrace_destroy_context(&context);
+}
+
+TEST(libbacktrace, thread_current_max) {
+  ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, NULL), 0);
+}
+
+void* ThreadLevelRun(void* data) {
+  thread_t* thread = reinterpret_cast<thread_t*>(data);
+
+  thread->tid = gettid();
+  EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0);
+  return NULL;
+}
+
+TEST(libbacktrace, thread_level_trace) {
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+  thread_t thread_data = { 0, 0, 0 };
+  pthread_t thread;
+  ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0);
+
+  // Wait up to 2 seconds for the tid to be set.
+  ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
+
+  // Save the current signal action and make sure it is restored afterwards.
+  struct sigaction cur_action;
+  ASSERT_TRUE(sigaction(SIGURG, NULL, &cur_action) == 0);
+
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, getpid(), thread_data.tid,0));
+
+  VerifyLevelDump(context.backtrace);
+
+  backtrace_destroy_context(&context);
+
+  // Tell the thread to exit its infinite loop.
+  android_atomic_acquire_store(0, &thread_data.state);
+
+  // Verify that the old action was restored.
+  struct sigaction new_action;
+  ASSERT_TRUE(sigaction(SIGURG, NULL, &new_action) == 0);
+  EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction);
+  EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
+}
+
+TEST(libbacktrace, thread_ignore_frames) {
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+  thread_t thread_data = { 0, 0, 0 };
+  pthread_t thread;
+  ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0);
+
+  // Wait up to 2 seconds for the tid to be set.
+  ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
+
+  backtrace_context_t all;
+  ASSERT_TRUE(backtrace_create_context(&all, getpid(), thread_data.tid, 0));
+
+  backtrace_context_t ign1;
+  ASSERT_TRUE(backtrace_create_context(&ign1, getpid(), thread_data.tid, 1));
+
+  backtrace_context_t ign2;
+  ASSERT_TRUE(backtrace_create_context(&ign2, getpid(), thread_data.tid, 2));
+
+  VerifyIgnoreFrames(all.backtrace, ign1.backtrace, ign2.backtrace, NULL);
+
+  backtrace_destroy_context(&all);
+  backtrace_destroy_context(&ign1);
+  backtrace_destroy_context(&ign2);
+
+  // Tell the thread to exit its infinite loop.
+  android_atomic_acquire_store(0, &thread_data.state);
+}
+
+void* ThreadMaxRun(void* data) {
+  thread_t* thread = reinterpret_cast<thread_t*>(data);
+
+  thread->tid = gettid();
+  EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0);
+  return NULL;
+}
+
+TEST(libbacktrace, thread_max_trace) {
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+  thread_t thread_data = { 0, 0, 0 };
+  pthread_t thread;
+  ASSERT_TRUE(pthread_create(&thread, &attr, ThreadMaxRun, &thread_data) == 0);
+
+  // Wait for the tid to be set.
+  ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
+
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, getpid(), thread_data.tid, 0));
+
+  VerifyMaxDump(context.backtrace);
+
+  backtrace_destroy_context(&context);
+
+  // Tell the thread to exit its infinite loop.
+  android_atomic_acquire_store(0, &thread_data.state);
+}
+
+void* ThreadDump(void* data) {
+  dump_thread_t* dump = reinterpret_cast<dump_thread_t*>(data);
+  while (true) {
+    if (android_atomic_acquire_load(dump->now)) {
+      break;
+    }
+  }
+
+  dump->context.data = NULL;
+  dump->context.backtrace = NULL;
+
+  // The status of the actual unwind will be checked elsewhere.
+  backtrace_create_context(&dump->context, getpid(), dump->thread.tid, 0);
+
+  android_atomic_acquire_store(1, &dump->done);
+
+  return NULL;
+}
+
+TEST(libbacktrace, thread_multiple_dump) {
+  // Dump NUM_THREADS simultaneously.
+  std::vector<thread_t> runners(NUM_THREADS);
+  std::vector<dump_thread_t> dumpers(NUM_THREADS);
+
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+  for (size_t i = 0; i < NUM_THREADS; i++) {
+    // Launch the runners, they will spin in hard loops doing nothing.
+    runners[i].tid = 0;
+    runners[i].state = 0;
+    ASSERT_TRUE(pthread_create(&runners[i].threadId, &attr, ThreadMaxRun, &runners[i]) == 0);
+  }
+
+  // Wait for tids to be set.
+  for (std::vector<thread_t>::iterator it = runners.begin(); it != runners.end(); ++it) {
+    ASSERT_TRUE(WaitForNonZero(&it->state, 10));
+  }
+
+  // Start all of the dumpers at once, they will spin until they are signalled
+  // to begin their dump run.
+  int32_t dump_now = 0;
+  for (size_t i = 0; i < NUM_THREADS; i++) {
+    dumpers[i].thread.tid = runners[i].tid;
+    dumpers[i].thread.state = 0;
+    dumpers[i].done = 0;
+    dumpers[i].now = &dump_now;
+
+    ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0);
+  }
+
+  // Start all of the dumpers going at once.
+  android_atomic_acquire_store(1, &dump_now);
+
+  for (size_t i = 0; i < NUM_THREADS; i++) {
+    ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 10));
+
+    // Tell the runner thread to exit its infinite loop.
+    android_atomic_acquire_store(0, &runners[i].state);
+
+    ASSERT_TRUE(dumpers[i].context.backtrace != NULL);
+    VerifyMaxDump(dumpers[i].context.backtrace);
+    backtrace_destroy_context(&dumpers[i].context);
+  }
+}
+
+TEST(libbacktrace, format_test) {
+  backtrace_context_t context;
+
+  ASSERT_TRUE(backtrace_create_context(&context, -1, -1, 0));
+  ASSERT_TRUE(context.backtrace != NULL);
+
+  backtrace_frame_data_t* frame = &context.backtrace->frames[1];
+  backtrace_frame_data_t save_frame = *frame;
+
+  memset(frame, 0, sizeof(backtrace_frame_data_t));
+  char buf[512];
+  backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+#if defined(__LP64__)
+  EXPECT_STREQ(buf, "#01 pc 0000000000000000  <unknown>");
+#else
+  EXPECT_STREQ(buf, "#01 pc 00000000  <unknown>");
+#endif
+
+  frame->pc = 0x12345678;
+  frame->map_name = "MapFake";
+  backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+#if defined(__LP64__)
+  EXPECT_STREQ(buf, "#01 pc 0000000012345678  MapFake");
+#else
+  EXPECT_STREQ(buf, "#01 pc 12345678  MapFake");
+#endif
+
+  frame->func_name = "ProcFake";
+  backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+#if defined(__LP64__)
+  EXPECT_STREQ(buf, "#01 pc 0000000012345678  MapFake (ProcFake)");
+#else
+  EXPECT_STREQ(buf, "#01 pc 12345678  MapFake (ProcFake)");
+#endif
+
+  frame->func_offset = 645;
+  backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+#if defined(__LP64__)
+  EXPECT_STREQ(buf, "#01 pc 0000000012345678  MapFake (ProcFake+645)");
+#else
+  EXPECT_STREQ(buf, "#01 pc 12345678  MapFake (ProcFake+645)");
+#endif
+
+  *frame = save_frame;
+
+  backtrace_destroy_context(&context);
+}
diff --git a/libbacktrace/backtrace_testlib.c b/libbacktrace/backtrace_testlib.c
new file mode 100644
index 0000000..d4d15db
--- /dev/null
+++ b/libbacktrace/backtrace_testlib.c
@@ -0,0 +1,55 @@
+/*
+ * 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>
+
+int test_level_four(int one, int two, int three, int four,
+                    void (*callback_func)(void*), void* data) {
+  if (callback_func != NULL) {
+    callback_func(data);
+  } else {
+    while (1) {
+    }
+  }
+  return one + two + three + four;
+}
+
+int test_level_three(int one, int two, int three, int four,
+                     void (*callback_func)(void*), void* data) {
+  return test_level_four(one+3, two+6, three+9, four+12, callback_func, data) + 3;
+}
+
+int test_level_two(int one, int two, int three, int four,
+                   void (*callback_func)(void*), void* data) {
+  return test_level_three(one+2, two+4, three+6, four+8, callback_func, data) + 2;
+}
+
+int test_level_one(int one, int two, int three, int four,
+                   void (*callback_func)(void*), void* data) {
+  return test_level_two(one+1, two+2, three+3, four+4, callback_func, data) + 1;
+}
+
+int test_recursive_call(int level, void (*callback_func)(void*), void* data) {
+  if (level > 0) {
+    return test_recursive_call(level - 1, callback_func, data) + level;
+  } else if (callback_func != NULL) {
+    callback_func(data);
+  } else {
+    while (1) {
+    }
+  }
+  return 0;
+}
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/thread_utils.c b/libbacktrace/thread_utils.c
new file mode 100644
index 0000000..6f4cd3c
--- /dev/null
+++ b/libbacktrace/thread_utils.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "thread_utils.h"
+
+#if defined(__APPLE__)
+
+#include <sys/syscall.h>
+
+// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
+pid_t gettid() {
+  return syscall(SYS_thread_selfid);
+}
+
+#elif !defined(__BIONIC__)
+
+// glibc doesn't implement or export either gettid or tgkill.
+#include <unistd.h>
+#include <sys/syscall.h>
+
+pid_t gettid() {
+  return syscall(__NR_gettid);
+}
+
+int tgkill(int tgid, int tid, int sig) {
+  return syscall(__NR_tgkill, tgid, tid, sig);
+}
+
+#endif
diff --git a/libbacktrace/thread_utils.h b/libbacktrace/thread_utils.h
new file mode 100644
index 0000000..ae4c929
--- /dev/null
+++ b/libbacktrace/thread_utils.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBBACKTRACE_THREAD_UTILS_H
+#define _LIBBACKTRACE_THREAD_UTILS_H
+
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+int tgkill(int tgid, int tid, int sig);
+
+pid_t gettid();
+
+__END_DECLS
+
+#endif /* _LIBBACKTRACE_THREAD_UTILS_H */
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..f8dda36 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -96,11 +96,6 @@
 # Shared and static library for target
 # ========================================================
 
-# This is needed in LOCAL_C_INCLUDES to access the C library's private
-# header named <bionic_time.h>
-#
-libcutils_c_includes := bionic/libc/private
-
 include $(CLEAR_VARS)
 LOCAL_MODULE := libcutils
 LOCAL_SRC_FILES := $(commonSources) \
@@ -115,18 +110,18 @@
         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)
+        LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+        LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
+    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/arch-x86/android_memset16.S b/libcutils/arch-x86/android_memset16.S
index b1f09cb..f8b79bd 100644
--- a/libcutils/arch-x86/android_memset16.S
+++ b/libcutils/arch-x86/android_memset16.S
@@ -17,16 +17,9 @@
  * Contributed by: Intel Corporation
  */
 
-#if defined(USE_SSE2)
-
 # include "cache_wrapper.S"
 # undef __i686
 # define USE_AS_ANDROID
 # define sse2_memset16_atom android_memset16
 # include "sse2-memset16-atom.S"
 
-#else
-
-# include "memset16.S"
-
-#endif
diff --git a/libcutils/arch-x86/android_memset32.S b/libcutils/arch-x86/android_memset32.S
index 1fb2ffe..6249fce 100644
--- a/libcutils/arch-x86/android_memset32.S
+++ b/libcutils/arch-x86/android_memset32.S
@@ -17,17 +17,9 @@
  * Contributed by: Intel Corporation
  */
 
-#if defined(USE_SSE2)
-
 # include "cache_wrapper.S"
 # undef __i686
 # define USE_AS_ANDROID
 # define sse2_memset32_atom android_memset32
 # include "sse2-memset32-atom.S"
 
-#else
-
-# include "memset32.S"
-
-#endif
-
diff --git a/libcutils/arch-x86/sse2-memset16-atom.S b/libcutils/arch-x86/sse2-memset16-atom.S
old mode 100644
new mode 100755
index cafec82..c2a762b
--- a/libcutils/arch-x86/sse2-memset16-atom.S
+++ b/libcutils/arch-x86/sse2-memset16-atom.S
@@ -86,7 +86,7 @@
 # define SETRTNVAL	movl DEST(%esp), %eax
 #endif
 
-#ifdef SHARED
+#if (defined SHARED || defined __PIC__)
 # define ENTRANCE	PUSH (%ebx);
 # define RETURN_END	POP (%ebx); ret
 # define RETURN		RETURN_END; CFI_PUSH (%ebx)
@@ -344,7 +344,7 @@
 	PUSH (%ebx)
 	mov	$SHARED_CACHE_SIZE, %ebx
 #else
-# ifdef SHARED
+# if (defined SHARED || defined __PIC__)
 	call	__i686.get_pc_thunk.bx
 	add	$_GLOBAL_OFFSET_TABLE_, %ebx
 	mov	__x86_shared_cache_size@GOTOFF(%ebx), %ebx
@@ -362,7 +362,7 @@
 # define RESTORE_EBX_STATE CFI_PUSH (%ebx)
 	cmp	$DATA_CACHE_SIZE, %ecx
 #else
-# ifdef SHARED
+# if (defined SHARED || defined __PIC__)
 #  define RESTORE_EBX_STATE
 	call	__i686.get_pc_thunk.bx
 	add	$_GLOBAL_OFFSET_TABLE_, %ebx
@@ -471,7 +471,7 @@
 	jae	L(128bytesormore_nt)
 	sfence
 L(shared_cache_loop_end):
-#if defined DATA_CACHE_SIZE || !defined SHARED
+#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__)
 	POP (%ebx)
 #endif
 	add	%ecx, %edx
diff --git a/libcutils/arch-x86/sse2-memset32-atom.S b/libcutils/arch-x86/sse2-memset32-atom.S
old mode 100644
new mode 100755
index 4a52484..05eb64f
--- a/libcutils/arch-x86/sse2-memset32-atom.S
+++ b/libcutils/arch-x86/sse2-memset32-atom.S
@@ -86,7 +86,7 @@
 # define SETRTNVAL
 #endif
 
-#ifdef SHARED
+#if (defined SHARED || defined __PIC__)
 # define ENTRANCE	PUSH (%ebx);
 # define RETURN_END	POP (%ebx); ret
 # define RETURN		RETURN_END; CFI_PUSH (%ebx)
@@ -259,7 +259,7 @@
 	PUSH (%ebx)
 	mov	$SHARED_CACHE_SIZE, %ebx
 #else
-# ifdef SHARED
+# if (defined SHARED || defined __PIC__)
 	call	__i686.get_pc_thunk.bx
 	add	$_GLOBAL_OFFSET_TABLE_, %ebx
 	mov	__x86_shared_cache_size@GOTOFF(%ebx), %ebx
@@ -276,7 +276,7 @@
 # define RESTORE_EBX_STATE CFI_PUSH (%ebx)
 	cmp	$DATA_CACHE_SIZE, %ecx
 #else
-# ifdef SHARED
+# if (defined SHARED || defined __PIC__)
 #  define RESTORE_EBX_STATE
 	call	__i686.get_pc_thunk.bx
 	add	$_GLOBAL_OFFSET_TABLE_, %ebx
@@ -386,7 +386,7 @@
 	jae	L(128bytesormore_nt)
 	sfence
 L(shared_cache_loop_end):
-#if defined DATA_CACHE_SIZE || !defined SHARED
+#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__)
 	POP (%ebx)
 #endif
 	add	%ecx, %edx
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/libcutils/dir_hash.c b/libcutils/dir_hash.c
index be14af6..098b5db 100644
--- a/libcutils/dir_hash.c
+++ b/libcutils/dir_hash.c
@@ -159,6 +159,7 @@
 
             free(name);
             free(node);
+            closedir(d);
             return -1;
         }
 
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
index 090d0e5..7906986 100644
--- a/libmincrypt/Android.mk
+++ b/libmincrypt/Android.mk
@@ -1,18 +1,18 @@
 # Copyright 2008 The Android Open Source Project
 #
 LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
 
+include $(CLEAR_VARS)
 LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := rsa.c sha.c sha256.c
+LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
+LOCAL_CFLAGS := -Wall -Werror
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-
 LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := rsa.c sha.c sha256.c
+LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
+LOCAL_CFLAGS := -Wall -Werror
 include $(BUILD_HOST_STATIC_LIBRARY)
 
-
 include $(LOCAL_PATH)/tools/Android.mk \
         $(LOCAL_PATH)/test/Android.mk
diff --git a/libmincrypt/dsa_sig.c b/libmincrypt/dsa_sig.c
new file mode 100644
index 0000000..8df6cf7
--- /dev/null
+++ b/libmincrypt/dsa_sig.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google Inc. nor the names of its contributors may
+ *       be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "mincrypt/p256.h"
+
+/**
+ * Trims off the leading zero bytes and copy it to a buffer aligning it to the end.
+ */
+static inline int trim_to_p256_bytes(unsigned char dst[P256_NBYTES], unsigned char *src,
+        int src_len) {
+    int dst_offset;
+    while (*src == '\0' && src_len > 0) {
+        src++;
+        src_len--;
+    }
+    if (src_len > P256_NBYTES || src_len < 1) {
+        return 0;
+    }
+    dst_offset = P256_NBYTES - src_len;
+    memset(dst, 0, dst_offset);
+    memcpy(dst + dst_offset, src, src_len);
+    return 1;
+}
+
+/**
+ * Unpacks the ASN.1 DSA signature sequence.
+ */
+int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int) {
+    /*
+     * Structure is:
+     *   0x30 0xNN  SEQUENCE + s_length
+     *     0x02 0xNN  INTEGER + r_length
+     *       0xAA 0xBB ..   r_length bytes of "r" (offset 4)
+     *     0x02 0xNN  INTEGER + s_length
+     *       0xMM 0xNN ..   s_length bytes of "s" (offset 6 + r_len)
+     */
+    int seq_len;
+    unsigned char r_bytes[P256_NBYTES];
+    unsigned char s_bytes[P256_NBYTES];
+    int r_len;
+    int s_len;
+
+    memset(r_bytes, 0, sizeof(r_bytes));
+    memset(s_bytes, 0, sizeof(s_bytes));
+
+    /*
+     * Must have at least:
+     * 2 bytes sequence header and length
+     * 2 bytes R integer header and length
+     * 1 byte of R
+     * 2 bytes S integer header and length
+     * 1 byte of S
+     *
+     * 8 bytes total
+     */
+    if (sig_len < 8 || sig[0] != 0x30 || sig[2] != 0x02) {
+        return 0;
+    }
+
+    seq_len = sig[1];
+    if ((seq_len <= 0) || (seq_len + 2 != sig_len)) {
+        return 0;
+    }
+
+    r_len = sig[3];
+    /*
+     * Must have at least:
+     * 2 bytes for R header and length
+     * 2 bytes S integer header and length
+     * 1 byte of S
+     */
+    if ((r_len < 1) || (r_len > seq_len - 5) || (sig[4 + r_len] != 0x02)) {
+        return 0;
+    }
+    s_len = sig[5 + r_len];
+
+    /**
+     * Must have:
+     * 2 bytes for R header and length
+     * r_len bytes for R
+     * 2 bytes S integer header and length
+     */
+    if ((s_len < 1) || (s_len != seq_len - 4 - r_len)) {
+        return 0;
+    }
+
+    /*
+     * ASN.1 encoded integers are zero-padded for positive integers. Make sure we have
+     * a correctly-sized buffer and that the resulting integer isn't too large.
+     */
+    if (!trim_to_p256_bytes(r_bytes, &sig[4], r_len)
+            || !trim_to_p256_bytes(s_bytes, &sig[6 + r_len], s_len)) {
+        return 0;
+    }
+
+    p256_from_bin(r_bytes, r_int);
+    p256_from_bin(s_bytes, s_int);
+
+    return 1;
+}
diff --git a/libmincrypt/p256.c b/libmincrypt/p256.c
new file mode 100644
index 0000000..1608d37
--- /dev/null
+++ b/libmincrypt/p256.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google Inc. nor the names of its contributors may
+ *       be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This is an implementation of the P256 elliptic curve group. It's written to
+// be portable 32-bit, although it's still constant-time.
+//
+// WARNING: Implementing these functions in a constant-time manner is far from
+//          obvious. Be careful when touching this code.
+//
+// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "mincrypt/p256.h"
+
+const p256_int SECP256r1_n =  // curve order
+  {{0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1}};
+
+const p256_int SECP256r1_p =  // curve field size
+  {{-1, -1, -1, 0, 0, 0, 1, -1 }};
+
+const p256_int SECP256r1_b =  // curve b
+  {{0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
+    0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8}};
+
+static const p256_int p256_one = P256_ONE;
+
+void p256_init(p256_int* a) {
+  memset(a, 0, sizeof(*a));
+}
+
+void p256_clear(p256_int* a) { p256_init(a); }
+
+int p256_get_bit(const p256_int* scalar, int bit) {
+  return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT)
+              >> (bit & (P256_BITSPERDIGIT - 1))) & 1;
+}
+
+int p256_is_zero(const p256_int* a) {
+  int i, result = 0;
+  for (i = 0; i < P256_NDIGITS; ++i) result |= P256_DIGIT(a, i);
+  return !result;
+}
+
+// top, c[] += a[] * b
+// Returns new top
+static p256_digit mulAdd(const p256_int* a,
+                         p256_digit b,
+                         p256_digit top,
+                         p256_digit* c) {
+  int i;
+  p256_ddigit carry = 0;
+
+  for (i = 0; i < P256_NDIGITS; ++i) {
+    carry += *c;
+    carry += (p256_ddigit)P256_DIGIT(a, i) * b;
+    *c++ = (p256_digit)carry;
+    carry >>= P256_BITSPERDIGIT;
+  }
+  return top + (p256_digit)carry;
+}
+
+// top, c[] -= top_a, a[]
+static p256_digit subTop(p256_digit top_a,
+                         const p256_digit* a,
+                         p256_digit top_c,
+                         p256_digit* c) {
+  int i;
+  p256_sddigit borrow = 0;
+
+  for (i = 0; i < P256_NDIGITS; ++i) {
+    borrow += *c;
+    borrow -= *a++;
+    *c++ = (p256_digit)borrow;
+    borrow >>= P256_BITSPERDIGIT;
+  }
+  borrow += top_c;
+  borrow -= top_a;
+  top_c = (p256_digit)borrow;
+  assert((borrow >> P256_BITSPERDIGIT) == 0);
+  return top_c;
+}
+
+// top, c[] -= MOD[] & mask (0 or -1)
+// returns new top.
+static p256_digit subM(const p256_int* MOD,
+                       p256_digit top,
+                       p256_digit* c,
+                       p256_digit mask) {
+  int i;
+  p256_sddigit borrow = 0;
+  for (i = 0; i < P256_NDIGITS; ++i) {
+    borrow += *c;
+    borrow -= P256_DIGIT(MOD, i) & mask;
+    *c++ = (p256_digit)borrow;
+    borrow >>= P256_BITSPERDIGIT;
+  }
+  return top + (p256_digit)borrow;
+}
+
+// top, c[] += MOD[] & mask (0 or -1)
+// returns new top.
+static p256_digit addM(const p256_int* MOD,
+                       p256_digit top,
+                       p256_digit* c,
+                       p256_digit mask) {
+  int i;
+  p256_ddigit carry = 0;
+  for (i = 0; i < P256_NDIGITS; ++i) {
+    carry += *c;
+    carry += P256_DIGIT(MOD, i) & mask;
+    *c++ = (p256_digit)carry;
+    carry >>= P256_BITSPERDIGIT;
+  }
+  return top + (p256_digit)carry;
+}
+
+// c = a * b mod MOD. c can be a and/or b.
+void p256_modmul(const p256_int* MOD,
+                 const p256_int* a,
+                 const p256_digit top_b,
+                 const p256_int* b,
+                 p256_int* c) {
+  p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 };
+  p256_digit top = 0;
+  int i;
+
+  // Multiply/add into tmp.
+  for (i = 0; i < P256_NDIGITS; ++i) {
+    if (i) tmp[i + P256_NDIGITS - 1] = top;
+    top = mulAdd(a, P256_DIGIT(b, i), 0, tmp + i);
+  }
+
+  // Multiply/add top digit
+  tmp[i + P256_NDIGITS - 1] = top;
+  top = mulAdd(a, top_b, 0, tmp + i);
+
+  // Reduce tmp, digit by digit.
+  for (; i >= 0; --i) {
+    p256_digit reducer[P256_NDIGITS] = { 0 };
+    p256_digit top_reducer;
+
+    // top can be any value at this point.
+    // Guestimate reducer as top * MOD, since msw of MOD is -1.
+    top_reducer = mulAdd(MOD, top, 0, reducer);
+
+    // Subtract reducer from top | tmp.
+    top = subTop(top_reducer, reducer, top, tmp + i);
+
+    // top is now either 0 or 1. Make it 0, fixed-timing.
+    assert(top <= 1);
+
+    top = subM(MOD, top, tmp + i, ~(top - 1));
+
+    assert(top == 0);
+
+    // We have now reduced the top digit off tmp. Fetch new top digit.
+    top = tmp[i + P256_NDIGITS - 1];
+  }
+
+  // tmp might still be larger than MOD, yet same bit length.
+  // Make sure it is less, fixed-timing.
+  addM(MOD, 0, tmp, subM(MOD, 0, tmp, -1));
+
+  memcpy(c, tmp, P256_NBYTES);
+}
+int p256_is_odd(const p256_int* a) { return P256_DIGIT(a, 0) & 1; }
+int p256_is_even(const p256_int* a) { return !(P256_DIGIT(a, 0) & 1); }
+
+p256_digit p256_shl(const p256_int* a, int n, p256_int* b) {
+  int i;
+  p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1);
+
+  n %= P256_BITSPERDIGIT;
+  for (i = P256_NDIGITS - 1; i > 0; --i) {
+    p256_digit accu = (P256_DIGIT(a, i) << n);
+    accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n));
+    P256_DIGIT(b, i) = accu;
+  }
+  P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n);
+
+  top = (p256_digit)((((p256_ddigit)top) << n) >> P256_BITSPERDIGIT);
+
+  return top;
+}
+
+void p256_shr(const p256_int* a, int n, p256_int* b) {
+  int i;
+
+  n %= P256_BITSPERDIGIT;
+  for (i = 0; i < P256_NDIGITS - 1; ++i) {
+    p256_digit accu = (P256_DIGIT(a, i) >> n);
+    accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n));
+    P256_DIGIT(b, i) = accu;
+  }
+  P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n);
+}
+
+static void p256_shr1(const p256_int* a, int highbit, p256_int* b) {
+  int i;
+
+  for (i = 0; i < P256_NDIGITS - 1; ++i) {
+    p256_digit accu = (P256_DIGIT(a, i) >> 1);
+    accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1));
+    P256_DIGIT(b, i) = accu;
+  }
+  P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) |
+      (highbit << (P256_BITSPERDIGIT - 1));
+}
+
+// Return -1, 0, 1 for a < b, a == b or a > b respectively.
+int p256_cmp(const p256_int* a, const p256_int* b) {
+  int i;
+  p256_sddigit borrow = 0;
+  p256_digit notzero = 0;
+
+  for (i = 0; i < P256_NDIGITS; ++i) {
+    borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
+    // Track whether any result digit is ever not zero.
+    // Relies on !!(non-zero) evaluating to 1, e.g., !!(-1) evaluating to 1.
+    notzero |= !!((p256_digit)borrow);
+    borrow >>= P256_BITSPERDIGIT;
+  }
+  return (int)borrow | notzero;
+}
+
+// c = a - b. Returns borrow: 0 or -1.
+int p256_sub(const p256_int* a, const p256_int* b, p256_int* c) {
+  int i;
+  p256_sddigit borrow = 0;
+
+  for (i = 0; i < P256_NDIGITS; ++i) {
+    borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
+    if (c) P256_DIGIT(c, i) = (p256_digit)borrow;
+    borrow >>= P256_BITSPERDIGIT;
+  }
+  return (int)borrow;
+}
+
+// c = a + b. Returns carry: 0 or 1.
+int p256_add(const p256_int* a, const p256_int* b, p256_int* c) {
+  int i;
+  p256_ddigit carry = 0;
+
+  for (i = 0; i < P256_NDIGITS; ++i) {
+    carry += (p256_ddigit)P256_DIGIT(a, i) + P256_DIGIT(b, i);
+    if (c) P256_DIGIT(c, i) = (p256_digit)carry;
+    carry >>= P256_BITSPERDIGIT;
+  }
+  return (int)carry;
+}
+
+// b = a + d. Returns carry, 0 or 1.
+int p256_add_d(const p256_int* a, p256_digit d, p256_int* b) {
+  int i;
+  p256_ddigit carry = d;
+
+  for (i = 0; i < P256_NDIGITS; ++i) {
+    carry += (p256_ddigit)P256_DIGIT(a, i);
+    if (b) P256_DIGIT(b, i) = (p256_digit)carry;
+    carry >>= P256_BITSPERDIGIT;
+  }
+  return (int)carry;
+}
+
+// b = 1/a mod MOD, binary euclid.
+void p256_modinv_vartime(const p256_int* MOD,
+                         const p256_int* a,
+                         p256_int* b) {
+  p256_int R = P256_ZERO;
+  p256_int S = P256_ONE;
+  p256_int U = *MOD;
+  p256_int V = *a;
+
+  for (;;) {
+    if (p256_is_even(&U)) {
+      p256_shr1(&U, 0, &U);
+      if (p256_is_even(&R)) {
+        p256_shr1(&R, 0, &R);
+      } else {
+        // R = (R+MOD)/2
+        p256_shr1(&R, p256_add(&R, MOD, &R), &R);
+      }
+    } else if (p256_is_even(&V)) {
+      p256_shr1(&V, 0, &V);
+      if (p256_is_even(&S)) {
+        p256_shr1(&S, 0, &S);
+      } else {
+        // S = (S+MOD)/2
+        p256_shr1(&S, p256_add(&S, MOD, &S) , &S);
+      }
+    } else {  // U,V both odd.
+      if (!p256_sub(&V, &U, NULL)) {
+        p256_sub(&V, &U, &V);
+        if (p256_sub(&S, &R, &S)) p256_add(&S, MOD, &S);
+        if (p256_is_zero(&V)) break;  // done.
+      } else {
+        p256_sub(&U, &V, &U);
+        if (p256_sub(&R, &S, &R)) p256_add(&R, MOD, &R);
+      }
+    }
+  }
+
+  p256_mod(MOD, &R, b);
+}
+
+void p256_mod(const p256_int* MOD,
+              const p256_int* in,
+              p256_int* out) {
+  if (out != in) *out = *in;
+  addM(MOD, 0, P256_DIGITS(out), subM(MOD, 0, P256_DIGITS(out), -1));
+}
+
+// Verify y^2 == x^3 - 3x + b mod p
+// and 0 < x < p and 0 < y < p
+int p256_is_valid_point(const p256_int* x, const p256_int* y) {
+  p256_int y2, x3;
+
+  if (p256_cmp(&SECP256r1_p, x) <= 0 ||
+      p256_cmp(&SECP256r1_p, y) <= 0 ||
+      p256_is_zero(x) ||
+      p256_is_zero(y)) return 0;
+
+  p256_modmul(&SECP256r1_p, y, 0, y, &y2);  // y^2
+
+  p256_modmul(&SECP256r1_p, x, 0, x, &x3);  // x^2
+  p256_modmul(&SECP256r1_p, x, 0, &x3, &x3);  // x^3
+  if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3);  // x^3 - x
+  if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3);  // x^3 - 2x
+  if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3);  // x^3 - 3x
+  if (p256_add(&x3, &SECP256r1_b, &x3))  // x^3 - 3x + b
+    p256_sub(&x3, &SECP256r1_p, &x3);
+
+  return p256_cmp(&y2, &x3) == 0;
+}
+
+void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst) {
+  int i;
+  const uint8_t* p = &src[0];
+
+  for (i = P256_NDIGITS - 1; i >= 0; --i) {
+    P256_DIGIT(dst, i) =
+        (p[0] << 24) |
+        (p[1] << 16) |
+        (p[2] << 8) |
+        p[3];
+    p += 4;
+  }
+}
diff --git a/libmincrypt/p256_ec.c b/libmincrypt/p256_ec.c
new file mode 100644
index 0000000..90262cc
--- /dev/null
+++ b/libmincrypt/p256_ec.c
@@ -0,0 +1,1279 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google Inc. nor the names of its contributors may
+ *       be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This is an implementation of the P256 elliptic curve group. It's written to
+// be portable 32-bit, although it's still constant-time.
+//
+// WARNING: Implementing these functions in a constant-time manner is far from
+//          obvious. Be careful when touching this code.
+//
+// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mincrypt/p256.h"
+
+typedef uint8_t u8;
+typedef uint32_t u32;
+typedef int32_t s32;
+typedef uint64_t u64;
+
+/* Our field elements are represented as nine 32-bit limbs.
+ *
+ * The value of an felem (field element) is:
+ *   x[0] + (x[1] * 2**29) + (x[2] * 2**57) + ... + (x[8] * 2**228)
+ *
+ * That is, each limb is alternately 29 or 28-bits wide in little-endian
+ * order.
+ *
+ * This means that an felem hits 2**257, rather than 2**256 as we would like. A
+ * 28, 29, ... pattern would cause us to hit 2**256, but that causes problems
+ * when multiplying as terms end up one bit short of a limb which would require
+ * much bit-shifting to correct.
+ *
+ * Finally, the values stored in an felem are in Montgomery form. So the value
+ * |y| is stored as (y*R) mod p, where p is the P-256 prime and R is 2**257.
+ */
+typedef u32 limb;
+#define NLIMBS 9
+typedef limb felem[NLIMBS];
+
+static const limb kBottom28Bits = 0xfffffff;
+static const limb kBottom29Bits = 0x1fffffff;
+
+/* kOne is the number 1 as an felem. It's 2**257 mod p split up into 29 and
+ * 28-bit words. */
+static const felem kOne = {
+    2, 0, 0, 0xffff800,
+    0x1fffffff, 0xfffffff, 0x1fbfffff, 0x1ffffff,
+    0
+};
+static const felem kZero = {0};
+static const felem kP = {
+    0x1fffffff, 0xfffffff, 0x1fffffff, 0x3ff,
+    0, 0, 0x200000, 0xf000000,
+    0xfffffff
+};
+static const felem k2P = {
+    0x1ffffffe, 0xfffffff, 0x1fffffff, 0x7ff,
+    0, 0, 0x400000, 0xe000000,
+    0x1fffffff
+};
+/* kPrecomputed contains precomputed values to aid the calculation of scalar
+ * multiples of the base point, G. It's actually two, equal length, tables
+ * concatenated.
+ *
+ * The first table contains (x,y) felem pairs for 16 multiples of the base
+ * point, G.
+ *
+ *   Index  |  Index (binary) | Value
+ *       0  |           0000  | 0G (all zeros, omitted)
+ *       1  |           0001  | G
+ *       2  |           0010  | 2**64G
+ *       3  |           0011  | 2**64G + G
+ *       4  |           0100  | 2**128G
+ *       5  |           0101  | 2**128G + G
+ *       6  |           0110  | 2**128G + 2**64G
+ *       7  |           0111  | 2**128G + 2**64G + G
+ *       8  |           1000  | 2**192G
+ *       9  |           1001  | 2**192G + G
+ *      10  |           1010  | 2**192G + 2**64G
+ *      11  |           1011  | 2**192G + 2**64G + G
+ *      12  |           1100  | 2**192G + 2**128G
+ *      13  |           1101  | 2**192G + 2**128G + G
+ *      14  |           1110  | 2**192G + 2**128G + 2**64G
+ *      15  |           1111  | 2**192G + 2**128G + 2**64G + G
+ *
+ * The second table follows the same style, but the terms are 2**32G,
+ * 2**96G, 2**160G, 2**224G.
+ *
+ * This is ~2KB of data. */
+static const limb kPrecomputed[NLIMBS * 2 * 15 * 2] = {
+    0x11522878, 0xe730d41, 0xdb60179, 0x4afe2ff, 0x12883add, 0xcaddd88, 0x119e7edc, 0xd4a6eab, 0x3120bee,
+    0x1d2aac15, 0xf25357c, 0x19e45cdd, 0x5c721d0, 0x1992c5a5, 0xa237487, 0x154ba21, 0x14b10bb, 0xae3fe3,
+    0xd41a576, 0x922fc51, 0x234994f, 0x60b60d3, 0x164586ae, 0xce95f18, 0x1fe49073, 0x3fa36cc, 0x5ebcd2c,
+    0xb402f2f, 0x15c70bf, 0x1561925c, 0x5a26704, 0xda91e90, 0xcdc1c7f, 0x1ea12446, 0xe1ade1e, 0xec91f22,
+    0x26f7778, 0x566847e, 0xa0bec9e, 0x234f453, 0x1a31f21a, 0xd85e75c, 0x56c7109, 0xa267a00, 0xb57c050,
+    0x98fb57, 0xaa837cc, 0x60c0792, 0xcfa5e19, 0x61bab9e, 0x589e39b, 0xa324c5, 0x7d6dee7, 0x2976e4b,
+    0x1fc4124a, 0xa8c244b, 0x1ce86762, 0xcd61c7e, 0x1831c8e0, 0x75774e1, 0x1d96a5a9, 0x843a649, 0xc3ab0fa,
+    0x6e2e7d5, 0x7673a2a, 0x178b65e8, 0x4003e9b, 0x1a1f11c2, 0x7816ea, 0xf643e11, 0x58c43df, 0xf423fc2,
+    0x19633ffa, 0x891f2b2, 0x123c231c, 0x46add8c, 0x54700dd, 0x59e2b17, 0x172db40f, 0x83e277d, 0xb0dd609,
+    0xfd1da12, 0x35c6e52, 0x19ede20c, 0xd19e0c0, 0x97d0f40, 0xb015b19, 0x449e3f5, 0xe10c9e, 0x33ab581,
+    0x56a67ab, 0x577734d, 0x1dddc062, 0xc57b10d, 0x149b39d, 0x26a9e7b, 0xc35df9f, 0x48764cd, 0x76dbcca,
+    0xca4b366, 0xe9303ab, 0x1a7480e7, 0x57e9e81, 0x1e13eb50, 0xf466cf3, 0x6f16b20, 0x4ba3173, 0xc168c33,
+    0x15cb5439, 0x6a38e11, 0x73658bd, 0xb29564f, 0x3f6dc5b, 0x53b97e, 0x1322c4c0, 0x65dd7ff, 0x3a1e4f6,
+    0x14e614aa, 0x9246317, 0x1bc83aca, 0xad97eed, 0xd38ce4a, 0xf82b006, 0x341f077, 0xa6add89, 0x4894acd,
+    0x9f162d5, 0xf8410ef, 0x1b266a56, 0xd7f223, 0x3e0cb92, 0xe39b672, 0x6a2901a, 0x69a8556, 0x7e7c0,
+    0x9b7d8d3, 0x309a80, 0x1ad05f7f, 0xc2fb5dd, 0xcbfd41d, 0x9ceb638, 0x1051825c, 0xda0cf5b, 0x812e881,
+    0x6f35669, 0x6a56f2c, 0x1df8d184, 0x345820, 0x1477d477, 0x1645db1, 0xbe80c51, 0xc22be3e, 0xe35e65a,
+    0x1aeb7aa0, 0xc375315, 0xf67bc99, 0x7fdd7b9, 0x191fc1be, 0x61235d, 0x2c184e9, 0x1c5a839, 0x47a1e26,
+    0xb7cb456, 0x93e225d, 0x14f3c6ed, 0xccc1ac9, 0x17fe37f3, 0x4988989, 0x1a90c502, 0x2f32042, 0xa17769b,
+    0xafd8c7c, 0x8191c6e, 0x1dcdb237, 0x16200c0, 0x107b32a1, 0x66c08db, 0x10d06a02, 0x3fc93, 0x5620023,
+    0x16722b27, 0x68b5c59, 0x270fcfc, 0xfad0ecc, 0xe5de1c2, 0xeab466b, 0x2fc513c, 0x407f75c, 0xbaab133,
+    0x9705fe9, 0xb88b8e7, 0x734c993, 0x1e1ff8f, 0x19156970, 0xabd0f00, 0x10469ea7, 0x3293ac0, 0xcdc98aa,
+    0x1d843fd, 0xe14bfe8, 0x15be825f, 0x8b5212, 0xeb3fb67, 0x81cbd29, 0xbc62f16, 0x2b6fcc7, 0xf5a4e29,
+    0x13560b66, 0xc0b6ac2, 0x51ae690, 0xd41e271, 0xf3e9bd4, 0x1d70aab, 0x1029f72, 0x73e1c35, 0xee70fbc,
+    0xad81baf, 0x9ecc49a, 0x86c741e, 0xfe6be30, 0x176752e7, 0x23d416, 0x1f83de85, 0x27de188, 0x66f70b8,
+    0x181cd51f, 0x96b6e4c, 0x188f2335, 0xa5df759, 0x17a77eb6, 0xfeb0e73, 0x154ae914, 0x2f3ec51, 0x3826b59,
+    0xb91f17d, 0x1c72949, 0x1362bf0a, 0xe23fddf, 0xa5614b0, 0xf7d8f, 0x79061, 0x823d9d2, 0x8213f39,
+    0x1128ae0b, 0xd095d05, 0xb85c0c2, 0x1ecb2ef, 0x24ddc84, 0xe35e901, 0x18411a4a, 0xf5ddc3d, 0x3786689,
+    0x52260e8, 0x5ae3564, 0x542b10d, 0x8d93a45, 0x19952aa4, 0x996cc41, 0x1051a729, 0x4be3499, 0x52b23aa,
+    0x109f307e, 0x6f5b6bb, 0x1f84e1e7, 0x77a0cfa, 0x10c4df3f, 0x25a02ea, 0xb048035, 0xe31de66, 0xc6ecaa3,
+    0x28ea335, 0x2886024, 0x1372f020, 0xf55d35, 0x15e4684c, 0xf2a9e17, 0x1a4a7529, 0xcb7beb1, 0xb2a78a1,
+    0x1ab21f1f, 0x6361ccf, 0x6c9179d, 0xb135627, 0x1267b974, 0x4408bad, 0x1cbff658, 0xe3d6511, 0xc7d76f,
+    0x1cc7a69, 0xe7ee31b, 0x54fab4f, 0x2b914f, 0x1ad27a30, 0xcd3579e, 0xc50124c, 0x50daa90, 0xb13f72,
+    0xb06aa75, 0x70f5cc6, 0x1649e5aa, 0x84a5312, 0x329043c, 0x41c4011, 0x13d32411, 0xb04a838, 0xd760d2d,
+    0x1713b532, 0xbaa0c03, 0x84022ab, 0x6bcf5c1, 0x2f45379, 0x18ae070, 0x18c9e11e, 0x20bca9a, 0x66f496b,
+    0x3eef294, 0x67500d2, 0xd7f613c, 0x2dbbeb, 0xb741038, 0xe04133f, 0x1582968d, 0xbe985f7, 0x1acbc1a,
+    0x1a6a939f, 0x33e50f6, 0xd665ed4, 0xb4b7bd6, 0x1e5a3799, 0x6b33847, 0x17fa56ff, 0x65ef930, 0x21dc4a,
+    0x2b37659, 0x450fe17, 0xb357b65, 0xdf5efac, 0x15397bef, 0x9d35a7f, 0x112ac15f, 0x624e62e, 0xa90ae2f,
+    0x107eecd2, 0x1f69bbe, 0x77d6bce, 0x5741394, 0x13c684fc, 0x950c910, 0x725522b, 0xdc78583, 0x40eeabb,
+    0x1fde328a, 0xbd61d96, 0xd28c387, 0x9e77d89, 0x12550c40, 0x759cb7d, 0x367ef34, 0xae2a960, 0x91b8bdc,
+    0x93462a9, 0xf469ef, 0xb2e9aef, 0xd2ca771, 0x54e1f42, 0x7aaa49, 0x6316abb, 0x2413c8e, 0x5425bf9,
+    0x1bed3e3a, 0xf272274, 0x1f5e7326, 0x6416517, 0xea27072, 0x9cedea7, 0x6e7633, 0x7c91952, 0xd806dce,
+    0x8e2a7e1, 0xe421e1a, 0x418c9e1, 0x1dbc890, 0x1b395c36, 0xa1dc175, 0x1dc4ef73, 0x8956f34, 0xe4b5cf2,
+    0x1b0d3a18, 0x3194a36, 0x6c2641f, 0xe44124c, 0xa2f4eaa, 0xa8c25ba, 0xf927ed7, 0x627b614, 0x7371cca,
+    0xba16694, 0x417bc03, 0x7c0a7e3, 0x9c35c19, 0x1168a205, 0x8b6b00d, 0x10e3edc9, 0x9c19bf2, 0x5882229,
+    0x1b2b4162, 0xa5cef1a, 0x1543622b, 0x9bd433e, 0x364e04d, 0x7480792, 0x5c9b5b3, 0xe85ff25, 0x408ef57,
+    0x1814cfa4, 0x121b41b, 0xd248a0f, 0x3b05222, 0x39bb16a, 0xc75966d, 0xa038113, 0xa4a1769, 0x11fbc6c,
+    0x917e50e, 0xeec3da8, 0x169d6eac, 0x10c1699, 0xa416153, 0xf724912, 0x15cd60b7, 0x4acbad9, 0x5efc5fa,
+    0xf150ed7, 0x122b51, 0x1104b40a, 0xcb7f442, 0xfbb28ff, 0x6ac53ca, 0x196142cc, 0x7bf0fa9, 0x957651,
+    0x4e0f215, 0xed439f8, 0x3f46bd5, 0x5ace82f, 0x110916b6, 0x6db078, 0xffd7d57, 0xf2ecaac, 0xca86dec,
+    0x15d6b2da, 0x965ecc9, 0x1c92b4c2, 0x1f3811, 0x1cb080f5, 0x2d8b804, 0x19d1c12d, 0xf20bd46, 0x1951fa7,
+    0xa3656c3, 0x523a425, 0xfcd0692, 0xd44ddc8, 0x131f0f5b, 0xaf80e4a, 0xcd9fc74, 0x99bb618, 0x2db944c,
+    0xa673090, 0x1c210e1, 0x178c8d23, 0x1474383, 0x10b8743d, 0x985a55b, 0x2e74779, 0x576138, 0x9587927,
+    0x133130fa, 0xbe05516, 0x9f4d619, 0xbb62570, 0x99ec591, 0xd9468fe, 0x1d07782d, 0xfc72e0b, 0x701b298,
+    0x1863863b, 0x85954b8, 0x121a0c36, 0x9e7fedf, 0xf64b429, 0x9b9d71e, 0x14e2f5d8, 0xf858d3a, 0x942eea8,
+    0xda5b765, 0x6edafff, 0xa9d18cc, 0xc65e4ba, 0x1c747e86, 0xe4ea915, 0x1981d7a1, 0x8395659, 0x52ed4e2,
+    0x87d43b7, 0x37ab11b, 0x19d292ce, 0xf8d4692, 0x18c3053f, 0x8863e13, 0x4c146c0, 0x6bdf55a, 0x4e4457d,
+    0x16152289, 0xac78ec2, 0x1a59c5a2, 0x2028b97, 0x71c2d01, 0x295851f, 0x404747b, 0x878558d, 0x7d29aa4,
+    0x13d8341f, 0x8daefd7, 0x139c972d, 0x6b7ea75, 0xd4a9dde, 0xff163d8, 0x81d55d7, 0xa5bef68, 0xb7b30d8,
+    0xbe73d6f, 0xaa88141, 0xd976c81, 0x7e7a9cc, 0x18beb771, 0xd773cbd, 0x13f51951, 0x9d0c177, 0x1c49a78,
+};
+
+
+/* Field element operations: */
+
+/* NON_ZERO_TO_ALL_ONES returns:
+ *   0xffffffff for 0 < x <= 2**31
+ *   0 for x == 0 or x > 2**31.
+ *
+ * x must be a u32 or an equivalent type such as limb. */
+#define NON_ZERO_TO_ALL_ONES(x) ((((u32)(x) - 1) >> 31) - 1)
+
+/* felem_reduce_carry adds a multiple of p in order to cancel |carry|,
+ * which is a term at 2**257.
+ *
+ * On entry: carry < 2**3, inout[0,2,...] < 2**29, inout[1,3,...] < 2**28.
+ * On exit: inout[0,2,..] < 2**30, inout[1,3,...] < 2**29. */
+static void felem_reduce_carry(felem inout, limb carry) {
+  const u32 carry_mask = NON_ZERO_TO_ALL_ONES(carry);
+
+  inout[0] += carry << 1;
+  inout[3] += 0x10000000 & carry_mask;
+  /* carry < 2**3 thus (carry << 11) < 2**14 and we added 2**28 in the
+   * previous line therefore this doesn't underflow. */
+  inout[3] -= carry << 11;
+  inout[4] += (0x20000000 - 1) & carry_mask;
+  inout[5] += (0x10000000 - 1) & carry_mask;
+  inout[6] += (0x20000000 - 1) & carry_mask;
+  inout[6] -= carry << 22;
+  /* This may underflow if carry is non-zero but, if so, we'll fix it in the
+   * next line. */
+  inout[7] -= 1 & carry_mask;
+  inout[7] += carry << 25;
+}
+
+/* felem_sum sets out = in+in2.
+ *
+ * On entry, in[i]+in2[i] must not overflow a 32-bit word.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */
+static void felem_sum(felem out, const felem in, const felem in2) {
+  limb carry = 0;
+  unsigned i;
+
+  for (i = 0;; i++) {
+    out[i] = in[i] + in2[i];
+    out[i] += carry;
+    carry = out[i] >> 29;
+    out[i] &= kBottom29Bits;
+
+    i++;
+    if (i == NLIMBS)
+      break;
+
+    out[i] = in[i] + in2[i];
+    out[i] += carry;
+    carry = out[i] >> 28;
+    out[i] &= kBottom28Bits;
+  }
+
+  felem_reduce_carry(out, carry);
+}
+
+#define two31m3 (((limb)1) << 31) - (((limb)1) << 3)
+#define two30m2 (((limb)1) << 30) - (((limb)1) << 2)
+#define two30p13m2 (((limb)1) << 30) + (((limb)1) << 13) - (((limb)1) << 2)
+#define two31m2 (((limb)1) << 31) - (((limb)1) << 2)
+#define two31p24m2 (((limb)1) << 31) + (((limb)1) << 24) - (((limb)1) << 2)
+#define two30m27m2 (((limb)1) << 30) - (((limb)1) << 27) - (((limb)1) << 2)
+
+/* zero31 is 0 mod p. */
+static const felem zero31 = { two31m3, two30m2, two31m2, two30p13m2, two31m2, two30m2, two31p24m2, two30m27m2, two31m2 };
+
+/* felem_diff sets out = in-in2.
+ *
+ * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
+ *           in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_diff(felem out, const felem in, const felem in2) {
+  limb carry = 0;
+  unsigned i;
+
+   for (i = 0;; i++) {
+    out[i] = in[i] - in2[i];
+    out[i] += zero31[i];
+    out[i] += carry;
+    carry = out[i] >> 29;
+    out[i] &= kBottom29Bits;
+
+    i++;
+    if (i == NLIMBS)
+      break;
+
+    out[i] = in[i] - in2[i];
+    out[i] += zero31[i];
+    out[i] += carry;
+    carry = out[i] >> 28;
+    out[i] &= kBottom28Bits;
+  }
+
+  felem_reduce_carry(out, carry);
+}
+
+/* felem_reduce_degree sets out = tmp/R mod p where tmp contains 64-bit words
+ * with the same 29,28,... bit positions as an felem.
+ *
+ * The values in felems are in Montgomery form: x*R mod p where R = 2**257.
+ * Since we just multiplied two Montgomery values together, the result is
+ * x*y*R*R mod p. We wish to divide by R in order for the result also to be
+ * in Montgomery form.
+ *
+ * On entry: tmp[i] < 2**64
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */
+static void felem_reduce_degree(felem out, u64 tmp[17]) {
+   /* The following table may be helpful when reading this code:
+    *
+    * Limb number:   0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10...
+    * Width (bits):  29| 28| 29| 28| 29| 28| 29| 28| 29| 28| 29
+    * Start bit:     0 | 29| 57| 86|114|143|171|200|228|257|285
+    *   (odd phase): 0 | 28| 57| 85|114|142|171|199|228|256|285 */
+  limb tmp2[18], carry, x, xMask;
+  unsigned i;
+
+  /* tmp contains 64-bit words with the same 29,28,29-bit positions as an
+   * felem. So the top of an element of tmp might overlap with another
+   * element two positions down. The following loop eliminates this
+   * overlap. */
+  tmp2[0] = (limb)(tmp[0] & kBottom29Bits);
+
+  /* In the following we use "(limb) tmp[x]" and "(limb) (tmp[x]>>32)" to try
+   * and hint to the compiler that it can do a single-word shift by selecting
+   * the right register rather than doing a double-word shift and truncating
+   * afterwards. */
+  tmp2[1] = ((limb) tmp[0]) >> 29;
+  tmp2[1] |= (((limb)(tmp[0] >> 32)) << 3) & kBottom28Bits;
+  tmp2[1] += ((limb) tmp[1]) & kBottom28Bits;
+  carry = tmp2[1] >> 28;
+  tmp2[1] &= kBottom28Bits;
+
+  for (i = 2; i < 17; i++) {
+    tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25;
+    tmp2[i] += ((limb)(tmp[i - 1])) >> 28;
+    tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 4) & kBottom29Bits;
+    tmp2[i] += ((limb) tmp[i]) & kBottom29Bits;
+    tmp2[i] += carry;
+    carry = tmp2[i] >> 29;
+    tmp2[i] &= kBottom29Bits;
+
+    i++;
+    if (i == 17)
+      break;
+    tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25;
+    tmp2[i] += ((limb)(tmp[i - 1])) >> 29;
+    tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 3) & kBottom28Bits;
+    tmp2[i] += ((limb) tmp[i]) & kBottom28Bits;
+    tmp2[i] += carry;
+    carry = tmp2[i] >> 28;
+    tmp2[i] &= kBottom28Bits;
+  }
+
+  tmp2[17] = ((limb)(tmp[15] >> 32)) >> 25;
+  tmp2[17] += ((limb)(tmp[16])) >> 29;
+  tmp2[17] += (((limb)(tmp[16] >> 32)) << 3);
+  tmp2[17] += carry;
+
+  /* Montgomery elimination of terms.
+   *
+   * Since R is 2**257, we can divide by R with a bitwise shift if we can
+   * ensure that the right-most 257 bits are all zero. We can make that true by
+   * adding multiplies of p without affecting the value.
+   *
+   * So we eliminate limbs from right to left. Since the bottom 29 bits of p
+   * are all ones, then by adding tmp2[0]*p to tmp2 we'll make tmp2[0] == 0.
+   * We can do that for 8 further limbs and then right shift to eliminate the
+   * extra factor of R. */
+  for (i = 0;; i += 2) {
+    tmp2[i + 1] += tmp2[i] >> 29;
+    x = tmp2[i] & kBottom29Bits;
+    xMask = NON_ZERO_TO_ALL_ONES(x);
+    tmp2[i] = 0;
+
+    /* The bounds calculations for this loop are tricky. Each iteration of
+     * the loop eliminates two words by adding values to words to their
+     * right.
+     *
+     * The following table contains the amounts added to each word (as an
+     * offset from the value of i at the top of the loop). The amounts are
+     * accounted for from the first and second half of the loop separately
+     * and are written as, for example, 28 to mean a value <2**28.
+     *
+     * Word:                   3   4   5   6   7   8   9   10
+     * Added in top half:     28  11      29  21  29  28
+     *                                        28  29
+     *                                            29
+     * Added in bottom half:      29  10      28  21  28   28
+     *                                            29
+     *
+     * The value that is currently offset 7 will be offset 5 for the next
+     * iteration and then offset 3 for the iteration after that. Therefore
+     * the total value added will be the values added at 7, 5 and 3.
+     *
+     * The following table accumulates these values. The sums at the bottom
+     * are written as, for example, 29+28, to mean a value < 2**29+2**28.
+     *
+     * Word:                   3   4   5   6   7   8   9  10  11  12  13
+     *                        28  11  10  29  21  29  28  28  28  28  28
+     *                            29  28  11  28  29  28  29  28  29  28
+     *                                    29  28  21  21  29  21  29  21
+     *                                        10  29  28  21  28  21  28
+     *                                        28  29  28  29  28  29  28
+     *                                            11  10  29  10  29  10
+     *                                            29  28  11  28  11
+     *                                                    29      29
+     *                        --------------------------------------------
+     *                                                30+ 31+ 30+ 31+ 30+
+     *                                                28+ 29+ 28+ 29+ 21+
+     *                                                21+ 28+ 21+ 28+ 10
+     *                                                10  21+ 10  21+
+     *                                                    11      11
+     *
+     * So the greatest amount is added to tmp2[10] and tmp2[12]. If
+     * tmp2[10/12] has an initial value of <2**29, then the maximum value
+     * will be < 2**31 + 2**30 + 2**28 + 2**21 + 2**11, which is < 2**32,
+     * as required. */
+    tmp2[i + 3] += (x << 10) & kBottom28Bits;
+    tmp2[i + 4] += (x >> 18);
+
+    tmp2[i + 6] += (x << 21) & kBottom29Bits;
+    tmp2[i + 7] += x >> 8;
+
+    /* At position 200, which is the starting bit position for word 7, we
+     * have a factor of 0xf000000 = 2**28 - 2**24. */
+    tmp2[i + 7] += 0x10000000 & xMask;
+    /* Word 7 is 28 bits wide, so the 2**28 term exactly hits word 8. */
+    tmp2[i + 8] += (x - 1) & xMask;
+    tmp2[i + 7] -= (x << 24) & kBottom28Bits;
+    tmp2[i + 8] -= x >> 4;
+
+    tmp2[i + 8] += 0x20000000 & xMask;
+    tmp2[i + 8] -= x;
+    tmp2[i + 8] += (x << 28) & kBottom29Bits;
+    tmp2[i + 9] += ((x >> 1) - 1) & xMask;
+
+    if (i+1 == NLIMBS)
+      break;
+    tmp2[i + 2] += tmp2[i + 1] >> 28;
+    x = tmp2[i + 1] & kBottom28Bits;
+    xMask = NON_ZERO_TO_ALL_ONES(x);
+    tmp2[i + 1] = 0;
+
+    tmp2[i + 4] += (x << 11) & kBottom29Bits;
+    tmp2[i + 5] += (x >> 18);
+
+    tmp2[i + 7] += (x << 21) & kBottom28Bits;
+    tmp2[i + 8] += x >> 7;
+
+    /* At position 199, which is the starting bit of the 8th word when
+     * dealing with a context starting on an odd word, we have a factor of
+     * 0x1e000000 = 2**29 - 2**25. Since we have not updated i, the 8th
+     * word from i+1 is i+8. */
+    tmp2[i + 8] += 0x20000000 & xMask;
+    tmp2[i + 9] += (x - 1) & xMask;
+    tmp2[i + 8] -= (x << 25) & kBottom29Bits;
+    tmp2[i + 9] -= x >> 4;
+
+    tmp2[i + 9] += 0x10000000 & xMask;
+    tmp2[i + 9] -= x;
+    tmp2[i + 10] += (x - 1) & xMask;
+  }
+
+  /* We merge the right shift with a carry chain. The words above 2**257 have
+   * widths of 28,29,... which we need to correct when copying them down.  */
+  carry = 0;
+  for (i = 0; i < 8; i++) {
+    /* The maximum value of tmp2[i + 9] occurs on the first iteration and
+     * is < 2**30+2**29+2**28. Adding 2**29 (from tmp2[i + 10]) is
+     * therefore safe. */
+    out[i] = tmp2[i + 9];
+    out[i] += carry;
+    out[i] += (tmp2[i + 10] << 28) & kBottom29Bits;
+    carry = out[i] >> 29;
+    out[i] &= kBottom29Bits;
+
+    i++;
+    out[i] = tmp2[i + 9] >> 1;
+    out[i] += carry;
+    carry = out[i] >> 28;
+    out[i] &= kBottom28Bits;
+  }
+
+  out[8] = tmp2[17];
+  out[8] += carry;
+  carry = out[8] >> 29;
+  out[8] &= kBottom29Bits;
+
+  felem_reduce_carry(out, carry);
+}
+
+/* felem_square sets out=in*in.
+ *
+ * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_square(felem out, const felem in) {
+  u64 tmp[17];
+
+  tmp[0] = ((u64) in[0]) * in[0];
+  tmp[1] = ((u64) in[0]) * (in[1] << 1);
+  tmp[2] = ((u64) in[0]) * (in[2] << 1) +
+           ((u64) in[1]) * (in[1] << 1);
+  tmp[3] = ((u64) in[0]) * (in[3] << 1) +
+           ((u64) in[1]) * (in[2] << 1);
+  tmp[4] = ((u64) in[0]) * (in[4] << 1) +
+           ((u64) in[1]) * (in[3] << 2) + ((u64) in[2]) * in[2];
+  tmp[5] = ((u64) in[0]) * (in[5] << 1) + ((u64) in[1]) *
+           (in[4] << 1) + ((u64) in[2]) * (in[3] << 1);
+  tmp[6] = ((u64) in[0]) * (in[6] << 1) + ((u64) in[1]) *
+           (in[5] << 2) + ((u64) in[2]) * (in[4] << 1) +
+           ((u64) in[3]) * (in[3] << 1);
+  tmp[7] = ((u64) in[0]) * (in[7] << 1) + ((u64) in[1]) *
+           (in[6] << 1) + ((u64) in[2]) * (in[5] << 1) +
+           ((u64) in[3]) * (in[4] << 1);
+  /* tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60,
+   * which is < 2**64 as required. */
+  tmp[8] = ((u64) in[0]) * (in[8] << 1) + ((u64) in[1]) *
+           (in[7] << 2) + ((u64) in[2]) * (in[6] << 1) +
+           ((u64) in[3]) * (in[5] << 2) + ((u64) in[4]) * in[4];
+  tmp[9] = ((u64) in[1]) * (in[8] << 1) + ((u64) in[2]) *
+           (in[7] << 1) + ((u64) in[3]) * (in[6] << 1) +
+           ((u64) in[4]) * (in[5] << 1);
+  tmp[10] = ((u64) in[2]) * (in[8] << 1) + ((u64) in[3]) *
+            (in[7] << 2) + ((u64) in[4]) * (in[6] << 1) +
+            ((u64) in[5]) * (in[5] << 1);
+  tmp[11] = ((u64) in[3]) * (in[8] << 1) + ((u64) in[4]) *
+            (in[7] << 1) + ((u64) in[5]) * (in[6] << 1);
+  tmp[12] = ((u64) in[4]) * (in[8] << 1) +
+            ((u64) in[5]) * (in[7] << 2) + ((u64) in[6]) * in[6];
+  tmp[13] = ((u64) in[5]) * (in[8] << 1) +
+            ((u64) in[6]) * (in[7] << 1);
+  tmp[14] = ((u64) in[6]) * (in[8] << 1) +
+            ((u64) in[7]) * (in[7] << 1);
+  tmp[15] = ((u64) in[7]) * (in[8] << 1);
+  tmp[16] = ((u64) in[8]) * in[8];
+
+  felem_reduce_degree(out, tmp);
+}
+
+/* felem_mul sets out=in*in2.
+ *
+ * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
+ *           in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_mul(felem out, const felem in, const felem in2) {
+  u64 tmp[17];
+
+  tmp[0] = ((u64) in[0]) * in2[0];
+  tmp[1] = ((u64) in[0]) * (in2[1] << 0) +
+           ((u64) in[1]) * (in2[0] << 0);
+  tmp[2] = ((u64) in[0]) * (in2[2] << 0) + ((u64) in[1]) *
+           (in2[1] << 1) + ((u64) in[2]) * (in2[0] << 0);
+  tmp[3] = ((u64) in[0]) * (in2[3] << 0) + ((u64) in[1]) *
+           (in2[2] << 0) + ((u64) in[2]) * (in2[1] << 0) +
+           ((u64) in[3]) * (in2[0] << 0);
+  tmp[4] = ((u64) in[0]) * (in2[4] << 0) + ((u64) in[1]) *
+           (in2[3] << 1) + ((u64) in[2]) * (in2[2] << 0) +
+           ((u64) in[3]) * (in2[1] << 1) +
+           ((u64) in[4]) * (in2[0] << 0);
+  tmp[5] = ((u64) in[0]) * (in2[5] << 0) + ((u64) in[1]) *
+           (in2[4] << 0) + ((u64) in[2]) * (in2[3] << 0) +
+           ((u64) in[3]) * (in2[2] << 0) + ((u64) in[4]) *
+           (in2[1] << 0) + ((u64) in[5]) * (in2[0] << 0);
+  tmp[6] = ((u64) in[0]) * (in2[6] << 0) + ((u64) in[1]) *
+           (in2[5] << 1) + ((u64) in[2]) * (in2[4] << 0) +
+           ((u64) in[3]) * (in2[3] << 1) + ((u64) in[4]) *
+           (in2[2] << 0) + ((u64) in[5]) * (in2[1] << 1) +
+           ((u64) in[6]) * (in2[0] << 0);
+  tmp[7] = ((u64) in[0]) * (in2[7] << 0) + ((u64) in[1]) *
+           (in2[6] << 0) + ((u64) in[2]) * (in2[5] << 0) +
+           ((u64) in[3]) * (in2[4] << 0) + ((u64) in[4]) *
+           (in2[3] << 0) + ((u64) in[5]) * (in2[2] << 0) +
+           ((u64) in[6]) * (in2[1] << 0) +
+           ((u64) in[7]) * (in2[0] << 0);
+  /* tmp[8] has the greatest value but doesn't overflow. See logic in
+   * felem_square. */
+  tmp[8] = ((u64) in[0]) * (in2[8] << 0) + ((u64) in[1]) *
+           (in2[7] << 1) + ((u64) in[2]) * (in2[6] << 0) +
+           ((u64) in[3]) * (in2[5] << 1) + ((u64) in[4]) *
+           (in2[4] << 0) + ((u64) in[5]) * (in2[3] << 1) +
+           ((u64) in[6]) * (in2[2] << 0) + ((u64) in[7]) *
+           (in2[1] << 1) + ((u64) in[8]) * (in2[0] << 0);
+  tmp[9] = ((u64) in[1]) * (in2[8] << 0) + ((u64) in[2]) *
+           (in2[7] << 0) + ((u64) in[3]) * (in2[6] << 0) +
+           ((u64) in[4]) * (in2[5] << 0) + ((u64) in[5]) *
+           (in2[4] << 0) + ((u64) in[6]) * (in2[3] << 0) +
+           ((u64) in[7]) * (in2[2] << 0) +
+           ((u64) in[8]) * (in2[1] << 0);
+  tmp[10] = ((u64) in[2]) * (in2[8] << 0) + ((u64) in[3]) *
+            (in2[7] << 1) + ((u64) in[4]) * (in2[6] << 0) +
+            ((u64) in[5]) * (in2[5] << 1) + ((u64) in[6]) *
+            (in2[4] << 0) + ((u64) in[7]) * (in2[3] << 1) +
+            ((u64) in[8]) * (in2[2] << 0);
+  tmp[11] = ((u64) in[3]) * (in2[8] << 0) + ((u64) in[4]) *
+            (in2[7] << 0) + ((u64) in[5]) * (in2[6] << 0) +
+            ((u64) in[6]) * (in2[5] << 0) + ((u64) in[7]) *
+            (in2[4] << 0) + ((u64) in[8]) * (in2[3] << 0);
+  tmp[12] = ((u64) in[4]) * (in2[8] << 0) + ((u64) in[5]) *
+            (in2[7] << 1) + ((u64) in[6]) * (in2[6] << 0) +
+            ((u64) in[7]) * (in2[5] << 1) +
+            ((u64) in[8]) * (in2[4] << 0);
+  tmp[13] = ((u64) in[5]) * (in2[8] << 0) + ((u64) in[6]) *
+            (in2[7] << 0) + ((u64) in[7]) * (in2[6] << 0) +
+            ((u64) in[8]) * (in2[5] << 0);
+  tmp[14] = ((u64) in[6]) * (in2[8] << 0) + ((u64) in[7]) *
+            (in2[7] << 1) + ((u64) in[8]) * (in2[6] << 0);
+  tmp[15] = ((u64) in[7]) * (in2[8] << 0) +
+            ((u64) in[8]) * (in2[7] << 0);
+  tmp[16] = ((u64) in[8]) * (in2[8] << 0);
+
+  felem_reduce_degree(out, tmp);
+}
+
+static void felem_assign(felem out, const felem in) {
+  memcpy(out, in, sizeof(felem));
+}
+
+/* felem_inv calculates |out| = |in|^{-1}
+ *
+ * Based on Fermat's Little Theorem:
+ *   a^p = a (mod p)
+ *   a^{p-1} = 1 (mod p)
+ *   a^{p-2} = a^{-1} (mod p)
+ */
+static void felem_inv(felem out, const felem in) {
+  felem ftmp, ftmp2;
+  /* each e_I will hold |in|^{2^I - 1} */
+  felem e2, e4, e8, e16, e32, e64;
+  unsigned i;
+
+  felem_square(ftmp, in); /* 2^1 */
+  felem_mul(ftmp, in, ftmp); /* 2^2 - 2^0 */
+  felem_assign(e2, ftmp);
+  felem_square(ftmp, ftmp); /* 2^3 - 2^1 */
+  felem_square(ftmp, ftmp); /* 2^4 - 2^2 */
+  felem_mul(ftmp, ftmp, e2); /* 2^4 - 2^0 */
+  felem_assign(e4, ftmp);
+  felem_square(ftmp, ftmp); /* 2^5 - 2^1 */
+  felem_square(ftmp, ftmp); /* 2^6 - 2^2 */
+  felem_square(ftmp, ftmp); /* 2^7 - 2^3 */
+  felem_square(ftmp, ftmp); /* 2^8 - 2^4 */
+  felem_mul(ftmp, ftmp, e4); /* 2^8 - 2^0 */
+  felem_assign(e8, ftmp);
+  for (i = 0; i < 8; i++) {
+    felem_square(ftmp, ftmp);
+  } /* 2^16 - 2^8 */
+  felem_mul(ftmp, ftmp, e8); /* 2^16 - 2^0 */
+  felem_assign(e16, ftmp);
+  for (i = 0; i < 16; i++) {
+    felem_square(ftmp, ftmp);
+  } /* 2^32 - 2^16 */
+  felem_mul(ftmp, ftmp, e16); /* 2^32 - 2^0 */
+  felem_assign(e32, ftmp);
+  for (i = 0; i < 32; i++) {
+    felem_square(ftmp, ftmp);
+  } /* 2^64 - 2^32 */
+  felem_assign(e64, ftmp);
+  felem_mul(ftmp, ftmp, in); /* 2^64 - 2^32 + 2^0 */
+  for (i = 0; i < 192; i++) {
+    felem_square(ftmp, ftmp);
+  } /* 2^256 - 2^224 + 2^192 */
+
+  felem_mul(ftmp2, e64, e32); /* 2^64 - 2^0 */
+  for (i = 0; i < 16; i++) {
+    felem_square(ftmp2, ftmp2);
+  } /* 2^80 - 2^16 */
+  felem_mul(ftmp2, ftmp2, e16); /* 2^80 - 2^0 */
+  for (i = 0; i < 8; i++) {
+    felem_square(ftmp2, ftmp2);
+  } /* 2^88 - 2^8 */
+  felem_mul(ftmp2, ftmp2, e8); /* 2^88 - 2^0 */
+  for (i = 0; i < 4; i++) {
+    felem_square(ftmp2, ftmp2);
+  } /* 2^92 - 2^4 */
+  felem_mul(ftmp2, ftmp2, e4); /* 2^92 - 2^0 */
+  felem_square(ftmp2, ftmp2); /* 2^93 - 2^1 */
+  felem_square(ftmp2, ftmp2); /* 2^94 - 2^2 */
+  felem_mul(ftmp2, ftmp2, e2); /* 2^94 - 2^0 */
+  felem_square(ftmp2, ftmp2); /* 2^95 - 2^1 */
+  felem_square(ftmp2, ftmp2); /* 2^96 - 2^2 */
+  felem_mul(ftmp2, ftmp2, in); /* 2^96 - 3 */
+
+  felem_mul(out, ftmp2, ftmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */
+}
+
+/* felem_scalar_3 sets out=3*out.
+ *
+ * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_scalar_3(felem out) {
+  limb carry = 0;
+  unsigned i;
+
+  for (i = 0;; i++) {
+    out[i] *= 3;
+    out[i] += carry;
+    carry = out[i] >> 29;
+    out[i] &= kBottom29Bits;
+
+    i++;
+    if (i == NLIMBS)
+      break;
+
+    out[i] *= 3;
+    out[i] += carry;
+    carry = out[i] >> 28;
+    out[i] &= kBottom28Bits;
+  }
+
+  felem_reduce_carry(out, carry);
+}
+
+/* felem_scalar_4 sets out=4*out.
+ *
+ * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_scalar_4(felem out) {
+  limb carry = 0, next_carry;
+  unsigned i;
+
+  for (i = 0;; i++) {
+    next_carry = out[i] >> 27;
+    out[i] <<= 2;
+    out[i] &= kBottom29Bits;
+    out[i] += carry;
+    carry = next_carry + (out[i] >> 29);
+    out[i] &= kBottom29Bits;
+
+    i++;
+    if (i == NLIMBS)
+      break;
+
+    next_carry = out[i] >> 26;
+    out[i] <<= 2;
+    out[i] &= kBottom28Bits;
+    out[i] += carry;
+    carry = next_carry + (out[i] >> 28);
+    out[i] &= kBottom28Bits;
+  }
+
+  felem_reduce_carry(out, carry);
+}
+
+/* felem_scalar_8 sets out=8*out.
+ *
+ * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_scalar_8(felem out) {
+  limb carry = 0, next_carry;
+  unsigned i;
+
+  for (i = 0;; i++) {
+    next_carry = out[i] >> 26;
+    out[i] <<= 3;
+    out[i] &= kBottom29Bits;
+    out[i] += carry;
+    carry = next_carry + (out[i] >> 29);
+    out[i] &= kBottom29Bits;
+
+    i++;
+    if (i == NLIMBS)
+      break;
+
+    next_carry = out[i] >> 25;
+    out[i] <<= 3;
+    out[i] &= kBottom28Bits;
+    out[i] += carry;
+    carry = next_carry + (out[i] >> 28);
+    out[i] &= kBottom28Bits;
+  }
+
+  felem_reduce_carry(out, carry);
+}
+
+/* felem_is_zero_vartime returns 1 iff |in| == 0. It takes a variable amount of
+ * time depending on the value of |in|. */
+static char felem_is_zero_vartime(const felem in) {
+  limb carry;
+  int i;
+  limb tmp[NLIMBS];
+
+  felem_assign(tmp, in);
+
+  /* First, reduce tmp to a minimal form. */
+  do {
+    carry = 0;
+    for (i = 0;; i++) {
+      tmp[i] += carry;
+      carry = tmp[i] >> 29;
+      tmp[i] &= kBottom29Bits;
+
+      i++;
+      if (i == NLIMBS)
+        break;
+
+      tmp[i] += carry;
+      carry = tmp[i] >> 28;
+      tmp[i] &= kBottom28Bits;
+    }
+
+    felem_reduce_carry(tmp, carry);
+  } while (carry);
+
+  /* tmp < 2**257, so the only possible zero values are 0, p and 2p. */
+  return memcmp(tmp, kZero, sizeof(tmp)) == 0 ||
+         memcmp(tmp, kP, sizeof(tmp)) == 0 ||
+         memcmp(tmp, k2P, sizeof(tmp)) == 0;
+}
+
+
+/* Group operations:
+ *
+ * Elements of the elliptic curve group are represented in Jacobian
+ * coordinates: (x, y, z). An affine point (x', y') is x'=x/z**2, y'=y/z**3 in
+ * Jacobian form. */
+
+/* point_double sets {x_out,y_out,z_out} = 2*{x,y,z}.
+ *
+ * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l */
+static void point_double(felem x_out, felem y_out, felem z_out, const felem x,
+                         const felem y, const felem z) {
+  felem delta, gamma, alpha, beta, tmp, tmp2;
+
+  felem_square(delta, z);
+  felem_square(gamma, y);
+  felem_mul(beta, x, gamma);
+
+  felem_sum(tmp, x, delta);
+  felem_diff(tmp2, x, delta);
+  felem_mul(alpha, tmp, tmp2);
+  felem_scalar_3(alpha);
+
+  felem_sum(tmp, y, z);
+  felem_square(tmp, tmp);
+  felem_diff(tmp, tmp, gamma);
+  felem_diff(z_out, tmp, delta);
+
+  felem_scalar_4(beta);
+  felem_square(x_out, alpha);
+  felem_diff(x_out, x_out, beta);
+  felem_diff(x_out, x_out, beta);
+
+  felem_diff(tmp, beta, x_out);
+  felem_mul(tmp, alpha, tmp);
+  felem_square(tmp2, gamma);
+  felem_scalar_8(tmp2);
+  felem_diff(y_out, tmp, tmp2);
+}
+
+/* point_add_mixed sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,1}.
+ * (i.e. the second point is affine.)
+ *
+ * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ *
+ * Note that this function does not handle P+P, infinity+P nor P+infinity
+ * correctly. */
+static void point_add_mixed(felem x_out, felem y_out, felem z_out,
+                            const felem x1, const felem y1, const felem z1,
+                            const felem x2, const felem y2) {
+  felem z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp;
+
+  felem_square(z1z1, z1);
+  felem_sum(tmp, z1, z1);
+
+  felem_mul(u2, x2, z1z1);
+  felem_mul(z1z1z1, z1, z1z1);
+  felem_mul(s2, y2, z1z1z1);
+  felem_diff(h, u2, x1);
+  felem_sum(i, h, h);
+  felem_square(i, i);
+  felem_mul(j, h, i);
+  felem_diff(r, s2, y1);
+  felem_sum(r, r, r);
+  felem_mul(v, x1, i);
+
+  felem_mul(z_out, tmp, h);
+  felem_square(rr, r);
+  felem_diff(x_out, rr, j);
+  felem_diff(x_out, x_out, v);
+  felem_diff(x_out, x_out, v);
+
+  felem_diff(tmp, v, x_out);
+  felem_mul(y_out, tmp, r);
+  felem_mul(tmp, y1, j);
+  felem_diff(y_out, y_out, tmp);
+  felem_diff(y_out, y_out, tmp);
+}
+
+/* point_add sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,z2}.
+ *
+ * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ *
+ * Note that this function does not handle P+P, infinity+P nor P+infinity
+ * correctly. */
+static void point_add(felem x_out, felem y_out, felem z_out, const felem x1,
+                      const felem y1, const felem z1, const felem x2,
+                      const felem y2, const felem z2) {
+  felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp;
+
+  felem_square(z1z1, z1);
+  felem_square(z2z2, z2);
+  felem_mul(u1, x1, z2z2);
+
+  felem_sum(tmp, z1, z2);
+  felem_square(tmp, tmp);
+  felem_diff(tmp, tmp, z1z1);
+  felem_diff(tmp, tmp, z2z2);
+
+  felem_mul(z2z2z2, z2, z2z2);
+  felem_mul(s1, y1, z2z2z2);
+
+  felem_mul(u2, x2, z1z1);
+  felem_mul(z1z1z1, z1, z1z1);
+  felem_mul(s2, y2, z1z1z1);
+  felem_diff(h, u2, u1);
+  felem_sum(i, h, h);
+  felem_square(i, i);
+  felem_mul(j, h, i);
+  felem_diff(r, s2, s1);
+  felem_sum(r, r, r);
+  felem_mul(v, u1, i);
+
+  felem_mul(z_out, tmp, h);
+  felem_square(rr, r);
+  felem_diff(x_out, rr, j);
+  felem_diff(x_out, x_out, v);
+  felem_diff(x_out, x_out, v);
+
+  felem_diff(tmp, v, x_out);
+  felem_mul(y_out, tmp, r);
+  felem_mul(tmp, s1, j);
+  felem_diff(y_out, y_out, tmp);
+  felem_diff(y_out, y_out, tmp);
+}
+
+/* point_add_or_double_vartime sets {x_out,y_out,z_out} = {x1,y1,z1} +
+ *                                                        {x2,y2,z2}.
+ *
+ * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ *
+ * This function handles the case where {x1,y1,z1}={x2,y2,z2}. */
+static void point_add_or_double_vartime(
+    felem x_out, felem y_out, felem z_out, const felem x1, const felem y1,
+    const felem z1, const felem x2, const felem y2, const felem z2) {
+  felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp;
+  char x_equal, y_equal;
+
+  felem_square(z1z1, z1);
+  felem_square(z2z2, z2);
+  felem_mul(u1, x1, z2z2);
+
+  felem_sum(tmp, z1, z2);
+  felem_square(tmp, tmp);
+  felem_diff(tmp, tmp, z1z1);
+  felem_diff(tmp, tmp, z2z2);
+
+  felem_mul(z2z2z2, z2, z2z2);
+  felem_mul(s1, y1, z2z2z2);
+
+  felem_mul(u2, x2, z1z1);
+  felem_mul(z1z1z1, z1, z1z1);
+  felem_mul(s2, y2, z1z1z1);
+  felem_diff(h, u2, u1);
+  x_equal = felem_is_zero_vartime(h);
+  felem_sum(i, h, h);
+  felem_square(i, i);
+  felem_mul(j, h, i);
+  felem_diff(r, s2, s1);
+  y_equal = felem_is_zero_vartime(r);
+  if (x_equal && y_equal) {
+    point_double(x_out, y_out, z_out, x1, y1, z1);
+    return;
+  }
+  felem_sum(r, r, r);
+  felem_mul(v, u1, i);
+
+  felem_mul(z_out, tmp, h);
+  felem_square(rr, r);
+  felem_diff(x_out, rr, j);
+  felem_diff(x_out, x_out, v);
+  felem_diff(x_out, x_out, v);
+
+  felem_diff(tmp, v, x_out);
+  felem_mul(y_out, tmp, r);
+  felem_mul(tmp, s1, j);
+  felem_diff(y_out, y_out, tmp);
+  felem_diff(y_out, y_out, tmp);
+}
+
+/* copy_conditional sets out=in if mask = 0xffffffff in constant time.
+ *
+ * On entry: mask is either 0 or 0xffffffff. */
+static void copy_conditional(felem out, const felem in, limb mask) {
+  int i;
+
+  for (i = 0; i < NLIMBS; i++) {
+    const limb tmp = mask & (in[i] ^ out[i]);
+    out[i] ^= tmp;
+  }
+}
+
+/* select_affine_point sets {out_x,out_y} to the index'th entry of table.
+ * On entry: index < 16, table[0] must be zero. */
+static void select_affine_point(felem out_x, felem out_y, const limb* table,
+                                limb index) {
+  limb i, j;
+
+  memset(out_x, 0, sizeof(felem));
+  memset(out_y, 0, sizeof(felem));
+
+  for (i = 1; i < 16; i++) {
+    limb mask = i ^ index;
+    mask |= mask >> 2;
+    mask |= mask >> 1;
+    mask &= 1;
+    mask--;
+    for (j = 0; j < NLIMBS; j++, table++) {
+      out_x[j] |= *table & mask;
+    }
+    for (j = 0; j < NLIMBS; j++, table++) {
+      out_y[j] |= *table & mask;
+    }
+  }
+}
+
+/* select_jacobian_point sets {out_x,out_y,out_z} to the index'th entry of
+ * table. On entry: index < 16, table[0] must be zero. */
+static void select_jacobian_point(felem out_x, felem out_y, felem out_z,
+                                  const limb* table, limb index) {
+  limb i, j;
+
+  memset(out_x, 0, sizeof(felem));
+  memset(out_y, 0, sizeof(felem));
+  memset(out_z, 0, sizeof(felem));
+
+  /* The implicit value at index 0 is all zero. We don't need to perform that
+   * iteration of the loop because we already set out_* to zero. */
+  table += 3 * NLIMBS;
+
+  // Hit all entries to obscure cache profiling.
+  for (i = 1; i < 16; i++) {
+    limb mask = i ^ index;
+    mask |= mask >> 2;
+    mask |= mask >> 1;
+    mask &= 1;
+    mask--;
+    for (j = 0; j < NLIMBS; j++, table++) {
+      out_x[j] |= *table & mask;
+    }
+    for (j = 0; j < NLIMBS; j++, table++) {
+      out_y[j] |= *table & mask;
+    }
+    for (j = 0; j < NLIMBS; j++, table++) {
+      out_z[j] |= *table & mask;
+    }
+  }
+}
+
+/* scalar_base_mult sets {nx,ny,nz} = scalar*G where scalar is a little-endian
+ * number. Note that the value of scalar must be less than the order of the
+ * group. */
+static void scalar_base_mult(felem nx, felem ny, felem nz,
+                             const p256_int* scalar) {
+  int i, j;
+  limb n_is_infinity_mask = -1, p_is_noninfinite_mask, mask;
+  u32 table_offset;
+
+  felem px, py;
+  felem tx, ty, tz;
+
+  memset(nx, 0, sizeof(felem));
+  memset(ny, 0, sizeof(felem));
+  memset(nz, 0, sizeof(felem));
+
+  /* The loop adds bits at positions 0, 64, 128 and 192, followed by
+   * positions 32,96,160 and 224 and does this 32 times. */
+  for (i = 0; i < 32; i++) {
+    if (i) {
+      point_double(nx, ny, nz, nx, ny, nz);
+    }
+    table_offset = 0;
+    for (j = 0; j <= 32; j += 32) {
+      char bit0 = p256_get_bit(scalar, 31 - i + j);
+      char bit1 = p256_get_bit(scalar, 95 - i + j);
+      char bit2 = p256_get_bit(scalar, 159 - i + j);
+      char bit3 = p256_get_bit(scalar, 223 - i + j);
+      limb index = bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3);
+
+      select_affine_point(px, py, kPrecomputed + table_offset, index);
+      table_offset += 30 * NLIMBS;
+
+      /* Since scalar is less than the order of the group, we know that
+       * {nx,ny,nz} != {px,py,1}, unless both are zero, which we handle
+       * below. */
+      point_add_mixed(tx, ty, tz, nx, ny, nz, px, py);
+      /* The result of point_add_mixed is incorrect if {nx,ny,nz} is zero
+       * (a.k.a.  the point at infinity). We handle that situation by
+       * copying the point from the table. */
+      copy_conditional(nx, px, n_is_infinity_mask);
+      copy_conditional(ny, py, n_is_infinity_mask);
+      copy_conditional(nz, kOne, n_is_infinity_mask);
+
+      /* Equally, the result is also wrong if the point from the table is
+       * zero, which happens when the index is zero. We handle that by
+       * only copying from {tx,ty,tz} to {nx,ny,nz} if index != 0. */
+      p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);
+      mask = p_is_noninfinite_mask & ~n_is_infinity_mask;
+      copy_conditional(nx, tx, mask);
+      copy_conditional(ny, ty, mask);
+      copy_conditional(nz, tz, mask);
+      /* If p was not zero, then n is now non-zero. */
+      n_is_infinity_mask &= ~p_is_noninfinite_mask;
+    }
+  }
+}
+
+/* point_to_affine converts a Jacobian point to an affine point. If the input
+ * is the point at infinity then it returns (0, 0) in constant time. */
+static void point_to_affine(felem x_out, felem y_out, const felem nx,
+                            const felem ny, const felem nz) {
+  felem z_inv, z_inv_sq;
+  felem_inv(z_inv, nz);
+  felem_square(z_inv_sq, z_inv);
+  felem_mul(x_out, nx, z_inv_sq);
+  felem_mul(z_inv, z_inv, z_inv_sq);
+  felem_mul(y_out, ny, z_inv);
+}
+
+/* scalar_base_mult sets {nx,ny,nz} = scalar*{x,y}. */
+static void scalar_mult(felem nx, felem ny, felem nz, const felem x,
+                        const felem y, const p256_int* scalar) {
+  int i;
+  felem px, py, pz, tx, ty, tz;
+  felem precomp[16][3];
+  limb n_is_infinity_mask, index, p_is_noninfinite_mask, mask;
+
+  /* We precompute 0,1,2,... times {x,y}. */
+  memset(precomp, 0, sizeof(felem) * 3);
+  memcpy(&precomp[1][0], x, sizeof(felem));
+  memcpy(&precomp[1][1], y, sizeof(felem));
+  memcpy(&precomp[1][2], kOne, sizeof(felem));
+
+  for (i = 2; i < 16; i += 2) {
+    point_double(precomp[i][0], precomp[i][1], precomp[i][2],
+                 precomp[i / 2][0], precomp[i / 2][1], precomp[i / 2][2]);
+
+    point_add_mixed(precomp[i + 1][0], precomp[i + 1][1], precomp[i + 1][2],
+                    precomp[i][0], precomp[i][1], precomp[i][2], x, y);
+  }
+
+  memset(nx, 0, sizeof(felem));
+  memset(ny, 0, sizeof(felem));
+  memset(nz, 0, sizeof(felem));
+  n_is_infinity_mask = -1;
+
+  /* We add in a window of four bits each iteration and do this 64 times. */
+  for (i = 0; i < 256; i += 4) {
+    if (i) {
+      point_double(nx, ny, nz, nx, ny, nz);
+      point_double(nx, ny, nz, nx, ny, nz);
+      point_double(nx, ny, nz, nx, ny, nz);
+      point_double(nx, ny, nz, nx, ny, nz);
+    }
+
+    index = (p256_get_bit(scalar, 255 - i - 0) << 3) |
+            (p256_get_bit(scalar, 255 - i - 1) << 2) |
+            (p256_get_bit(scalar, 255 - i - 2) << 1) |
+            p256_get_bit(scalar, 255 - i - 3);
+
+    /* See the comments in scalar_base_mult about handling infinities. */
+    select_jacobian_point(px, py, pz, precomp[0][0], index);
+    point_add(tx, ty, tz, nx, ny, nz, px, py, pz);
+    copy_conditional(nx, px, n_is_infinity_mask);
+    copy_conditional(ny, py, n_is_infinity_mask);
+    copy_conditional(nz, pz, n_is_infinity_mask);
+
+    p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);
+    mask = p_is_noninfinite_mask & ~n_is_infinity_mask;
+
+    copy_conditional(nx, tx, mask);
+    copy_conditional(ny, ty, mask);
+    copy_conditional(nz, tz, mask);
+    n_is_infinity_mask &= ~p_is_noninfinite_mask;
+  }
+}
+
+#define kRDigits {2, 0, 0, 0xfffffffe, 0xffffffff, 0xffffffff, 0xfffffffd, 1} // 2^257 mod p256.p
+
+#define kRInvDigits {0x80000000, 1, 0xffffffff, 0, 0x80000001, 0xfffffffe, 1, 0x7fffffff}  // 1 / 2^257 mod p256.p
+
+static const p256_int kR = { kRDigits };
+static const p256_int kRInv = { kRInvDigits };
+
+/* to_montgomery sets out = R*in. */
+static void to_montgomery(felem out, const p256_int* in) {
+  p256_int in_shifted;
+  int i;
+
+  p256_init(&in_shifted);
+  p256_modmul(&SECP256r1_p, in, 0, &kR, &in_shifted);
+
+  for (i = 0; i < NLIMBS; i++) {
+    if ((i & 1) == 0) {
+      out[i] = P256_DIGIT(&in_shifted, 0) & kBottom29Bits;
+      p256_shr(&in_shifted, 29, &in_shifted);
+    } else {
+      out[i] = P256_DIGIT(&in_shifted, 0) & kBottom28Bits;
+      p256_shr(&in_shifted, 28, &in_shifted);
+    }
+  }
+
+  p256_clear(&in_shifted);
+}
+
+/* from_montgomery sets out=in/R. */
+static void from_montgomery(p256_int* out, const felem in) {
+  p256_int result, tmp;
+  int i, top;
+
+  p256_init(&result);
+  p256_init(&tmp);
+
+  p256_add_d(&tmp, in[NLIMBS - 1], &result);
+  for (i = NLIMBS - 2; i >= 0; i--) {
+    if ((i & 1) == 0) {
+      top = p256_shl(&result, 29, &tmp);
+    } else {
+      top = p256_shl(&result, 28, &tmp);
+    }
+    top |= p256_add_d(&tmp, in[i], &result);
+  }
+
+  p256_modmul(&SECP256r1_p, &kRInv, top, &result, out);
+
+  p256_clear(&result);
+  p256_clear(&tmp);
+}
+
+/* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the
+ * order of the group. */
+void p256_base_point_mul(const p256_int* n, p256_int* out_x, p256_int* out_y) {
+  felem x, y, z;
+
+  scalar_base_mult(x, y, z, n);
+
+  {
+    felem x_affine, y_affine;
+
+    point_to_affine(x_affine, y_affine, x, y, z);
+    from_montgomery(out_x, x_affine);
+    from_montgomery(out_y, y_affine);
+  }
+}
+
+/* p256_points_mul_vartime sets {out_x,out_y} = n1*G + n2*{in_x,in_y}, where
+ * n1 and n2 are < the order of the group.
+ *
+ * As indicated by the name, this function operates in variable time. This
+ * is safe because it's used for signature validation which doesn't deal
+ * with secrets. */
+void p256_points_mul_vartime(
+    const p256_int* n1, const p256_int* n2, const p256_int* in_x,
+    const p256_int* in_y, p256_int* out_x, p256_int* out_y) {
+  felem x1, y1, z1, x2, y2, z2, px, py;
+
+  /* If both scalars are zero, then the result is the point at infinity. */
+  if (p256_is_zero(n1) != 0 && p256_is_zero(n2) != 0) {
+    p256_clear(out_x);
+    p256_clear(out_y);
+    return;
+  }
+
+  to_montgomery(px, in_x);
+  to_montgomery(py, in_y);
+  scalar_base_mult(x1, y1, z1, n1);
+  scalar_mult(x2, y2, z2, px, py, n2);
+
+  if (p256_is_zero(n2) != 0) {
+    /* If n2 == 0, then {x2,y2,z2} is zero and the result is just
+         * {x1,y1,z1}. */
+  } else if (p256_is_zero(n1) != 0) {
+    /* If n1 == 0, then {x1,y1,z1} is zero and the result is just
+         * {x2,y2,z2}. */
+    memcpy(x1, x2, sizeof(x2));
+    memcpy(y1, y2, sizeof(y2));
+    memcpy(z1, z2, sizeof(z2));
+  } else {
+    /* This function handles the case where {x1,y1,z1} == {x2,y2,z2}. */
+    point_add_or_double_vartime(x1, y1, z1, x1, y1, z1, x2, y2, z2);
+  }
+
+  point_to_affine(px, py, x1, y1, z1);
+  from_montgomery(out_x, px);
+  from_montgomery(out_y, py);
+}
diff --git a/libmincrypt/p256_ecdsa.c b/libmincrypt/p256_ecdsa.c
new file mode 100644
index 0000000..f2264b0
--- /dev/null
+++ b/libmincrypt/p256_ecdsa.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google Inc. nor the names of its contributors may
+ *       be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "mincrypt/p256_ecdsa.h"
+#include "mincrypt/p256.h"
+
+int p256_ecdsa_verify(const p256_int* key_x, const p256_int* key_y,
+                      const p256_int* message,
+                      const p256_int* r, const p256_int* s) {
+  p256_int u, v;
+
+  // Check public key.
+  if (!p256_is_valid_point(key_x, key_y)) return 0;
+
+  // Check r and s are != 0 % n.
+  p256_mod(&SECP256r1_n, r, &u);
+  p256_mod(&SECP256r1_n, s, &v);
+  if (p256_is_zero(&u) || p256_is_zero(&v)) return 0;
+
+  p256_modinv_vartime(&SECP256r1_n, s, &v);
+  p256_modmul(&SECP256r1_n, message, 0, &v, &u);  // message / s % n
+  p256_modmul(&SECP256r1_n, r, 0, &v, &v);  // r / s % n
+
+  p256_points_mul_vartime(&u, &v,
+                          key_x, key_y,
+                          &u, &v);
+
+  p256_mod(&SECP256r1_n, &u, &u);  // (x coord % p) % n
+  return p256_cmp(r, &u) == 0;
+}
+
diff --git a/libmincrypt/test/Android.mk b/libmincrypt/test/Android.mk
index a28ccd8..73ff7d0 100644
--- a/libmincrypt/test/Android.mk
+++ b/libmincrypt/test/Android.mk
@@ -1,10 +1,15 @@
 # Copyright 2013 The Android Open Source Project
 
 LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
 
+include $(CLEAR_VARS)
 LOCAL_MODULE := rsa_test
 LOCAL_SRC_FILES := rsa_test.c
 LOCAL_STATIC_LIBRARIES := libmincrypt
-include $(BUILD_HOST_EXECUTABLE)
+include $(BUILD_HOST_NATIVE_TEST)
 
+include $(CLEAR_VARS)
+LOCAL_MODULE := ecdsa_test
+LOCAL_SRC_FILES := ecdsa_test.c
+LOCAL_STATIC_LIBRARIES := libmincrypt
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libmincrypt/test/ecdsa_test.c b/libmincrypt/test/ecdsa_test.c
new file mode 100644
index 0000000..b5a7b3a
--- /dev/null
+++ b/libmincrypt/test/ecdsa_test.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Google Inc. nor the names of its contributors may
+ *       be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mincrypt/p256.h"
+#include "mincrypt/p256_ecdsa.h"
+#include "mincrypt/sha256.h"
+
+/**
+ * Messages signed using:
+ *
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIDw6UiziVMbjlfSpOAIpA2tcL+v1OlznZLnpadO8BGi1oAoGCCqGSM49
+AwEHoUQDQgAEZw7VAOjAXYRFuhZWYBgjahdOvkwcAnjGkxQWytZW+iS1hI3ZGE24
+6XmNka9IGxAgj2n/ip+MuZJMFoJ9DRea3g==
+-----END EC PRIVATE KEY-----
+ */
+
+p256_int key_x = {
+    .a = {0xd656fa24u, 0x931416cau, 0x1c0278c6u, 0x174ebe4cu,
+          0x6018236au, 0x45ba1656u, 0xe8c05d84u, 0x670ed500u}
+};
+p256_int key_y = {
+    .a = {0x0d179adeu, 0x4c16827du, 0x9f8cb992u, 0x8f69ff8au,
+          0x481b1020u, 0x798d91afu, 0x184db8e9u, 0xb5848dd9u}
+};
+
+char* message_1 =
+    "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
+    "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
+    "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
+    "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
+    "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
+    "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
+    "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
+    "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
+    "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
+    "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
+    "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
+    "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
+    "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
+    "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
+    "d5 9d 73 be 12";
+
+char* signature_1 =
+    "30 44 02 20 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
+    "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
+    "7c 98 25 d9 02 20 54 f3 7f 5a e9 36 9c a2 f0 51"
+    "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
+    "ea 57 7e 88 46 12";
+
+// Same as signature 1, but with leading zeroes.
+char* message_2 =
+    "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
+    "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
+    "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
+    "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
+    "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
+    "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
+    "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
+    "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
+    "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
+    "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
+    "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
+    "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
+    "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
+    "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
+    "d5 9d 73 be 12";
+
+char* signature_2 =
+    "30 46 02 21 00 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
+    "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
+    "7c 98 25 d9 02 21 00 54 f3 7f 5a e9 36 9c a2 f0 51"
+    "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
+    "ea 57 7e 88 46 12";
+
+// Excessive zeroes on the signature
+char* message_3 =
+    "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
+    "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
+    "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
+    "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
+    "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
+    "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
+    "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
+    "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
+    "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
+    "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
+    "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
+    "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
+    "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
+    "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
+    "d5 9d 73 be 12";
+
+char* signature_3 =
+    "30 4c 02 24 00 00 00 00 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
+    "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
+    "7c 98 25 d9 02 24 00 00 00 00 54 f3 7f 5a e9 36 9c a2 f0 51"
+    "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
+    "ea 57 7e 88 46 12";
+
+
+char* good_dsa_signature_1 =
+    "30 0D 02 01 01 02 08 00 A5 55 5A 01 FF A5 01";
+p256_int good_dsa_signature_1_r = {
+    .a = {0x00000001U, 0x00000000U, 0x00000000U, 0x00000000U,
+          0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}
+};
+p256_int good_dsa_signature_1_s = {
+    .a = {0x01FFA501U, 0x00A5555AU, 0x00000000U, 0x00000000U,
+          0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}
+};
+
+
+char* bad_dsa_signature_1 =
+     "a0 06 02 01 01 02 01 01";
+
+char* bad_dsa_signature_2 =
+     "30 07 02 01 01 02 01 01";
+
+char* bad_dsa_signature_3 =
+     "30 06 82 01 01 02 01 01";
+
+char* bad_dsa_signature_4 =
+     "30 06 02 00 01 02 01 01";
+
+char* bad_dsa_signature_5 =
+     "30 06 02 01 01 82 01 01";
+
+char* bad_dsa_signature_6 =
+     "30 05 02 01 01 02 00";
+
+char* bad_dsa_signature_7 =
+     "30 06 02 01 01 02 00 01";
+
+unsigned char* parsehex(char* str, int* len) {
+    // result can't be longer than input
+    unsigned char* result = malloc(strlen(str));
+
+    unsigned char* p = result;
+    *len = 0;
+
+    while (*str) {
+        int b;
+
+        while (isspace(*str)) str++;
+
+        switch (*str) {
+            case '0': case '1': case '2': case '3': case '4':
+            case '5': case '6': case '7': case '8': case '9':
+                b = (*str - '0') << 4; break;
+            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+                b = (*str - 'a' + 10) << 4; break;
+            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+                b = (*str - 'A' + 10) << 4; break;
+            case '\0':
+                return result;
+            default:
+                return NULL;
+        }
+        str++;
+
+        while (isspace(*str)) str++;
+
+        switch (*str) {
+            case '0': case '1': case '2': case '3': case '4':
+            case '5': case '6': case '7': case '8': case '9':
+                b |= *str - '0'; break;
+            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+                b |= *str - 'a' + 10; break;
+            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+                b |= *str - 'A' + 10; break;
+            default:
+                return NULL;
+        }
+        str++;
+
+        *p++ = b;
+        ++*len;
+    }
+
+    return result;
+}
+
+int main(int arg, char** argv) {
+
+    unsigned char hash_buf[SHA256_DIGEST_SIZE];
+
+    unsigned char* message;
+    int mlen;
+    unsigned char* signature;
+    int slen;
+
+    p256_int hash;
+    p256_int r;
+    p256_int s;
+
+    int success = 1;
+
+#define CHECK_DSA_SIG(sig, good) do {\
+    message = parsehex(sig, &mlen); \
+    int result = dsa_sig_unpack(message, mlen, &r, &s); \
+    printf(#sig ": %s\n", result ? "good" : "bad"); \
+    success = success && !(good ^ result); \
+    free(message); \
+    } while(0)
+#define CHECK_GOOD_DSA_SIG(n) do {\
+    CHECK_DSA_SIG(good_dsa_signature_##n, 1); \
+    int result = !memcmp(P256_DIGITS(&good_dsa_signature_##n##_r), P256_DIGITS(&r), \
+                         P256_NBYTES); \
+    success = success && result; \
+    printf("    R value %s\n", result ? "good" : "bad"); \
+    result = !memcmp(P256_DIGITS(&good_dsa_signature_##n##_s), P256_DIGITS(&s), \
+                    P256_NBYTES); \
+    success = success && result; \
+    printf("    S value %s\n", result ? "good" : "bad"); \
+    } while (0)
+#define CHECK_BAD_DSA_SIG(n) \
+    CHECK_DSA_SIG(bad_dsa_signature_##n, 0)
+
+    CHECK_GOOD_DSA_SIG(1);
+
+    CHECK_BAD_DSA_SIG(1);
+    CHECK_BAD_DSA_SIG(2);
+    CHECK_BAD_DSA_SIG(3);
+    CHECK_BAD_DSA_SIG(4);
+    CHECK_BAD_DSA_SIG(5);
+    CHECK_BAD_DSA_SIG(6);
+    CHECK_BAD_DSA_SIG(7);
+
+
+#define TEST_MESSAGE(n) do {\
+    message = parsehex(message_##n, &mlen); \
+    SHA256_hash(message, mlen, hash_buf); \
+    p256_from_bin(hash_buf, &hash); \
+    signature = parsehex(signature_##n, &slen); \
+    int result = dsa_sig_unpack(signature, slen, &r, &s); \
+    if (result) { result = p256_ecdsa_verify(&key_x, &key_y, &hash, &r, &s); } \
+    printf("message %d: %s\n", n, result ? "verified" : "not verified"); \
+    success = success && result; \
+    free(signature); \
+    } while(0)
+
+    TEST_MESSAGE(1);
+    TEST_MESSAGE(2);
+    TEST_MESSAGE(3);
+
+    printf("\n%s\n\n", success ? "PASS" : "FAIL");
+
+    return !success;
+}
diff --git a/libmincrypt/tools/Android.mk b/libmincrypt/tools/Android.mk
index b61234a..3154914 100644
--- a/libmincrypt/tools/Android.mk
+++ b/libmincrypt/tools/Android.mk
@@ -13,9 +13,10 @@
 # limitations under the License.
 
 LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
 
+include $(CLEAR_VARS)
 LOCAL_MODULE := dumpkey
 LOCAL_SRC_FILES := DumpPublicKey.java
 LOCAL_JAR_MANIFEST := DumpPublicKey.mf
+LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/libmincrypt/tools/DumpPublicKey.java b/libmincrypt/tools/DumpPublicKey.java
index 7189116..3eb1398 100644
--- a/libmincrypt/tools/DumpPublicKey.java
+++ b/libmincrypt/tools/DumpPublicKey.java
@@ -16,6 +16,8 @@
 
 package com.android.dumpkey;
 
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
 import java.io.FileInputStream;
 import java.math.BigInteger;
 import java.security.cert.CertificateFactory;
@@ -23,7 +25,10 @@
 import java.security.KeyStore;
 import java.security.Key;
 import java.security.PublicKey;
+import java.security.Security;
+import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPublicKey;
+import java.security.spec.ECPoint;
 
 /**
  * Command line tool to extract RSA public keys from X.509 certificates
@@ -39,9 +44,8 @@
      *     3: 2048-bit RSA key with e=3 and SHA-256 hash
      *     4: 2048-bit RSA key with e=65537 and SHA-256 hash
      * @throws Exception if the key has the wrong size or public exponent
-
      */
-    static int check(RSAPublicKey key, boolean useSHA256) throws Exception {
+    static int checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
         BigInteger pubexp = key.getPublicExponent();
         BigInteger modulus = key.getModulus();
         int version;
@@ -64,12 +68,42 @@
     }
 
     /**
+     * @param key to perform sanity checks on
+     * @return version number of key.  Supported versions are:
+     *     5: 256-bit EC key with curve NIST P-256
+     * @throws Exception if the key has the wrong size or public exponent
+     */
+    static int checkEC(ECPublicKey key) throws Exception {
+        if (key.getParams().getCurve().getField().getFieldSize() != 256) {
+            throw new Exception("Curve must be NIST P-256");
+        }
+
+        return 5;
+    }
+
+    /**
+     * Perform sanity check on public key.
+     */
+    static int check(PublicKey key, boolean useSHA256) throws Exception {
+        if (key instanceof RSAPublicKey) {
+            return checkRSA((RSAPublicKey) key, useSHA256);
+        } else if (key instanceof ECPublicKey) {
+            if (!useSHA256) {
+                throw new Exception("Must use SHA-256 with EC keys!");
+            }
+            return checkEC((ECPublicKey) key);
+        } else {
+            throw new Exception("Unsupported key class: " + key.getClass().getName());
+        }
+    }
+
+    /**
      * @param key to output
      * @return a String representing this public key.  If the key is a
      *    version 1 key, the string will be a C initializer; this is
      *    not true for newer key versions.
      */
-    static String print(RSAPublicKey key, boolean useSHA256) throws Exception {
+    static String printRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
         int version = check(key, useSHA256);
 
         BigInteger N = key.getModulus();
@@ -128,11 +162,78 @@
         return result.toString();
     }
 
+    /**
+     * @param key to output
+     * @return a String representing this public key.  If the key is a
+     *    version 1 key, the string will be a C initializer; this is
+     *    not true for newer key versions.
+     */
+    static String printEC(ECPublicKey key) throws Exception {
+        int version = checkEC(key);
+
+        StringBuilder result = new StringBuilder();
+
+        result.append("v");
+        result.append(Integer.toString(version));
+        result.append(" ");
+
+        BigInteger X = key.getW().getAffineX();
+        BigInteger Y = key.getW().getAffineY();
+        int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8;    // # of 32 bit integers in X coordinate
+
+        result.append("{");
+        result.append(nbytes);
+
+        BigInteger B = BigInteger.valueOf(0x100L);  // 2^8
+
+        // Write out Y coordinate as array of characters.
+        result.append(",{");
+        for (int i = 0; i < nbytes; ++i) {
+            long n = X.mod(B).longValue();
+            result.append(n);
+
+            if (i != nbytes - 1) {
+                result.append(",");
+            }
+
+            X = X.divide(B);
+        }
+        result.append("}");
+
+        // Write out Y coordinate as array of characters.
+        result.append(",{");
+        for (int i = 0; i < nbytes; ++i) {
+            long n = Y.mod(B).longValue();
+            result.append(n);
+
+            if (i != nbytes - 1) {
+                result.append(",");
+            }
+
+            Y = Y.divide(B);
+        }
+        result.append("}");
+
+        result.append("}");
+        return result.toString();
+    }
+
+    static String print(PublicKey key, boolean useSHA256) throws Exception {
+        if (key instanceof RSAPublicKey) {
+            return printRSA((RSAPublicKey) key, useSHA256);
+        } else if (key instanceof ECPublicKey) {
+            return printEC((ECPublicKey) key);
+        } else {
+            throw new Exception("Unsupported key class: " + key.getClass().getName());
+        }
+    }
+
     public static void main(String[] args) {
         if (args.length < 1) {
             System.err.println("Usage: DumpPublicKey certfile ... > source.c");
             System.exit(1);
         }
+        Security.addProvider(new BouncyCastleProvider());
         try {
             for (int i = 0; i < args.length; i++) {
                 FileInputStream input = new FileInputStream(args[i]);
@@ -147,7 +248,7 @@
                     // anyway.  Continue to do so for backwards
                     // compatibility.
                   useSHA256 = false;
-                } else if ("SHA256withRSA".equals(sigAlg)) {
+                } else if ("SHA256withRSA".equals(sigAlg) || "SHA256withECDSA".equals(sigAlg)) {
                   useSHA256 = true;
                 } else {
                   System.err.println(args[i] + ": unsupported signature algorithm \"" +
@@ -155,7 +256,7 @@
                   System.exit(1);
                 }
 
-                RSAPublicKey key = (RSAPublicKey) (cert.getPublicKey());
+                PublicKey key = cert.getPublicKey();
                 check(key, useSHA256);
                 System.out.print(print(key, useSHA256));
                 System.out.println(i < args.length - 1 ? "," : "");
diff --git a/libsparse/backed_block.c b/libsparse/backed_block.c
index dfb217b..3e72b57 100644
--- a/libsparse/backed_block.c
+++ b/libsparse/backed_block.c
@@ -370,7 +370,7 @@
 	}
 
 	new_bb = malloc(sizeof(struct backed_block));
-	if (bb == NULL) {
+	if (new_bb == NULL) {
 		return -ENOMEM;
 	}
 
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index 5014e4a..a28b0a5 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; })
 
@@ -731,10 +722,12 @@
 	}
 	pos = lseek64(fd, offset, SEEK_SET);
 	if (pos < 0) {
+                free(data);
 		return -errno;
 	}
 	ret = read_all(fd, data, len);
 	if (ret < 0) {
+                free(data);
 		return ret;
 	}
 	ptr = data;
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 a0a9813..400c09e 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
@@ -216,6 +219,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
@@ -253,6 +260,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.
@@ -347,7 +357,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
@@ -417,10 +426,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