Merge "fastboot: Make tags_offset a command line option."
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 6fc55df..0c46a0c 100755
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -140,6 +140,8 @@
 #define VENDOR_ID_PMC           0x04DA
 // Positivo's USB Vendor ID
 #define VENDOR_ID_POSITIVO      0x1662
+// Prestigio's USB Vendor ID
+#define VENDOR_ID_PRESTIGIO     0x29e4
 // Qisda's USB Vendor ID
 #define VENDOR_ID_QISDA         0x1D45
 // Qualcomm's USB Vendor ID
@@ -237,6 +239,7 @@
     VENDOR_ID_PHILIPS,
     VENDOR_ID_PMC,
     VENDOR_ID_POSITIVO,
+    VENDOR_ID_PRESTIGIO,
     VENDOR_ID_QISDA,
     VENDOR_ID_QUALCOMM,
     VENDOR_ID_QUANTA,
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index 5a2bc3c..3e3ab5a 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -1,20 +1,17 @@
-
-//#include <cutils/misc.h>
-
-#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sched.h>
-#include <errno.h>
-
-#include <signal.h>
 #include <sys/ptrace.h>
-#include <sys/wait.h>
 #include <sys/socket.h>
+#include <sys/wait.h>
+#include <unistd.h>
 
-#include <pthread.h>
-
+#include <cutils/log.h>
 #include <cutils/sockets.h>
 
 extern const char* __progname;
@@ -23,8 +20,8 @@
 void crashnostack(void);
 static int do_action(const char* arg);
 
-static void maybeabort() {
-    if(time(0) != 42) {
+static void maybe_abort() {
+    if (time(0) != 42) {
         abort();
     }
 }
@@ -119,35 +116,54 @@
 
     if (!strncmp(arg, "thread-", strlen("thread-"))) {
         return do_action_on_thread(arg + strlen("thread-"));
-    } else if (!strcmp(arg,"smash-stack")) {
+    } else if (!strcmp(arg, "smash-stack")) {
         return smash_stack(42);
-    } else if (!strcmp(arg,"stack-overflow")) {
+    } else if (!strcmp(arg, "stack-overflow")) {
         overflow_stack(NULL);
-    } else if (!strcmp(arg,"nostack")) {
+    } else if (!strcmp(arg, "nostack")) {
         crashnostack();
-    } else if (!strcmp(arg,"ctest")) {
+    } else if (!strcmp(arg, "ctest")) {
         return ctest();
-    } else if (!strcmp(arg,"exit")) {
+    } else if (!strcmp(arg, "exit")) {
         exit(1);
-    } else if (!strcmp(arg,"crash")) {
+    } else if (!strcmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
         return crash(42);
-    } else if (!strcmp(arg,"abort")) {
-        maybeabort();
+    } else if (!strcmp(arg, "abort")) {
+        maybe_abort();
+    } else if (!strcmp(arg, "assert")) {
+        __assert("some_file.c", 123, "false");
+    } else if (!strcmp(arg, "assert2")) {
+      __assert2("some_file.c", 123, "some_function", "false");
+    } else if (!strcmp(arg, "LOG_ALWAYS_FATAL")) {
+        LOG_ALWAYS_FATAL("hello %s", "world");
+    } else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
+        LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
+    } else if (!strcmp(arg, "SIGPIPE")) {
+        int pipe_fds[2];
+        pipe(pipe_fds);
+        close(pipe_fds[0]);
+        write(pipe_fds[1], "oops", 4);
+        return EXIT_SUCCESS;
     } else if (!strcmp(arg, "heap-usage")) {
         abuse_heap();
     }
 
     fprintf(stderr, "%s OP\n", __progname);
     fprintf(stderr, "where OP is:\n");
-    fprintf(stderr, "  smash-stack     overwrite a stack-guard canary\n");
-    fprintf(stderr, "  stack-overflow  recurse until the stack overflows\n");
-    fprintf(stderr, "  heap-corruption cause a libc abort by corrupting the heap\n");
-    fprintf(stderr, "  heap-usage      cause a libc abort by abusing a heap function\n");
-    fprintf(stderr, "  nostack         crash with a NULL stack pointer\n");
-    fprintf(stderr, "  ctest           (obsoleted by thread-crash?)\n");
-    fprintf(stderr, "  exit            call exit(1)\n");
-    fprintf(stderr, "  crash           cause a SIGSEGV\n");
-    fprintf(stderr, "  abort           call abort()\n");
+    fprintf(stderr, "  smash-stack           overwrite a stack-guard canary\n");
+    fprintf(stderr, "  stack-overflow        recurse until the stack overflows\n");
+    fprintf(stderr, "  heap-corruption       cause a libc abort by corrupting the heap\n");
+    fprintf(stderr, "  heap-usage            cause a libc abort by abusing a heap function\n");
+    fprintf(stderr, "  nostack               crash with a NULL stack pointer\n");
+    fprintf(stderr, "  ctest                 (obsoleted by thread-crash?)\n");
+    fprintf(stderr, "  exit                  call exit(1)\n");
+    fprintf(stderr, "  abort                 call abort()\n");
+    fprintf(stderr, "  assert                call assert() without a function\n");
+    fprintf(stderr, "  assert2               call assert() with a function\n");
+    fprintf(stderr, "  LOG_ALWAYS_FATAL      call LOG_ALWAYS_FATAL\n");
+    fprintf(stderr, "  LOG_ALWAYS_FATAL_IF   call LOG_ALWAYS_FATAL\n");
+    fprintf(stderr, "  SIGPIPE               cause a SIGPIPE\n");
+    fprintf(stderr, "  SIGSEGV               cause a SIGSEGV (synonym: crash)\n");
     fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
     fprintf(stderr, "on the process' main thread.\n");
     return EXIT_SUCCESS;
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index a2b164e..76bd7a3 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -51,6 +51,7 @@
   pid_t pid, tid;
   uid_t uid, gid;
   uintptr_t abort_msg_address;
+  int32_t original_si_code;
 };
 
 static int write_string(const char* file, const char* string) {
@@ -218,6 +219,7 @@
   out_request->uid = cr.uid;
   out_request->gid = cr.gid;
   out_request->abort_msg_address = msg.abort_msg_address;
+  out_request->original_si_code = msg.original_si_code;
 
   if (msg.action == DEBUGGER_ACTION_CRASH) {
     // Ensure that the tid reported by the crashing process is valid.
@@ -302,9 +304,10 @@
             case SIGSTOP:
               if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
                 XLOG("stopped -- dumping to tombstone\n");
-                tombstone_path = engrave_tombstone(
-                    request.pid, request.tid, signal, request.abort_msg_address, true, true,
-                    &detach_failed, &total_sleep_time_usec);
+                tombstone_path = engrave_tombstone(request.pid, request.tid,
+                                                   signal, request.original_si_code,
+                                                   request.abort_msg_address, true, true,
+                                                   &detach_failed, &total_sleep_time_usec);
               } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
                 XLOG("stopped -- dumping to fd\n");
                 dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed,
@@ -336,9 +339,10 @@
               kill(request.pid, SIGSTOP);
               // don't dump sibling threads when attaching to GDB because it
               // makes the process less reliable, apparently...
-              tombstone_path = engrave_tombstone(
-                  request.pid, request.tid, signal, request.abort_msg_address, !attach_gdb,
-                  false, &detach_failed, &total_sleep_time_usec);
+              tombstone_path = engrave_tombstone(request.pid, request.tid,
+                                                 signal, request.original_si_code,
+                                                 request.abort_msg_address, !attach_gdb, false,
+                                                 &detach_failed, &total_sleep_time_usec);
               break;
 
             default:
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 6a1b963..f95e572 100755
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -55,7 +55,7 @@
 // Must match the path defined in NativeCrashListener.java
 #define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
 
-static bool signal_has_address(int sig) {
+static bool signal_has_si_addr(int sig) {
   switch (sig) {
     case SIGILL:
     case SIGFPE:
@@ -75,7 +75,7 @@
     case SIGFPE: return "SIGFPE";
     case SIGSEGV: return "SIGSEGV";
     case SIGPIPE: return "SIGPIPE";
-#ifdef SIGSTKFLT
+#if defined(SIGSTKFLT)
     case SIGSTKFLT: return "SIGSTKFLT";
 #endif
     case SIGSTOP: return "SIGSTOP";
@@ -97,13 +97,17 @@
         case ILL_COPROC: return "ILL_COPROC";
         case ILL_BADSTK: return "ILL_BADSTK";
       }
+      static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
       break;
     case SIGBUS:
       switch (code) {
         case BUS_ADRALN: return "BUS_ADRALN";
         case BUS_ADRERR: return "BUS_ADRERR";
         case BUS_OBJERR: return "BUS_OBJERR";
+        case BUS_MCEERR_AR: return "BUS_MCEERR_AR";
+        case BUS_MCEERR_AO: return "BUS_MCEERR_AO";
       }
+      static_assert(NSIGBUS == BUS_MCEERR_AO, "missing BUS_* si_code");
       break;
     case SIGFPE:
       switch (code) {
@@ -116,36 +120,36 @@
         case FPE_FLTINV: return "FPE_FLTINV";
         case FPE_FLTSUB: return "FPE_FLTSUB";
       }
+      static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
       break;
     case SIGSEGV:
       switch (code) {
         case SEGV_MAPERR: return "SEGV_MAPERR";
         case SEGV_ACCERR: return "SEGV_ACCERR";
       }
+      static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
       break;
     case SIGTRAP:
       switch (code) {
         case TRAP_BRKPT: return "TRAP_BRKPT";
         case TRAP_TRACE: return "TRAP_TRACE";
+        case TRAP_BRANCH: return "TRAP_BRANCH";
+        case TRAP_HWBKPT: return "TRAP_HWBKPT";
       }
+      static_assert(NSIGTRAP == TRAP_HWBKPT, "missing TRAP_* si_code");
       break;
   }
   // Then the other codes...
   switch (code) {
     case SI_USER: return "SI_USER";
-#if defined(SI_KERNEL)
     case SI_KERNEL: return "SI_KERNEL";
-#endif
     case SI_QUEUE: return "SI_QUEUE";
     case SI_TIMER: return "SI_TIMER";
     case SI_MESGQ: return "SI_MESGQ";
     case SI_ASYNCIO: return "SI_ASYNCIO";
-#if defined(SI_SIGIO)
     case SI_SIGIO: return "SI_SIGIO";
-#endif
-#if defined(SI_TKILL)
     case SI_TKILL: return "SI_TKILL";
-#endif
+    case SI_DETHREAD: return "SI_DETHREAD";
   }
   // Then give up...
   return "?";
@@ -167,20 +171,26 @@
   _LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
 }
 
-static void dump_fault_addr(log_t* log, pid_t tid, int sig) {
+static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) {
   siginfo_t si;
-
   memset(&si, 0, sizeof(si));
-  if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
+  if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
     _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
-  } else if (signal_has_address(sig)) {
-    _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %" PRIPTR "\n",
-         sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code),
-         reinterpret_cast<uintptr_t>(si.si_addr));
-  } else {
-    _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr --------\n",
-         sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
+    return;
   }
+
+  // bionic has to re-raise some signals, which overwrites the si_code with SI_TKILL.
+  si.si_code = si_code;
+
+  char addr_desc[32]; // ", fault addr 0x1234"
+  if (signal_has_si_addr(signal)) {
+    snprintf(addr_desc, sizeof(addr_desc), "%p", si.si_addr);
+  } else {
+    snprintf(addr_desc, sizeof(addr_desc), "--------");
+  }
+
+  _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %s\n",
+       signal, get_signame(signal), si.si_code, get_sigcode(signal, si.si_code), addr_desc);
 }
 
 static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) {
@@ -345,7 +355,7 @@
     _LOG(log, scope_flags, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
     return;
   }
-  if (!signal_has_address(si.si_signo)) {
+  if (!signal_has_si_addr(si.si_signo)) {
     return;
   }
 
@@ -584,8 +594,9 @@
 }
 
 // Dumps all information about the specified pid to the tombstone.
-static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
-                       bool dump_sibling_threads, int* total_sleep_time_usec) {
+static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code,
+                       uintptr_t abort_msg_address, bool dump_sibling_threads,
+                       int* total_sleep_time_usec) {
   // don't copy log messages to tombstone unless this is a dev device
   char value[PROPERTY_VALUE_MAX];
   property_get("ro.debuggable", value, "0");
@@ -607,7 +618,7 @@
   dump_revision_info(log);
   dump_thread_info(log, pid, tid, SCOPE_AT_FAULT);
   if (signal) {
-    dump_fault_addr(log, tid, signal);
+    dump_signal_info(log, tid, signal, si_code);
   }
 
   UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
@@ -721,9 +732,9 @@
   return amfd;
 }
 
-char* engrave_tombstone(
-    pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address, bool dump_sibling_threads,
-    bool quiet, bool* detach_failed, int* total_sleep_time_usec) {
+char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
+                        uintptr_t abort_msg_address, bool dump_sibling_threads, bool quiet,
+                        bool* detach_failed, int* total_sleep_time_usec) {
   if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
       LOG("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
   }
@@ -748,8 +759,8 @@
   log.tfd = fd;
   log.amfd = activity_manager_connect();
   log.quiet = quiet;
-  *detach_failed = dump_crash(
-      &log, pid, tid, signal, abort_msg_address, dump_sibling_threads, total_sleep_time_usec);
+  *detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address,
+                              dump_sibling_threads, total_sleep_time_usec);
 
   close(log.amfd);
   close(fd);
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index e9878bf..3574e84 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -23,7 +23,9 @@
 
 /* Creates a tombstone file and writes the crash dump to it.
  * Returns the path of the tombstone, which must be freed using free(). */
-char* engrave_tombstone(pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
-        bool dump_sibling_threads, bool quiet, bool* detach_failed, int* total_sleep_time_usec);
+char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
+                        uintptr_t abort_msg_address,
+                        bool dump_sibling_threads, bool quiet,
+                        bool* detach_failed, int* total_sleep_time_usec);
 
 #endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index 9b20914..d4c252f 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -24,6 +24,7 @@
 #include <sys/wait.h>
 
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 #include <log/logd.h>
 
 const int sleep_time_usec = 50000;         // 0.05 seconds
@@ -64,7 +65,7 @@
   }
 
   if (want_log_write) {
-    __android_log_write(ANDROID_LOG_INFO, "DEBUG", buf);
+    __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, "DEBUG", buf);
     if (want_amfd_write) {
       int written = write_to_am(log->amfd, buf, len);
       if (written <= 0) {
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 6145771..45bbfdc 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -337,7 +337,7 @@
 /* Add an entry to the fstab, and return 0 on success or -1 on error */
 int fs_mgr_add_entry(struct fstab *fstab,
                      const char *mount_point, const char *fs_type,
-                     const char *blk_device, long long length)
+                     const char *blk_device)
 {
     struct fstab_rec *new_fstab_recs;
     int n = fstab->num_entries;
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 4bde4a1..e5a00d5 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -80,10 +80,10 @@
     int a_flag=0;
     int u_flag=0;
     int n_flag=0;
-    char *n_name;
-    char *n_blk_dev;
-    char *fstab_file;
-    struct fstab *fstab;
+    char *n_name=NULL;
+    char *n_blk_dev=NULL;
+    char *fstab_file=NULL;
+    struct fstab *fstab=NULL;
 
     klog_init();
     klog_set_level(6);
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 0f90c32..835cf64 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -57,7 +57,7 @@
                           char *real_blk_device, int size);
 int fs_mgr_add_entry(struct fstab *fstab,
                      const char *mount_point, const char *fs_type,
-                     const char *blk_device, long long length);
+                     const char *blk_device);
 struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path);
 int fs_mgr_is_voldmanaged(struct fstab_rec *fstab);
 int fs_mgr_is_nonremovable(struct fstab_rec *fstab);
diff --git a/healthd/healthd_board_default.cpp b/healthd/healthd_board_default.cpp
index b2bb516..ed4ddb4 100644
--- a/healthd/healthd_board_default.cpp
+++ b/healthd/healthd_board_default.cpp
@@ -16,13 +16,13 @@
 
 #include <healthd.h>
 
-void healthd_board_init(struct healthd_config *config)
+void healthd_board_init(struct healthd_config*)
 {
     // use defaults
 }
 
 
-int healthd_board_battery_update(struct android::BatteryProperties *props)
+int healthd_board_battery_update(struct android::BatteryProperties*)
 {
     // return 0 to log periodic polled battery status to kernel log
     return 0;
diff --git a/include/android/log.h b/include/android/log.h
index 0ea4c29..f5b1900 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -110,11 +110,11 @@
                          const char *fmt, va_list ap);
 
 /*
- * Log an assertion failure and SIGTRAP the process to have a chance
- * to inspect it, if a debugger is attached. This uses the FATAL priority.
+ * Log an assertion failure and abort the process to have a chance
+ * to inspect it if a debugger is attached. This uses the FATAL priority.
  */
 void __android_log_assert(const char *cond, const char *tag,
-			  const char *fmt, ...)    
+                          const char *fmt, ...)
 #if defined(__GNUC__)
     __attribute__ ((noreturn))
     __attribute__ ((format(printf, 3, 4)))
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index af80e2c..ae6bfc4 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -42,6 +42,7 @@
     debugger_action_t action;
     pid_t tid;
     uintptr_t abort_msg_address;
+    int32_t original_si_code;
 } debugger_msg_t;
 
 /* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
diff --git a/include/log/log.h b/include/log/log.h
index d469f40..5b76c1a 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -550,6 +550,7 @@
     LOG_ID_RADIO = 1,
     LOG_ID_EVENTS = 2,
     LOG_ID_SYSTEM = 3,
+    LOG_ID_CRASH = 4,
 
     LOG_ID_MAX
 } log_id_t;
diff --git a/include/log/logger.h b/include/log/logger.h
index 3c6ea30..ed39c4f 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -142,9 +142,7 @@
 
 int android_logger_clear(struct logger *logger);
 long android_logger_get_log_size(struct logger *logger);
-#ifdef USERDEBUG_BUILD
 int android_logger_set_log_size(struct logger *logger, unsigned long size);
-#endif
 long android_logger_get_log_readable_size(struct logger *logger);
 int android_logger_get_log_version(struct logger *logger);
 
@@ -152,12 +150,10 @@
 
 ssize_t android_logger_get_statistics(struct logger_list *logger_list,
                                       char *buf, size_t len);
-#ifdef USERDEBUG_BUILD
 ssize_t android_logger_get_prune_list(struct logger_list *logger_list,
                                       char *buf, size_t len);
 int android_logger_set_prune_list(struct logger_list *logger_list,
                                   char *buf, size_t len);
-#endif
 
 struct logger_list *android_logger_list_alloc(int mode,
                                               unsigned int tail,
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 9c26baf..d662107 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -251,6 +251,7 @@
 
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/vendor/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
diff --git a/include/system/audio.h b/include/system/audio.h
index aa7ac02..f36befb 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -471,12 +471,16 @@
 
 static inline bool audio_is_bluetooth_sco_device(audio_devices_t device)
 {
-    device &= ~AUDIO_DEVICE_BIT_IN;
-    if ((popcount(device) == 1) && (device & (AUDIO_DEVICE_OUT_ALL_SCO |
-                   AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)))
-        return true;
-    else
-        return false;
+    if ((device & AUDIO_DEVICE_BIT_IN) == 0) {
+        if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL_SCO) == 0))
+            return true;
+    } else {
+        device &= ~AUDIO_DEVICE_BIT_IN;
+        if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) == 0))
+            return true;
+    }
+
+    return false;
 }
 
 static inline bool audio_is_usb_device(audio_devices_t device)
diff --git a/include/sysutils/FrameworkListener.h b/include/sysutils/FrameworkListener.h
index f1a4b43..18049cd 100644
--- a/include/sysutils/FrameworkListener.h
+++ b/include/sysutils/FrameworkListener.h
@@ -36,6 +36,7 @@
 public:
     FrameworkListener(const char *socketName);
     FrameworkListener(const char *socketName, bool withSeq);
+    FrameworkListener(int sock);
     virtual ~FrameworkListener() {}
 
 protected:
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
index c8c87c3..5b98de2 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -22,8 +22,11 @@
 
 extern "C" {
 
+// Definitions exist in C++11
+#if defined __cplusplus && __cplusplus < 201103L
 typedef uint32_t char32_t;
 typedef uint16_t char16_t;
+#endif
 
 // Standard string functions on char16_t strings.
 int strcmp16(const char16_t *, const char16_t *);
diff --git a/init/devices.c b/init/devices.c
index 80c6d75..5d7ad3b 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -699,7 +699,7 @@
 
 static void handle_device_event(struct uevent *uevent)
 {
-    if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change"))
+    if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
         fixup_sys_perms(uevent->path);
 
     if (!strncmp(uevent->subsystem, "block", 5)) {
diff --git a/init/property_service.c b/init/property_service.c
index fe7cbb5..7e8d79a 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -269,6 +269,7 @@
         return;
     }
     write(fd, value, strlen(value));
+    fsync(fd);
     close(fd);
 
     snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
@@ -556,7 +557,8 @@
                     || (sb.st_gid != 0)
                     || (sb.st_nlink != 1)) {
                 ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%d mode=%o)\n",
-                      entry->d_name, sb.st_uid, sb.st_gid, sb.st_nlink, sb.st_mode);
+                      entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid,
+                      sb.st_nlink, sb.st_mode);
                 close(fd);
                 continue;
             }
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index c743077..a7305da 100755
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -46,10 +46,6 @@
 	libcutils \
 	libgccdemangle \
 
-# To enable using libunwind on each arch, add it to this list.
-libunwind_architectures := arm arm64 mips x86 x86_64
-
-ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),$(libunwind_architectures)))
 libbacktrace_src_files += \
 	UnwindCurrent.cpp \
 	UnwindMap.cpp \
@@ -68,24 +64,6 @@
 libbacktrace_static_libraries_host := \
 	libcutils \
 
-else
-libbacktrace_src_files += \
-	Corkscrew.cpp \
-
-libbacktrace_c_includes := \
-	system/core/libcorkscrew \
-
-libbacktrace_shared_libraries := \
-	libcorkscrew \
-
-libbacktrace_shared_libraries_target += \
-	libdl \
-
-libbacktrace_ldlibs_host := \
-	-ldl \
-
-endif
-
 module := libbacktrace
 module_tag := optional
 build_type := target
@@ -118,17 +96,8 @@
 	-fno-builtin \
 	-O0 \
 	-g \
-	-DGTEST_HAS_STD_STRING \
-
-ifneq ($(TARGET_ARCH),arm64)
-backtrace_test_cflags += -fstack-protector-all
-else
-  $(info TODO: $(LOCAL_PATH)/Android.mk -fstack-protector not yet available for the AArch64 toolchain)
-  common_cflags += -fno-stack-protector
-endif # arm64
 
 backtrace_test_cflags_target := \
-	-DGTEST_OS_LINUX_ANDROID \
 	-DENABLE_PSS_TESTS \
 
 backtrace_test_src_files := \
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 6eb290d..0056f4b 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -108,11 +108,11 @@
 
 #if defined(__APPLE__)
   // cmd is guaranteed to always be big enough to hold this string.
-  sprintf(cmd, "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
+  snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
   FILE* fp = popen(cmd, "r");
 #else
   // path is guaranteed to always be big enough to hold this string.
-  sprintf(path, "/proc/%d/maps", pid_);
+  snprintf(path, sizeof(path), "/proc/%d/maps", pid_);
   FILE* fp = fopen(path, "r");
 #endif
   if (fp == NULL) {
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp
index 4cda19e..e0bab24 100644
--- a/libbacktrace/BacktraceThread.cpp
+++ b/libbacktrace/BacktraceThread.cpp
@@ -136,7 +136,7 @@
 bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
   entry->state = STATE_WAITING;
 
-  if (tgkill(Pid(), Tid(), SIGURG) != 0) {
+  if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
     BACK_LOGW("tgkill failed %s", strerror(errno));
     return false;
   }
@@ -196,9 +196,9 @@
     act.sa_sigaction = SignalHandler;
     act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
     sigemptyset(&act.sa_mask);
-    if (sigaction(SIGURG, &act, &oldact) == 0) {
+    if (sigaction(THREAD_SIGNAL, &act, &oldact) == 0) {
       retval = TriggerUnwindOnThread(entry);
-      sigaction(SIGURG, &oldact, NULL);
+      sigaction(THREAD_SIGNAL, &oldact, NULL);
     } else {
       BACK_LOGW("sigaction failed %s", strerror(errno));
     }
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h
index 3412d58..9310a44 100644
--- a/libbacktrace/BacktraceThread.h
+++ b/libbacktrace/BacktraceThread.h
@@ -18,6 +18,7 @@
 #define _LIBBACKTRACE_BACKTRACE_THREAD_H
 
 #include <inttypes.h>
+#include <signal.h>
 #include <sys/types.h>
 
 #include "BacktraceImpl.h"
@@ -29,6 +30,14 @@
   STATE_CANCEL,
 };
 
+// The signal used to cause a thread to dump the stack.
+#if defined(__GLIBC__)
+// GLIBC reserves __SIGRTMIN signals, so use SIGRTMIN to avoid errors.
+#define THREAD_SIGNAL SIGRTMIN
+#else
+#define THREAD_SIGNAL (__SIGRTMIN+1)
+#endif
+
 class BacktraceThreadInterface;
 
 struct ThreadEntry {
diff --git a/libbacktrace/Corkscrew.cpp b/libbacktrace/Corkscrew.cpp
deleted file mode 100644
index 773b0a2..0000000
--- a/libbacktrace/Corkscrew.cpp
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <backtrace/Backtrace.h>
-
-#include <string.h>
-
-#include <backtrace-arch.h>
-#include <corkscrew/backtrace.h>
-
-#ifndef __USE_GNU
-#define __USE_GNU
-#endif
-#include <dlfcn.h>
-
-#include "BacktraceLog.h"
-#include "Corkscrew.h"
-
-//-------------------------------------------------------------------------
-// CorkscrewMap functions.
-//-------------------------------------------------------------------------
-CorkscrewMap::CorkscrewMap(pid_t pid) : BacktraceMap(pid), map_info_(NULL) {
-}
-
-CorkscrewMap::~CorkscrewMap() {
-  if (map_info_) {
-    free_map_info_list(map_info_);
-    map_info_ = NULL;
-  }
-}
-
-bool CorkscrewMap::Build() {
-  map_info_ = load_map_info_list(pid_);
-
-  // Use the information in map_info_ to construct the BacktraceMap data
-  // rather than reparsing /proc/self/maps.
-  map_info_t* cur_map = map_info_;
-  while (cur_map) {
-    backtrace_map_t map;
-    map.start = cur_map->start;
-    map.end = cur_map->end;
-    map.flags = 0;
-    if (cur_map->is_readable) {
-      map.flags |= PROT_READ;
-    }
-    if (cur_map->is_writable) {
-      map.flags |= PROT_WRITE;
-    }
-    if (cur_map->is_executable) {
-      map.flags |= PROT_EXEC;
-    }
-    map.name = cur_map->name;
-
-    // The maps are in descending order, but we want them in ascending order.
-    maps_.push_front(map);
-
-    cur_map = cur_map->next;
-  }
-  return map_info_ != NULL;
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewCommon functions.
-//-------------------------------------------------------------------------
-bool CorkscrewCommon::GenerateFrameData(
-    backtrace_frame_t* cork_frames, ssize_t num_frames) {
-  if (num_frames < 0) {
-    BACK_LOGW("libcorkscrew unwind failed.");
-    return false;
-  }
-
-  std::vector<backtrace_frame_data_t>* frames = GetFrames();
-  frames->resize(num_frames);
-  size_t i = 0;
-  for (std::vector<backtrace_frame_data_t>::iterator it = frames->begin();
-       it != frames->end(); ++it, ++i) {
-    it->num = i;
-    it->pc = cork_frames[i].absolute_pc;
-    it->sp = cork_frames[i].stack_top;
-    it->stack_size = cork_frames[i].stack_size;
-    it->func_offset = 0;
-
-    it->map = FindMap(it->pc);
-    it->func_name = GetFunctionName(it->pc, &it->func_offset);
-  }
-  return true;
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewCurrent functions.
-//-------------------------------------------------------------------------
-CorkscrewCurrent::CorkscrewCurrent() {
-}
-
-CorkscrewCurrent::~CorkscrewCurrent() {
-}
-
-bool CorkscrewCurrent::Unwind(size_t num_ignore_frames) {
-  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
-  ssize_t num_frames = unwind_backtrace(frames, num_ignore_frames, MAX_BACKTRACE_FRAMES);
-
-  return GenerateFrameData(frames, num_frames);
-}
-
-std::string CorkscrewCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
-  *offset = 0;
-
-  Dl_info info;
-  const backtrace_map_t* map = FindMap(pc);
-  if (map) {
-    if (dladdr((const void*)pc, &info)) {
-      if (info.dli_sname) {
-        *offset = pc - map->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase;
-        return info.dli_sname;
-      }
-    } else {
-      // dladdr(3) didn't find a symbol; maybe it's static? Look in the ELF file...
-      symbol_table_t* symbol_table = load_symbol_table(map->name.c_str());
-      if (symbol_table) {
-        // First check if we can find the symbol using a relative pc.
-        std::string name;
-        const symbol_t* elf_symbol = find_symbol(symbol_table, pc - map->start);
-        if (elf_symbol) {
-          name = elf_symbol->name;
-          *offset = pc - map->start - elf_symbol->start;
-        } else if ((elf_symbol = find_symbol(symbol_table, pc)) != NULL) {
-          // Found the symbol using the absolute pc.
-          name = elf_symbol->name;
-          *offset = pc - elf_symbol->start;
-        }
-        free_symbol_table(symbol_table);
-        return name;
-      }
-    }
-  }
-  return "";
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewThread functions.
-//-------------------------------------------------------------------------
-CorkscrewThread::CorkscrewThread() {
-}
-
-CorkscrewThread::~CorkscrewThread() {
-}
-
-void CorkscrewThread::ThreadUnwind(
-    siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
-  backtrace_frame_t cork_frames[MAX_BACKTRACE_FRAMES];
-  CorkscrewMap* map = static_cast<CorkscrewMap*>(GetMap());
-  ssize_t num_frames = unwind_backtrace_signal_arch(
-      siginfo, sigcontext, map->GetMapInfo(), cork_frames,
-      num_ignore_frames, MAX_BACKTRACE_FRAMES);
-  if (num_frames > 0) {
-    std::vector<backtrace_frame_data_t>* frames = GetFrames();
-    frames->resize(num_frames);
-    size_t i = 0;
-    for (std::vector<backtrace_frame_data_t>::iterator it = frames->begin();
-         it != frames->end(); ++it, ++i) {
-      it->num = i;
-      it->pc = cork_frames[i].absolute_pc;
-      it->sp = cork_frames[i].stack_top;
-      it->stack_size = cork_frames[i].stack_size;
-      it->map = NULL;
-      it->func_offset = 0;
-    }
-  }
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewPtrace functions.
-//-------------------------------------------------------------------------
-CorkscrewPtrace::CorkscrewPtrace() : ptrace_context_(NULL) {
-}
-
-CorkscrewPtrace::~CorkscrewPtrace() {
-  if (ptrace_context_) {
-    free_ptrace_context(ptrace_context_);
-    ptrace_context_ = NULL;
-  }
-}
-
-bool CorkscrewPtrace::Unwind(size_t num_ignore_frames) {
-  ptrace_context_ = load_ptrace_context(Tid());
-
-  backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
-  ssize_t num_frames = unwind_backtrace_ptrace(
-      Tid(), ptrace_context_, frames, num_ignore_frames, MAX_BACKTRACE_FRAMES);
-
-  return GenerateFrameData(frames, num_frames);
-}
-
-std::string CorkscrewPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
-  // Get information about a different process.
-  const map_info_t* map_info;
-  const symbol_t* symbol;
-  find_symbol_ptrace(ptrace_context_, pc, &map_info, &symbol);
-  char* symbol_name = NULL;
-  if (symbol) {
-    if (map_info) {
-      *offset = pc - map_info->start - symbol->start;
-    }
-    symbol_name = symbol->name;
-    return symbol_name;
-  }
-
-  return "";
-}
-
-//-------------------------------------------------------------------------
-// C++ object creation functions.
-//-------------------------------------------------------------------------
-Backtrace* CreateCurrentObj(BacktraceMap* map) {
-  return new BacktraceCurrent(new CorkscrewCurrent(), map);
-}
-
-Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) {
-  return new BacktracePtrace(new CorkscrewPtrace(), pid, tid, map);
-}
-
-Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) {
-  CorkscrewThread* thread_obj = new CorkscrewThread();
-  return new BacktraceThread(thread_obj, thread_obj, tid, map);
-}
-
-//-------------------------------------------------------------------------
-// BacktraceMap create function.
-//-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::Create(pid_t pid) {
-  BacktraceMap* map = new CorkscrewMap(pid);
-  if (!map->Build()) {
-    delete map;
-    return NULL;
-  }
-  return map;
-}
diff --git a/libbacktrace/Corkscrew.h b/libbacktrace/Corkscrew.h
deleted file mode 100644
index 1633398..0000000
--- a/libbacktrace/Corkscrew.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBBACKTRACE_CORKSCREW_H
-#define _LIBBACKTRACE_CORKSCREW_H
-
-#include <inttypes.h>
-
-#include <string>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include <corkscrew/backtrace.h>
-
-#include "BacktraceImpl.h"
-#include "BacktraceThread.h"
-
-class CorkscrewMap : public BacktraceMap {
-public:
-  CorkscrewMap(pid_t pid);
-  virtual ~CorkscrewMap();
-
-  virtual bool Build();
-
-  map_info_t* GetMapInfo() { return map_info_; }
-
-private:
-  map_info_t* map_info_;
-};
-
-class CorkscrewCommon : public BacktraceImpl {
-public:
-  bool GenerateFrameData(backtrace_frame_t* cork_frames, ssize_t num_frames);
-};
-
-class CorkscrewCurrent : public CorkscrewCommon {
-public:
-  CorkscrewCurrent();
-  virtual ~CorkscrewCurrent();
-
-  virtual bool Unwind(size_t num_ignore_threads);
-
-  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
-};
-
-class CorkscrewThread : public CorkscrewCurrent, public BacktraceThreadInterface {
-public:
-  CorkscrewThread();
-  virtual ~CorkscrewThread();
-
-  virtual void ThreadUnwind(
-      siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
-};
-
-class CorkscrewPtrace : public CorkscrewCommon {
-public:
-  CorkscrewPtrace();
-  virtual ~CorkscrewPtrace();
-
-  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
-
-  virtual bool Unwind(size_t num_ignore_threads);
-
-private:
-  ptrace_context_t* ptrace_context_;
-};
-
-#endif // _LIBBACKTRACE_CORKSCREW_H
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
index 034b73c..67d372a 100755
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -42,7 +42,7 @@
     BACK_LOGW("unw_getcontext failed %d", ret);
     return false;
   }
-  return UnwindFromContext(num_ignore_frames, true);
+  return UnwindFromContext(num_ignore_frames, false);
 }
 
 std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
@@ -57,12 +57,14 @@
   return "";
 }
 
-bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) {
+bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool within_handler) {
   // The cursor structure is pretty large, do not put it on the stack.
   unw_cursor_t* cursor = new unw_cursor_t;
   int ret = unw_init_local(cursor, &context_);
   if (ret < 0) {
-    BACK_LOGW("unw_init_local failed %d", ret);
+    if (!within_handler) {
+      BACK_LOGW("unw_init_local failed %d", ret);
+    }
     delete cursor;
     return false;
   }
@@ -74,13 +76,17 @@
     unw_word_t pc;
     ret = unw_get_reg(cursor, UNW_REG_IP, &pc);
     if (ret < 0) {
-      BACK_LOGW("Failed to read IP %d", ret);
+      if (!within_handler) {
+        BACK_LOGW("Failed to read IP %d", ret);
+      }
       break;
     }
     unw_word_t sp;
     ret = unw_get_reg(cursor, UNW_REG_SP, &sp);
     if (ret < 0) {
-      BACK_LOGW("Failed to read SP %d", ret);
+      if (!within_handler) {
+        BACK_LOGW("Failed to read SP %d", ret);
+      }
       break;
     }
 
@@ -98,7 +104,7 @@
         prev->stack_size = frame->sp - prev->sp;
       }
 
-      if (resolve) {
+      if (!within_handler) {
         frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
         frame->map = FindMap(frame->pc);
       } else {
@@ -154,7 +160,7 @@
 void UnwindThread::ThreadUnwind(
     siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) {
   ExtractContext(sigcontext);
-  UnwindFromContext(num_ignore_frames, false);
+  UnwindFromContext(num_ignore_frames, true);
 }
 
 //-------------------------------------------------------------------------
diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h
index acce110..41080c7 100644
--- a/libbacktrace/UnwindCurrent.h
+++ b/libbacktrace/UnwindCurrent.h
@@ -34,7 +34,7 @@
 
   virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
 
-  bool UnwindFromContext(size_t num_ignore_frames, bool resolve);
+  bool UnwindFromContext(size_t num_ignore_frames, bool within_handler);
 
   void ExtractContext(void* sigcontext);
 
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index a5e141b..9744922 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -33,6 +33,9 @@
 #include <backtrace/BacktraceMap.h>
 #include <UniquePtr.h>
 
+// For the THREAD_SIGNAL definition.
+#include "BacktraceThread.h"
+
 #include <cutils/atomic.h>
 #include <gtest/gtest.h>
 
@@ -460,9 +463,15 @@
   // Wait up to 2 seconds for the tid to be set.
   ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
 
+  // Make sure that the thread signal used is not visible when compiled for
+  // the target.
+#if !defined(__GLIBC__)
+  ASSERT_LT(THREAD_SIGNAL, SIGRTMIN);
+#endif
+
   // Save the current signal action and make sure it is restored afterwards.
   struct sigaction cur_action;
-  ASSERT_TRUE(sigaction(SIGURG, NULL, &cur_action) == 0);
+  ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &cur_action) == 0);
 
   UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
   ASSERT_TRUE(backtrace.get() != NULL);
@@ -475,7 +484,7 @@
 
   // Verify that the old action was restored.
   struct sigaction new_action;
-  ASSERT_TRUE(sigaction(SIGURG, NULL, &new_action) == 0);
+  ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &new_action) == 0);
   EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction);
   EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
 }
diff --git a/libcorkscrew/Android.mk b/libcorkscrew/Android.mk
deleted file mode 100644
index 8f3b68c..0000000
--- a/libcorkscrew/Android.mk
+++ /dev/null
@@ -1,100 +0,0 @@
-# Copyright (C) 2011 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-generic_src_files := \
-	backtrace.c \
-	backtrace-helper.c \
-	demangle.c \
-	map_info.c \
-	ptrace.c \
-	symbol_table.c
-
-arm_src_files := \
-	arch-arm/backtrace-arm.c \
-	arch-arm/ptrace-arm.c
-
-x86_src_files := \
-	arch-x86/backtrace-x86.c \
-	arch-x86/ptrace-x86.c
-
-ifneq ($(TARGET_IS_64_BIT),true)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(generic_src_files)
-
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_SRC_FILES += $(arm_src_files)
-LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-endif
-ifeq ($(TARGET_ARCH),x86)
-LOCAL_SRC_FILES += $(x86_src_files)
-LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-endif
-ifeq ($(TARGET_ARCH),mips)
-LOCAL_SRC_FILES += \
-	arch-mips/backtrace-mips.c \
-	arch-mips/ptrace-mips.c
-LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-endif
-
-LOCAL_SHARED_LIBRARIES += libdl libcutils liblog libgccdemangle
-
-LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
-LOCAL_MODULE := libcorkscrew
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Build test.
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := test.cpp
-LOCAL_CFLAGS += -Werror -fno-inline-small-functions
-LOCAL_SHARED_LIBRARIES := libcorkscrew
-LOCAL_MODULE := libcorkscrew_test
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-endif # TARGET_IS_64_BIT == false
-
-
-ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
-
-# Build libcorkscrew.
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES += $(generic_src_files) $(x86_src_files)
-LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-LOCAL_STATIC_LIBRARIES += libcutils liblog
-LOCAL_LDLIBS += -ldl
-ifeq ($(HOST_OS),linux)
-  LOCAL_SHARED_LIBRARIES += libgccdemangle # TODO: is this even needed on Linux?
-  LOCAL_LDLIBS += -lrt
-endif
-LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
-LOCAL_MODULE := libcorkscrew
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-# Build test.
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := test.cpp
-LOCAL_CFLAGS += -Werror
-LOCAL_SHARED_LIBRARIES := libcorkscrew
-LOCAL_MODULE := libcorkscrew_test
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_HOST_EXECUTABLE)
-
-endif # $(HOST_OS)-$(HOST_ARCH) == linux-x86
diff --git a/libcorkscrew/MODULE_LICENSE_APACHE2 b/libcorkscrew/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/libcorkscrew/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/libcorkscrew/NOTICE b/libcorkscrew/NOTICE
deleted file mode 100644
index becc120..0000000
--- a/libcorkscrew/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2011, 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.
-
-   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.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
diff --git a/libcorkscrew/arch-arm/backtrace-arm.c b/libcorkscrew/arch-arm/backtrace-arm.c
deleted file mode 100644
index 751efbf..0000000
--- a/libcorkscrew/arch-arm/backtrace-arm.c
+++ /dev/null
@@ -1,589 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Backtracing functions for ARM.
- *
- * This implementation uses the exception unwinding tables provided by
- * the compiler to unwind call frames.  Refer to the ARM Exception Handling ABI
- * documentation (EHABI) for more details about what's going on here.
- *
- * An ELF binary may contain an EXIDX section that provides an index to
- * the exception handling table of each function, sorted by program
- * counter address.
- *
- * This implementation also supports unwinding other processes via ptrace().
- * In that case, the EXIDX section is found by reading the ELF section table
- * structures using ptrace().
- *
- * Because the tables are used for exception handling, it can happen that
- * a given function will not have an exception handling table.  In particular,
- * exceptions are assumed to only ever be thrown at call sites.  Therefore,
- * by definition leaf functions will not have exception handling tables.
- * This may make unwinding impossible in some cases although we can still get
- * some idea of the call stack by examining the PC and LR registers.
- *
- * As we are only interested in backtrace information, we do not need
- * to perform all of the work of unwinding such as restoring register
- * state and running cleanup functions.  Unwinding is performed virtually on
- * an abstract machine context consisting of just the ARM core registers.
- * Furthermore, we do not run generic "personality functions" because
- * we may not be in a position to execute arbitrary code, especially if
- * we are running in a signal handler or using ptrace()!
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../backtrace-arch.h"
-#include "../backtrace-helper.h"
-#include "../ptrace-arch.h"
-#include <corkscrew/ptrace.h>
-
-#include <stdlib.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <limits.h>
-#include <errno.h>
-#include <sys/ptrace.h>
-#include <elf.h>
-#include <cutils/log.h>
-
-#include <ucontext.h>
-
-/* Unwind state. */
-typedef struct {
-    uint32_t gregs[16];
-} unwind_state_t;
-
-static const int R_SP = 13;
-static const int R_LR = 14;
-static const int R_PC = 15;
-
-/* Special EXIDX value that indicates that a frame cannot be unwound. */
-static const uint32_t EXIDX_CANTUNWIND = 1;
-
-/* Get the EXIDX section start and size for the module that contains a
- * given program counter address.
- *
- * When the executable is statically linked, the EXIDX section can be
- * accessed by querying the values of the __exidx_start and __exidx_end
- * symbols.
- *
- * When the executable is dynamically linked, the linker exports a function
- * called dl_unwind_find_exidx that obtains the EXIDX section for a given
- * absolute program counter address.
- *
- * Bionic exports a helpful function called __gnu_Unwind_Find_exidx that
- * handles both cases, so we use that here.
- */
-typedef long unsigned int* _Unwind_Ptr;
-extern _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr pc, int *pcount);
-
-static uintptr_t find_exidx(uintptr_t pc, size_t* out_exidx_size) {
-    int count;
-    uintptr_t start = (uintptr_t)__gnu_Unwind_Find_exidx((_Unwind_Ptr)pc, &count);
-    *out_exidx_size = count;
-    return start;
-}
-
-/* Transforms a 31-bit place-relative offset to an absolute address.
- * We assume the most significant bit is clear. */
-static uintptr_t prel_to_absolute(uintptr_t place, uint32_t prel_offset) {
-    return place + (((int32_t)(prel_offset << 1)) >> 1);
-}
-
-static uintptr_t get_exception_handler(const memory_t* memory,
-        const map_info_t* map_info_list, uintptr_t pc) {
-    if (!pc) {
-        ALOGV("get_exception_handler: pc is zero, no handler");
-        return 0;
-    }
-
-    uintptr_t exidx_start;
-    size_t exidx_size;
-    const map_info_t* mi;
-    if (memory->tid < 0) {
-        mi = NULL;
-        exidx_start = find_exidx(pc, &exidx_size);
-    } else {
-        mi = find_map_info(map_info_list, pc);
-        if (mi && mi->data) {
-            const map_info_data_t* data = (const map_info_data_t*)mi->data;
-            exidx_start = data->exidx_start;
-            exidx_size = data->exidx_size;
-        } else {
-            exidx_start = 0;
-            exidx_size = 0;
-        }
-    }
-
-    uintptr_t handler = 0;
-    int32_t handler_index = -1;
-    if (exidx_start) {
-        uint32_t low = 0;
-        uint32_t high = exidx_size;
-        while (low < high) {
-            uint32_t index = (low + high) / 2;
-            uintptr_t entry = exidx_start + index * 8;
-            uint32_t entry_prel_pc;
-            ALOGV("XXX low=%u, high=%u, index=%u", low, high, index);
-            if (!try_get_word(memory, entry, &entry_prel_pc)) {
-                break;
-            }
-            uintptr_t entry_pc = prel_to_absolute(entry, entry_prel_pc);
-            ALOGV("XXX entry_pc=0x%08x", entry_pc);
-            if (pc < entry_pc) {
-                high = index;
-                continue;
-            }
-            if (index + 1 < exidx_size) {
-                uintptr_t next_entry = entry + 8;
-                uint32_t next_entry_prel_pc;
-                if (!try_get_word(memory, next_entry, &next_entry_prel_pc)) {
-                    break;
-                }
-                uintptr_t next_entry_pc = prel_to_absolute(next_entry, next_entry_prel_pc);
-                ALOGV("XXX next_entry_pc=0x%08x", next_entry_pc);
-                if (pc >= next_entry_pc) {
-                    low = index + 1;
-                    continue;
-                }
-            }
-
-            uintptr_t entry_handler_ptr = entry + 4;
-            uint32_t entry_handler;
-            if (!try_get_word(memory, entry_handler_ptr, &entry_handler)) {
-                break;
-            }
-            if (entry_handler & (1L << 31)) {
-                handler = entry_handler_ptr; // in-place handler data
-            } else if (entry_handler != EXIDX_CANTUNWIND) {
-                handler = prel_to_absolute(entry_handler_ptr, entry_handler);
-            }
-            handler_index = index;
-            break;
-        }
-    }
-    if (mi) {
-        ALOGV("get_exception_handler: pc=0x%08x, module='%s', module_start=0x%08x, "
-                "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x, handler_index=%d",
-                pc, mi->name, mi->start, exidx_start, exidx_size, handler, handler_index);
-    } else {
-        ALOGV("get_exception_handler: pc=0x%08x, "
-                "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x, handler_index=%d",
-                pc, exidx_start, exidx_size, handler, handler_index);
-    }
-    return handler;
-}
-
-typedef struct {
-    uintptr_t ptr;
-    uint32_t word;
-} byte_stream_t;
-
-static bool try_next_byte(const memory_t* memory, byte_stream_t* stream, uint8_t* out_value) {
-    uint8_t result;
-    switch (stream->ptr & 3) {
-    case 0:
-        if (!try_get_word(memory, stream->ptr, &stream->word)) {
-            *out_value = 0;
-            return false;
-        }
-        *out_value = stream->word >> 24;
-        break;
-
-    case 1:
-        *out_value = stream->word >> 16;
-        break;
-
-    case 2:
-        *out_value = stream->word >> 8;
-        break;
-
-    default:
-        *out_value = stream->word;
-        break;
-    }
-
-    ALOGV("next_byte: ptr=0x%08x, value=0x%02x", stream->ptr, *out_value);
-    stream->ptr += 1;
-    return true;
-}
-
-static void set_reg(unwind_state_t* state, uint32_t reg, uint32_t value) {
-    ALOGV("set_reg: reg=%d, value=0x%08x", reg, value);
-    state->gregs[reg] = value;
-}
-
-static bool try_pop_registers(const memory_t* memory, unwind_state_t* state, uint32_t mask) {
-    uint32_t sp = state->gregs[R_SP];
-    bool sp_updated = false;
-    for (int i = 0; i < 16; i++) {
-        if (mask & (1 << i)) {
-            uint32_t value;
-            if (!try_get_word(memory, sp, &value)) {
-                return false;
-            }
-            if (i == R_SP) {
-                sp_updated = true;
-            }
-            set_reg(state, i, value);
-            sp += 4;
-        }
-    }
-    if (!sp_updated) {
-        set_reg(state, R_SP, sp);
-    }
-    return true;
-}
-
-/* Executes a built-in personality routine as defined in the EHABI.
- * Returns true if unwinding should continue.
- *
- * The data for the built-in personality routines consists of a sequence
- * of unwinding instructions, followed by a sequence of scope descriptors,
- * each of which has a length and offset encoded using 16-bit or 32-bit
- * values.
- *
- * We only care about the unwinding instructions.  They specify the
- * operations of an abstract machine whose purpose is to transform the
- * virtual register state (including the stack pointer) such that
- * the call frame is unwound and the PC register points to the call site.
- */
-static bool execute_personality_routine(const memory_t* memory,
-        unwind_state_t* state, byte_stream_t* stream, int pr_index) {
-    size_t size;
-    switch (pr_index) {
-    case 0: // Personality routine #0, short frame, descriptors have 16-bit scope.
-        size = 3;
-        break;
-    case 1: // Personality routine #1, long frame, descriptors have 16-bit scope.
-    case 2: { // Personality routine #2, long frame, descriptors have 32-bit scope.
-        uint8_t size_byte;
-        if (!try_next_byte(memory, stream, &size_byte)) {
-            return false;
-        }
-        size = (uint32_t)size_byte * sizeof(uint32_t) + 2;
-        break;
-    }
-    default: // Unknown personality routine.  Stop here.
-        return false;
-    }
-
-    bool pc_was_set = false;
-    while (size--) {
-        uint8_t op;
-        if (!try_next_byte(memory, stream, &op)) {
-            return false;
-        }
-        if ((op & 0xc0) == 0x00) {
-            // "vsp = vsp + (xxxxxx << 2) + 4"
-            set_reg(state, R_SP, state->gregs[R_SP] + ((op & 0x3f) << 2) + 4);
-        } else if ((op & 0xc0) == 0x40) {
-            // "vsp = vsp - (xxxxxx << 2) - 4"
-            set_reg(state, R_SP, state->gregs[R_SP] - ((op & 0x3f) << 2) - 4);
-        } else if ((op & 0xf0) == 0x80) {
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            uint32_t mask = (((uint32_t)op & 0x0f) << 12) | ((uint32_t)op2 << 4);
-            if (mask) {
-                // "Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}"
-                if (!try_pop_registers(memory, state, mask)) {
-                    return false;
-                }
-                if (mask & (1 << R_PC)) {
-                    pc_was_set = true;
-                }
-            } else {
-                // "Refuse to unwind"
-                return false;
-            }
-        } else if ((op & 0xf0) == 0x90) {
-            if (op != 0x9d && op != 0x9f) {
-                // "Set vsp = r[nnnn]"
-                set_reg(state, R_SP, state->gregs[op & 0x0f]);
-            } else {
-                // "Reserved as prefix for ARM register to register moves"
-                // "Reserved as prefix for Intel Wireless MMX register to register moves"
-                return false;
-            }
-        } else if ((op & 0xf8) == 0xa0) {
-            // "Pop r4-r[4+nnn]"
-            uint32_t mask = (0x0ff0 >> (7 - (op & 0x07))) & 0x0ff0;
-            if (!try_pop_registers(memory, state, mask)) {
-                return false;
-            }
-        } else if ((op & 0xf8) == 0xa8) {
-            // "Pop r4-r[4+nnn], r14"
-            uint32_t mask = ((0x0ff0 >> (7 - (op & 0x07))) & 0x0ff0) | 0x4000;
-            if (!try_pop_registers(memory, state, mask)) {
-                return false;
-            }
-        } else if (op == 0xb0) {
-            // "Finish"
-            break;
-        } else if (op == 0xb1) {
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            if (op2 != 0x00 && (op2 & 0xf0) == 0x00) {
-                // "Pop integer registers under mask {r3, r2, r1, r0}"
-                if (!try_pop_registers(memory, state, op2)) {
-                    return false;
-                }
-            } else {
-                // "Spare"
-                return false;
-            }
-        } else if (op == 0xb2) {
-            // "vsp = vsp + 0x204 + (uleb128 << 2)"
-            uint32_t value = 0;
-            uint32_t shift = 0;
-            uint8_t op2;
-            do {
-                if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                    return false;
-                }
-                value |= (op2 & 0x7f) << shift;
-                shift += 7;
-            } while (op2 & 0x80);
-            set_reg(state, R_SP, state->gregs[R_SP] + (value << 2) + 0x204);
-        } else if (op == 0xb3) {
-            // "Pop VFP double-precision registers D[ssss]-D[ssss+cccc] saved (as if) by FSTMFDX"
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 12);
-        } else if ((op & 0xf8) == 0xb8) {
-            // "Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by FSTMFDX"
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op & 0x07) * 8 + 12);
-        } else if ((op & 0xf8) == 0xc0) {
-            // "Intel Wireless MMX pop wR[10]-wR[10+nnn]"
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op & 0x07) * 8 + 8);
-        } else if (op == 0xc6) {
-            // "Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc]"
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 8);
-        } else if (op == 0xc7) {
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            if (op2 != 0x00 && (op2 & 0xf0) == 0x00) {
-                // "Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}"
-                set_reg(state, R_SP, state->gregs[R_SP] + __builtin_popcount(op2) * 4);
-            } else {
-                // "Spare"
-                return false;
-            }
-        } else if (op == 0xc8) {
-            // "Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc]
-            // saved (as if) by FSTMFD"
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 8);
-        } else if (op == 0xc9) {
-            // "Pop VFP double precision registers D[ssss]-D[ssss+cccc] saved (as if) by FSTMFDD"
-            uint8_t op2;
-            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
-                return false;
-            }
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 8);
-        } else if ((op == 0xf8) == 0xd0) {
-            // "Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by FSTMFDD"
-            set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op & 0x07) * 8 + 8);
-        } else {
-            // "Spare"
-            return false;
-        }
-    }
-    if (!pc_was_set) {
-        set_reg(state, R_PC, state->gregs[R_LR]);
-    }
-    return true;
-}
-
-static bool try_get_half_word(const memory_t* memory, uint32_t pc, uint16_t* out_value) {
-    uint32_t word;
-    if (try_get_word(memory, pc & ~2, &word)) {
-        *out_value = pc & 2 ? word >> 16 : word & 0xffff;
-        return true;
-    }
-    return false;
-}
-
-uintptr_t rewind_pc_arch(const memory_t* memory, uintptr_t pc) {
-    if (pc & 1) {
-        /* Thumb mode - need to check whether the bl(x) has long offset or not.
-         * Examples:
-         *
-         * arm blx in the middle of thumb:
-         * 187ae:       2300            movs    r3, #0
-         * 187b0:       f7fe ee1c       blx     173ec
-         * 187b4:       2c00            cmp     r4, #0
-         *
-         * arm bl in the middle of thumb:
-         * 187d8:       1c20            adds    r0, r4, #0
-         * 187da:       f136 fd15       bl      14f208
-         * 187de:       2800            cmp     r0, #0
-         *
-         * pure thumb:
-         * 18894:       189b            adds    r3, r3, r2
-         * 18896:       4798            blx     r3
-         * 18898:       b001            add     sp, #4
-         */
-        uint16_t prev1, prev2;
-        if (try_get_half_word(memory, pc - 5, &prev1)
-            && ((prev1 & 0xf000) == 0xf000)
-            && try_get_half_word(memory, pc - 3, &prev2)
-            && ((prev2 & 0xe000) == 0xe000)) {
-            pc -= 4; // long offset
-        } else {
-            pc -= 2;
-        }
-    } else {
-        /* ARM mode, all instructions are 32bit.  Yay! */
-        pc -= 4;
-    }
-    return pc;
-}
-
-static ssize_t unwind_backtrace_common(const memory_t* memory,
-        const map_info_t* map_info_list,
-        unwind_state_t* state, backtrace_frame_t* backtrace,
-        size_t ignore_depth, size_t max_depth) {
-    size_t ignored_frames = 0;
-    size_t returned_frames = 0;
-
-    for (size_t index = 0; returned_frames < max_depth; index++) {
-        uintptr_t pc = index ? rewind_pc_arch(memory, state->gregs[R_PC])
-                : state->gregs[R_PC];
-        backtrace_frame_t* frame = add_backtrace_entry(pc,
-                backtrace, ignore_depth, max_depth, &ignored_frames, &returned_frames);
-        if (frame) {
-            frame->stack_top = state->gregs[R_SP];
-        }
-
-        uintptr_t handler = get_exception_handler(memory, map_info_list, pc);
-        if (!handler) {
-            // If there is no handler for the PC and this is the first frame,
-            // then the program may have branched to an invalid address.
-            // Try starting from the LR instead, otherwise stop unwinding.
-            if (index == 0 && state->gregs[R_LR]
-                    && state->gregs[R_LR] != state->gregs[R_PC]) {
-                set_reg(state, R_PC, state->gregs[R_LR]);
-                continue;
-            } else {
-                break;
-            }
-        }
-
-        byte_stream_t stream;
-        stream.ptr = handler;
-        uint8_t pr;
-        if (!try_next_byte(memory, &stream, &pr)) {
-            break;
-        }
-        if ((pr & 0xf0) != 0x80) {
-            // The first word is a place-relative pointer to a generic personality
-            // routine function.  We don't support invoking such functions, so stop here.
-            break;
-        }
-
-        // The first byte indicates the personality routine to execute.
-        // Following bytes provide instructions to the personality routine.
-        if (!execute_personality_routine(memory, state, &stream, pr & 0x0f)) {
-            break;
-        }
-        if (frame && state->gregs[R_SP] > frame->stack_top) {
-            frame->stack_size = state->gregs[R_SP] - frame->stack_top;
-        }
-        if (!state->gregs[R_PC]) {
-            break;
-        }
-    }
-
-    // Ran out of frames that we could unwind using handlers.
-    // Add a final entry for the LR if it looks sane and call it good.
-    if (returned_frames < max_depth
-            && state->gregs[R_LR]
-            && state->gregs[R_LR] != state->gregs[R_PC]
-            && is_executable_map(map_info_list, state->gregs[R_LR])) {
-        // We don't know where the stack for this extra frame starts so we
-        // don't return any stack information for it.
-        add_backtrace_entry(rewind_pc_arch(memory, state->gregs[R_LR]),
-                backtrace, ignore_depth, max_depth, &ignored_frames, &returned_frames);
-    }
-    return returned_frames;
-}
-
-ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext,
-        const map_info_t* map_info_list,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-    const ucontext_t* uc = (const ucontext_t*)sigcontext;
-
-    unwind_state_t state;
-
-    state.gregs[0] = uc->uc_mcontext.arm_r0;
-    state.gregs[1] = uc->uc_mcontext.arm_r1;
-    state.gregs[2] = uc->uc_mcontext.arm_r2;
-    state.gregs[3] = uc->uc_mcontext.arm_r3;
-    state.gregs[4] = uc->uc_mcontext.arm_r4;
-    state.gregs[5] = uc->uc_mcontext.arm_r5;
-    state.gregs[6] = uc->uc_mcontext.arm_r6;
-    state.gregs[7] = uc->uc_mcontext.arm_r7;
-    state.gregs[8] = uc->uc_mcontext.arm_r8;
-    state.gregs[9] = uc->uc_mcontext.arm_r9;
-    state.gregs[10] = uc->uc_mcontext.arm_r10;
-    state.gregs[11] = uc->uc_mcontext.arm_fp;
-    state.gregs[12] = uc->uc_mcontext.arm_ip;
-    state.gregs[13] = uc->uc_mcontext.arm_sp;
-    state.gregs[14] = uc->uc_mcontext.arm_lr;
-    state.gregs[15] = uc->uc_mcontext.arm_pc;
-
-    memory_t memory;
-    init_memory(&memory, map_info_list);
-    return unwind_backtrace_common(&memory, map_info_list, &state,
-            backtrace, ignore_depth, max_depth);
-}
-
-ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-    struct pt_regs regs;
-    if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
-        return -1;
-    }
-
-    unwind_state_t state;
-    for (int i = 0; i < 16; i++) {
-        state.gregs[i] = regs.uregs[i];
-    }
-
-    memory_t memory;
-    init_memory_ptrace(&memory, tid);
-    return unwind_backtrace_common(&memory, context->map_info_list, &state,
-            backtrace, ignore_depth, max_depth);
-}
diff --git a/libcorkscrew/arch-arm/ptrace-arm.c b/libcorkscrew/arch-arm/ptrace-arm.c
deleted file mode 100644
index a50844e..0000000
--- a/libcorkscrew/arch-arm/ptrace-arm.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2011 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 "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../ptrace-arch.h"
-
-#include <elf.h>
-#include <cutils/log.h>
-
-#ifndef PT_ARM_EXIDX
-#define PT_ARM_EXIDX 0x70000001
-#endif
-
-static void load_exidx_header(pid_t pid, map_info_t* mi,
-        uintptr_t* out_exidx_start, size_t* out_exidx_size) {
-    uint32_t elf_phoff;
-    uint32_t elf_phentsize_ehsize;
-    uint32_t elf_shentsize_phnum;
-    if (try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff)
-            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_ehsize),
-                    &elf_phentsize_ehsize)
-            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phnum),
-                    &elf_shentsize_phnum)) {
-        uint32_t elf_phentsize = elf_phentsize_ehsize >> 16;
-        uint32_t elf_phnum = elf_shentsize_phnum & 0xffff;
-        for (uint32_t i = 0; i < elf_phnum; i++) {
-            uintptr_t elf_phdr = mi->start + elf_phoff + i * elf_phentsize;
-            uint32_t elf_phdr_type;
-            if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_type), &elf_phdr_type)) {
-                break;
-            }
-            if (elf_phdr_type == PT_ARM_EXIDX) {
-                uint32_t elf_phdr_offset;
-                uint32_t elf_phdr_filesz;
-                if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_offset),
-                        &elf_phdr_offset)
-                        || !try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_filesz),
-                                &elf_phdr_filesz)) {
-                    break;
-                }
-                *out_exidx_start = mi->start + elf_phdr_offset;
-                *out_exidx_size = elf_phdr_filesz / 8;
-                ALOGV("Parsed EXIDX header info for %s: start=0x%08x, size=%d", mi->name,
-                        *out_exidx_start, *out_exidx_size);
-                return;
-            }
-        }
-    }
-    *out_exidx_start = 0;
-    *out_exidx_size = 0;
-}
-
-void load_ptrace_map_info_data_arch(pid_t pid, map_info_t* mi, map_info_data_t* data) {
-    load_exidx_header(pid, mi, &data->exidx_start, &data->exidx_size);
-}
-
-void free_ptrace_map_info_data_arch(map_info_t* mi, map_info_data_t* data) {
-}
diff --git a/libcorkscrew/arch-mips/backtrace-mips.c b/libcorkscrew/arch-mips/backtrace-mips.c
deleted file mode 100644
index 832fb86..0000000
--- a/libcorkscrew/arch-mips/backtrace-mips.c
+++ /dev/null
@@ -1,901 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-/*
- * Backtracing functions for mips
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../backtrace-arch.h"
-#include "../backtrace-helper.h"
-#include "../ptrace-arch.h"
-#include <corkscrew/ptrace.h>
-#include "dwarf.h"
-
-#include <stdlib.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <limits.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <cutils/log.h>
-
-#include <sys/ucontext.h>
-
-/* For PTRACE_GETREGS */
-typedef struct {
-    uint64_t regs[32];
-    uint64_t lo;
-    uint64_t hi;
-    uint64_t epc;
-    uint64_t badvaddr;
-    uint64_t status;
-    uint64_t cause;
-} user_regs_struct;
-
-enum {
-    REG_ZERO = 0, REG_AT, REG_V0, REG_V1,
-    REG_A0, REG_A1, REG_A2, REG_A3,
-    REG_T0, REG_T1, REG_T2, REG_T3,
-    REG_T4, REG_T5, REG_T6, REG_T7,
-    REG_S0, REG_S1, REG_S2, REG_S3,
-    REG_S4, REG_S5, REG_S6, REG_S7,
-    REG_T8, REG_T9, REG_K0, REG_K1,
-    REG_GP, REG_SP, REG_S8, REG_RA,
-};
-
-
-/* Unwind state. */
-typedef struct {
-    uint32_t reg[DWARF_REGISTERS];
-} unwind_state_t;
-
-uintptr_t rewind_pc_arch(const memory_t* memory __attribute__((unused)), uintptr_t pc) {
-    if (pc == 0)
-        return pc;
-    if ((pc & 1) == 0)
-        return pc-8;            /* jal/bal/jalr + branch delay slot */
-    return pc;
-}
-
-/* Read byte through 4 byte cache. Usually we read byte by byte and updating cursor. */
-static bool try_get_byte(const memory_t* memory, uintptr_t ptr, uint8_t* out_value, uint32_t* cursor) {
-    static uintptr_t lastptr;
-    static uint32_t buf;
-
-    ptr += *cursor;
-
-    if (ptr < lastptr || lastptr + 3 < ptr) {
-        lastptr = (ptr >> 2) << 2;
-        if (!try_get_word(memory, lastptr, &buf)) {
-            return false;
-        }
-    }
-    *out_value = (uint8_t)((buf >> ((ptr & 3) * 8)) & 0xff);
-    ++*cursor;
-    return true;
-}
-
-/* Getting X bytes. 4 is maximum for now. */
-static bool try_get_xbytes(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint8_t bytes, uint32_t* cursor) {
-    uint32_t data = 0;
-    if (bytes > 4) {
-        ALOGE("can't read more than 4 bytes, trying to read %d", bytes);
-        return false;
-    }
-    for (int i = 0; i < bytes; i++) {
-        uint8_t buf;
-        if (!try_get_byte(memory, ptr, &buf, cursor)) {
-            return false;
-        }
-        data |= (uint32_t)buf << (i * 8);
-    }
-    *out_value = data;
-    return true;
-}
-
-/* Reads signed/unsigned LEB128 encoded data. From 1 to 4 bytes. */
-static bool try_get_leb128(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint32_t* cursor, bool sign_extend) {
-    uint8_t buf = 0;
-    uint32_t val = 0;
-    uint8_t c = 0;
-    do {
-        if (!try_get_byte(memory, ptr, &buf, cursor)) {
-            return false;
-        }
-        val |= ((uint32_t)buf & 0x7f) << (c * 7);
-        c++;
-    } while (buf & 0x80 && (c * 7) <= 32);
-    if (c * 7 > 32) {
-        ALOGE("%s: data exceeds expected 4 bytes maximum", __FUNCTION__);
-        return false;
-    }
-    if (sign_extend) {
-        if (buf & 0x40) {
-            val |= ((uint32_t)-1 << (c * 7));
-        }
-    }
-    *out_value = val;
-    return true;
-}
-
-/* Reads signed LEB128 encoded data. From 1 to 4 bytes. */
-static bool try_get_sleb128(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint32_t* cursor) {
-    return try_get_leb128(memory, ptr, out_value, cursor, true);
-}
-
-/* Reads unsigned LEB128 encoded data. From 1 to 4 bytes. */
-static bool try_get_uleb128(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint32_t* cursor) {
-    return try_get_leb128(memory, ptr, out_value, cursor, false);
-}
-
-/* Getting data encoded by dwarf encodings. */
-static bool read_dwarf(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint8_t encoding, uint32_t* cursor) {
-    uint32_t data = 0;
-    bool issigned = true;
-    uintptr_t addr = ptr + *cursor;
-    /* Lower 4 bits is data type/size */
-    /* TODO: add more encodings if it becomes necessary */
-    switch (encoding & 0xf) {
-    case DW_EH_PE_absptr:
-        if (!try_get_xbytes(memory, ptr, &data, 4, cursor)) {
-            return false;
-        }
-        *out_value = data;
-        return true;
-    case DW_EH_PE_udata4:
-        issigned = false;
-    case DW_EH_PE_sdata4:
-        if (!try_get_xbytes(memory, ptr, &data, 4, cursor)) {
-            return false;
-        }
-        break;
-    default:
-        ALOGE("unrecognized dwarf lower part encoding: 0x%x", encoding);
-        return false;
-    }
-    /* Higher 4 bits is modifier */
-    /* TODO: add more encodings if it becomes necessary */
-    switch (encoding & 0xf0) {
-    case 0:
-        *out_value = data;
-        break;
-    case DW_EH_PE_pcrel:
-        if (issigned) {
-            *out_value = addr + (int32_t)data;
-        } else {
-            *out_value = addr + data;
-        }
-        break;
-        /* Assuming ptr is correct base to calculate datarel */
-    case DW_EH_PE_datarel:
-        if (issigned) {
-            *out_value = ptr + (int32_t)data;
-        } else {
-            *out_value = ptr + data;
-        }
-        break;
-    default:
-        ALOGE("unrecognized dwarf higher part encoding: 0x%x", encoding);
-        return false;
-    }
-    return true;
-}
-
-/* Having PC find corresponding FDE by reading .eh_frame_hdr section data. */
-static uintptr_t find_fde(const memory_t* memory,
-                          const map_info_t* map_info_list, uintptr_t pc) {
-    if (!pc) {
-        ALOGV("find_fde: pc is zero, no eh_frame");
-        return 0;
-    }
-    const map_info_t* mi = find_map_info(map_info_list, pc);
-    if (!mi) {
-        ALOGV("find_fde: no map info for pc:0x%x", pc);
-        return 0;
-    }
-    const map_info_data_t* midata = mi->data;
-    if (!midata) {
-        ALOGV("find_fde: no eh_frame_hdr for map: start=0x%x, end=0x%x", mi->start, mi->end);
-        return 0;
-    }
-
-    eh_frame_hdr_info_t eh_hdr_info;
-    memset(&eh_hdr_info, 0, sizeof(eh_frame_hdr_info_t));
-
-    /* Getting the first word of eh_frame_hdr:
-       1st byte is version;
-       2nd byte is encoding of pointer to eh_frames;
-       3rd byte is encoding of count of FDEs in lookup table;
-       4th byte is encoding of lookup table entries.
-    */
-    uintptr_t eh_frame_hdr = midata->eh_frame_hdr;
-    uint32_t c = 0;
-    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.version, &c)) return 0;
-    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.eh_frame_ptr_enc, &c)) return 0;
-    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.fde_count_enc, &c)) return 0;
-    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.fde_table_enc, &c)) return 0;
-
-    /* TODO: 3rd byte can be DW_EH_PE_omit, that means no lookup table available and we should
-       try to parse eh_frame instead. Not sure how often it may occur, skipping now.
-    */
-    if (eh_hdr_info.version != 1) {
-        ALOGV("find_fde: eh_frame_hdr version %d is not supported", eh_hdr_info.version);
-        return 0;
-    }
-    /* Getting the data:
-       2nd word is eh_frame pointer (normally not used, because lookup table has all we need);
-       3rd word is count of FDEs in the lookup table;
-       starting from 4 word there is FDE lookup table (pairs of PC and FDE pointer) sorted by PC;
-    */
-    if (!read_dwarf(memory, eh_frame_hdr, &eh_hdr_info.eh_frame_ptr, eh_hdr_info.eh_frame_ptr_enc, &c)) return 0;
-    if (!read_dwarf(memory, eh_frame_hdr, &eh_hdr_info.fde_count, eh_hdr_info.fde_count_enc, &c)) return 0;
-    ALOGV("find_fde: found %d FDEs", eh_hdr_info.fde_count);
-
-    int32_t low = 0;
-    int32_t high = eh_hdr_info.fde_count;
-    uintptr_t start = 0;
-    uintptr_t fde = 0;
-    /* eh_frame_hdr + c points to lookup table at this point. */
-    while (low <= high) {
-        uint32_t mid = (high + low)/2;
-        uint32_t entry = c + mid * 8;
-        if (!read_dwarf(memory, eh_frame_hdr, &start, eh_hdr_info.fde_table_enc, &entry)) return 0;
-        if (pc <= start) {
-            high = mid - 1;
-        } else {
-            low = mid + 1;
-        }
-    }
-    /* Value found is at high. */
-    if (high < 0) {
-        ALOGV("find_fde: pc %x is out of FDE bounds: %x", pc, start);
-        return 0;
-    }
-    c += high * 8;
-    if (!read_dwarf(memory, eh_frame_hdr, &start, eh_hdr_info.fde_table_enc, &c)) return 0;
-    if (!read_dwarf(memory, eh_frame_hdr, &fde, eh_hdr_info.fde_table_enc, &c)) return 0;
-    ALOGV("pc 0x%x, ENTRY %d: start=0x%x, fde=0x%x", pc, high, start, fde);
-    return fde;
-}
-
-/* Execute single dwarf instruction and update dwarf state accordingly. */
-static bool execute_dwarf(const memory_t* memory, uintptr_t ptr, cie_info_t* cie_info,
-                          dwarf_state_t* dstate, uint32_t* cursor,
-                          dwarf_state_t* stack, uint8_t* stack_ptr) {
-    uint8_t inst;
-    uint8_t op = 0;
-
-    if (!try_get_byte(memory, ptr, &inst, cursor)) {
-        return false;
-    }
-    ALOGV("DW_CFA inst: 0x%x", inst);
-
-    /* For some instructions upper 2 bits is opcode and lower 6 bits is operand. See dwarf-2.0 7.23. */
-    if (inst & 0xc0) {
-        op = inst & 0x3f;
-        inst &= 0xc0;
-    }
-
-    switch ((dwarf_CFA)inst) {
-        uint32_t reg = 0;
-        uint32_t offset = 0;
-    case DW_CFA_advance_loc:
-        dstate->loc += op * cie_info->code_align;
-        ALOGV("DW_CFA_advance_loc: %d to 0x%x", op, dstate->loc);
-        break;
-    case DW_CFA_offset:
-        if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
-        dstate->regs[op].rule = 'o';
-        dstate->regs[op].value = offset * cie_info->data_align;
-        ALOGV("DW_CFA_offset: r%d = o(%d)", op, dstate->regs[op].value);
-        break;
-    case DW_CFA_restore:
-        dstate->regs[op].rule = stack->regs[op].rule;
-        dstate->regs[op].value = stack->regs[op].value;
-        ALOGV("DW_CFA_restore: r%d = %c(%d)", op, dstate->regs[op].rule, dstate->regs[op].value);
-        break;
-    case DW_CFA_nop:
-        break;
-    case DW_CFA_set_loc: // probably we don't have it on mips.
-        if (!try_get_xbytes(memory, ptr, &offset, 4, cursor)) return false;
-        if (offset < dstate->loc) {
-            ALOGE("DW_CFA_set_loc: attempt to move location backward");
-            return false;
-        }
-        dstate->loc = offset * cie_info->code_align;
-        ALOGV("DW_CFA_set_loc: %d to 0x%x", offset * cie_info->code_align, dstate->loc);
-        break;
-    case DW_CFA_advance_loc1:
-        if (!try_get_byte(memory, ptr, (uint8_t*)&offset, cursor)) return false;
-        dstate->loc += (uint8_t)offset * cie_info->code_align;
-        ALOGV("DW_CFA_advance_loc1: %d to 0x%x", (uint8_t)offset * cie_info->code_align, dstate->loc);
-        break;
-    case DW_CFA_advance_loc2:
-        if (!try_get_xbytes(memory, ptr, &offset, 2, cursor)) return false;
-        dstate->loc += (uint16_t)offset * cie_info->code_align;
-        ALOGV("DW_CFA_advance_loc2: %d to 0x%x", (uint16_t)offset * cie_info->code_align, dstate->loc);
-        break;
-    case DW_CFA_advance_loc4:
-        if (!try_get_xbytes(memory, ptr, &offset, 4, cursor)) return false;
-        dstate->loc += offset * cie_info->code_align;
-        ALOGV("DW_CFA_advance_loc4: %d to 0x%x", offset * cie_info->code_align, dstate->loc);
-        break;
-    case DW_CFA_offset_extended: // probably we don't have it on mips.
-        if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
-        if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
-        if (reg >= DWARF_REGISTERS) {
-            ALOGE("DW_CFA_offset_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
-            return false;
-        }
-        dstate->regs[reg].rule = 'o';
-        dstate->regs[reg].value = offset * cie_info->data_align;
-        ALOGV("DW_CFA_offset_extended: r%d = o(%d)", reg, dstate->regs[reg].value);
-        break;
-    case DW_CFA_restore_extended: // probably we don't have it on mips.
-        if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
-        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 mips.
-        if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
-        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 mips.
-        if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
-        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 mips.
-        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) {
-            ALOGE("DW_CFA_register: r%d or r%d exceeds supported number of registers (%d)", reg, offset, DWARF_REGISTERS);
-            return false;
-        }
-        dstate->regs[reg].rule = 'r';
-        dstate->regs[reg].value = offset;
-        ALOGV("DW_CFA_register: r%d = r(%d)", reg, dstate->regs[reg].value);
-        break;
-    case DW_CFA_remember_state:
-        if (*stack_ptr == DWARF_STATES_STACK) {
-            ALOGE("DW_CFA_remember_state: states stack overflow %d", *stack_ptr);
-            return false;
-        }
-        stack[(*stack_ptr)++] = *dstate;
-        ALOGV("DW_CFA_remember_state: stacktop moves to %d", *stack_ptr);
-        break;
-    case DW_CFA_restore_state:
-        /* We have CIE state saved at 0 position. It's not supposed to be taken
-           by DW_CFA_restore_state. */
-        if (*stack_ptr == 1) {
-            ALOGE("DW_CFA_restore_state: states stack is empty");
-            return false;
-        }
-        /* Don't touch location on restore. */
-        uintptr_t saveloc = dstate->loc;
-        *dstate = stack[--*stack_ptr];
-        dstate->loc = saveloc;
-        ALOGV("DW_CFA_restore_state: stacktop moves to %d", *stack_ptr);
-        break;
-    case DW_CFA_def_cfa:
-        if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
-        if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
-        dstate->cfa_reg = reg;
-        dstate->cfa_off = offset;
-        ALOGV("DW_CFA_def_cfa: %x(r%d)", offset, reg);
-        break;
-    case DW_CFA_def_cfa_register:
-        if (!try_get_uleb128(memory, ptr, &reg, cursor)) {
-            return false;
-        }
-        dstate->cfa_reg = reg;
-        ALOGV("DW_CFA_def_cfa_register: r%d", reg);
-        break;
-    case DW_CFA_def_cfa_offset:
-        if (!try_get_uleb128(memory, ptr, &offset, cursor)) {
-            return false;
-        }
-        dstate->cfa_off = offset;
-        ALOGV("DW_CFA_def_cfa_offset: %x", offset);
-        break;
-    default:
-        ALOGE("unrecognized DW_CFA_* instruction: 0x%x", inst);
-        return false;
-    }
-    return true;
-}
-
-/* Restoring particular register value based on dwarf state. */
-static bool get_old_register_value(const memory_t* memory, uint32_t cfa,
-                                   dwarf_state_t* dstate, uint8_t reg,
-                                   unwind_state_t* state, unwind_state_t* newstate) {
-    uint32_t addr;
-    switch (dstate->regs[reg].rule) {
-    case 0:
-        /* We don't have dstate updated for this register, so assuming value kept the same.
-           Normally we should look into state and return current value as the old one
-           but we don't have all registers in state to handle this properly */
-        ALOGV("get_old_register_value: value of r%d is the same", reg);
-        // for SP if it's not updated by dwarf rule we assume it's equal to CFA
-        // for PC if it's not updated by dwarf rule we assume it's equal to RA
-        if (reg == DWARF_SP) {
-            ALOGV("get_old_register_value: adjusting sp to CFA: 0x%x", cfa);
-            newstate->reg[reg] = cfa;
-        } else if (reg == DWARF_PC) {
-            ALOGV("get_old_register_value: adjusting PC to RA: 0x%x", newstate->reg[DWARF_RA]);
-            newstate->reg[reg] = newstate->reg[DWARF_RA];
-        } else {
-            newstate->reg[reg] = state->reg[reg];
-        }
-        break;
-    case 'o':
-        addr = cfa + (int32_t)dstate->regs[reg].value;
-        if (!try_get_word(memory, addr, &newstate->reg[reg])) {
-            ALOGE("get_old_register_value: can't read from 0x%x", addr);
-            return false;
-        }
-        ALOGV("get_old_register_value: r%d at 0x%x is 0x%x", reg, addr, newstate->reg[reg]);
-        break;
-    case 'r':
-        /* We don't have all registers in state so don't even try to look at 'r' */
-        ALOGE("get_old_register_value: register lookup not implemented yet");
-        break;
-    default:
-        ALOGE("get_old_register_value: unexpected rule:%c value:%d for register %d",
-              dstate->regs[reg].rule, (int32_t)dstate->regs[reg].value, reg);
-        return false;
-    }
-    return true;
-}
-
-/* Updaing state based on dwarf state. */
-static bool update_state(const memory_t* memory, unwind_state_t* state,
-                         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. */
-    uintptr_t cfa = 0;
-    if (dstate->cfa_reg == DWARF_SP) {
-        cfa = state->reg[DWARF_SP] + dstate->cfa_off;
-    } else if (dstate->cfa_reg == DWARF_FP) {
-        cfa = state->reg[DWARF_FP] + dstate->cfa_off;
-    } else {
-        ALOGE("update_state: unexpected CFA register: %d", dstate->cfa_reg);
-        return false;
-    }
-    ALOGV("update_state: new CFA: 0x%x", cfa);
-
-    /* Update registers. Order is important to allow RA to propagate to PC */
-    /* Getting FP. */
-    if (!get_old_register_value(memory, cfa, dstate, DWARF_FP, state, &newstate)) return false;
-    /* Getting SP. */
-    if (!get_old_register_value(memory, cfa, dstate, DWARF_SP, state, &newstate)) return false;
-    /* Getting RA. */
-    if (!get_old_register_value(memory, cfa, dstate, DWARF_RA, state, &newstate)) return false;
-    /* Getting PC. */
-    if (!get_old_register_value(memory, cfa, dstate, DWARF_PC, state, &newstate)) return false;
-
-    ALOGV("update_state: PC: 0x%x; restore PC: 0x%x", state->reg[DWARF_PC], newstate.reg[DWARF_PC]);
-    ALOGV("update_state: RA: 0x%x; restore RA: 0x%x", state->reg[DWARF_RA], newstate.reg[DWARF_RA]);
-    ALOGV("update_state: FP: 0x%x; restore FP: 0x%x", state->reg[DWARF_FP], newstate.reg[DWARF_FP]);
-    ALOGV("update_state: SP: 0x%x; restore SP: 0x%x", state->reg[DWARF_SP], newstate.reg[DWARF_SP]);
-
-    if (newstate.reg[DWARF_PC] == 0)
-        return false;
-
-    /* End backtrace if registers do not change */
-    if ((state->reg[DWARF_PC] == newstate.reg[DWARF_PC]) &&
-        (state->reg[DWARF_RA] == newstate.reg[DWARF_RA]) &&
-        (state->reg[DWARF_FP] == newstate.reg[DWARF_FP]) &&
-        (state->reg[DWARF_SP] == newstate.reg[DWARF_SP]))
-        return false;
-
-    *state = newstate;
-    return true;
-}
-
-/* Execute CIE and FDE instructions for FDE found with find_fde. */
-static bool execute_fde(const memory_t* memory,
-                        uintptr_t fde,
-                        unwind_state_t* state) {
-    uint32_t fde_length = 0;
-    uint32_t cie_length = 0;
-    uintptr_t cie = 0;
-    uintptr_t cie_offset = 0;
-    cie_info_t cie_i;
-    cie_info_t* cie_info = &cie_i;
-    fde_info_t fde_i;
-    fde_info_t* fde_info = &fde_i;
-    dwarf_state_t dwarf_state;
-    dwarf_state_t* dstate = &dwarf_state;
-    dwarf_state_t stack[DWARF_STATES_STACK];
-    uint8_t stack_ptr = 0;
-
-    memset(dstate, 0, sizeof(dwarf_state_t));
-    memset(cie_info, 0, sizeof(cie_info_t));
-    memset(fde_info, 0, sizeof(fde_info_t));
-
-    /* Read common CIE or FDE area:
-       1st word is length;
-       2nd word is ID: 0 for CIE, CIE pointer for FDE.
-    */
-    if (!try_get_word(memory, fde, &fde_length)) {
-        return false;
-    }
-    if ((int32_t)fde_length == -1) {
-        ALOGV("execute_fde: 64-bit dwarf detected, not implemented yet");
-        return false;
-    }
-    if (!try_get_word(memory, fde + 4, &cie_offset)) {
-        return false;
-    }
-    if (cie_offset == 0) {
-        /* This is CIE. We shouldn't be here normally. */
-        cie = fde;
-        cie_length = fde_length;
-    } else {
-        /* Find CIE. */
-        /* Positive cie_offset goes backward from current field. */
-        cie = fde + 4 - cie_offset;
-        if (!try_get_word(memory, cie, &cie_length)) {
-            return false;
-        }
-        if ((int32_t)cie_length == -1) {
-            ALOGV("execute_fde: 64-bit dwarf detected, not implemented yet");
-            return false;
-        }
-        if (!try_get_word(memory, cie + 4, &cie_offset)) {
-            return false;
-        }
-        if (cie_offset != 0) {
-            ALOGV("execute_fde: can't find CIE");
-            return false;
-        }
-    }
-    ALOGV("execute_fde: FDE length: %d", fde_length);
-    ALOGV("execute_fde: CIE pointer: %x", cie);
-    ALOGV("execute_fde: CIE length: %d", cie_length);
-
-    /* Read CIE:
-       Augmentation independent:
-       1st byte is version;
-       next x bytes is /0 terminated augmentation string;
-       next x bytes is unsigned LEB128 encoded code alignment factor;
-       next x bytes is signed LEB128 encoded data alignment factor;
-       next 1 (CIE version 1) or x (CIE version 3 unsigned LEB128) bytes is return register column;
-       Augmentation dependent:
-       if 'z' next x bytes is unsigned LEB128 encoded augmentation data size;
-       if 'L' next 1 byte is LSDA encoding;
-       if 'R' next 1 byte is FDE encoding;
-       if 'S' CIE represents signal handler stack frame;
-       if 'P' next 1 byte is personality encoding folowed by personality function pointer;
-       Next x bytes is CIE program.
-    */
-
-    uint32_t c = 8;
-    if (!try_get_byte(memory, cie, &cie_info->version, &c)) {
-        return false;
-    }
-    ALOGV("execute_fde: CIE version: %d", cie_info->version);
-    uint8_t ch;
-    do {
-        if (!try_get_byte(memory, cie, &ch, &c)) {
-            return false;
-        }
-        switch (ch) {
-        case '\0': break;
-        case 'z': cie_info->aug_z = 1; break;
-        case 'L': cie_info->aug_L = 1; break;
-        case 'R': cie_info->aug_R = 1; break;
-        case 'S': cie_info->aug_S = 1; break;
-        case 'P': cie_info->aug_P = 1; break;
-        default:
-            ALOGV("execute_fde: Unrecognized CIE augmentation char: '%c'", ch);
-            return false;
-            break;
-        }
-    } while (ch);
-    if (!try_get_uleb128(memory, cie, &cie_info->code_align, &c)) {
-        return false;
-    }
-    if (!try_get_sleb128(memory, cie, &cie_info->data_align, &c)) {
-        return false;
-    }
-    if (cie_info->version >= 3) {
-        if (!try_get_uleb128(memory, cie, &cie_info->reg, &c)) {
-            return false;
-        }
-    } else {
-        if (!try_get_byte(memory, cie, (uint8_t*)&cie_info->reg, &c)) {
-            return false;
-        }
-    }
-    ALOGV("execute_fde: CIE code alignment factor: %d", cie_info->code_align);
-    ALOGV("execute_fde: CIE data alignment factor: %d", cie_info->data_align);
-    if (cie_info->aug_z) {
-        if (!try_get_uleb128(memory, cie, &cie_info->aug_z, &c)) {
-            return false;
-        }
-    }
-    if (cie_info->aug_L) {
-        if (!try_get_byte(memory, cie, &cie_info->aug_L, &c)) {
-            return false;
-        }
-    } else {
-        /* Default encoding. */
-        cie_info->aug_L = DW_EH_PE_absptr;
-    }
-    if (cie_info->aug_R) {
-        if (!try_get_byte(memory, cie, &cie_info->aug_R, &c)) {
-            return false;
-        }
-    } else {
-        /* Default encoding. */
-        cie_info->aug_R = DW_EH_PE_absptr;
-    }
-    if (cie_info->aug_P) {
-        /* Get encoding of personality routine pointer. We don't use it now. */
-        if (!try_get_byte(memory, cie, (uint8_t*)&cie_info->aug_P, &c)) {
-            return false;
-        }
-        /* Get routine pointer. */
-        if (!read_dwarf(memory, cie, &cie_info->aug_P, (uint8_t)cie_info->aug_P, &c)) {
-            return false;
-        }
-    }
-    /* CIE program. */
-    /* Length field itself (4 bytes) is not included into length. */
-    stack[0] = *dstate;
-    stack_ptr = 1;
-    while (c < cie_length + 4) {
-        if (!execute_dwarf(memory, cie, cie_info, dstate, &c, stack, &stack_ptr)) {
-            return false;
-        }
-    }
-
-    /* We went directly to CIE. Normally it shouldn't occur. */
-    if (cie == fde) return true;
-
-    /* Go back to FDE. */
-    c = 8;
-    /* Read FDE:
-       Augmentation independent:
-       next x bytes (encoded as specified in CIE) is FDE starting address;
-       next x bytes (encoded as specified in CIE) is FDE number of instructions covered;
-       Augmentation dependent:
-       if 'z' next x bytes is unsigned LEB128 encoded augmentation data size;
-       if 'L' next x bytes is LSDA pointer (encoded as specified in CIE);
-       Next x bytes is FDE program.
-    */
-    if (!read_dwarf(memory, fde, &fde_info->start, (uint8_t)cie_info->aug_R, &c)) {
-        return false;
-    }
-    dstate->loc = fde_info->start;
-    ALOGV("execute_fde: FDE start: %x", dstate->loc);
-    if (!read_dwarf(memory, fde, &fde_info->length, 0, &c)) {
-        return false;
-    }
-    ALOGV("execute_fde: FDE length: %x", fde_info->length);
-    if (cie_info->aug_z) {
-        if (!try_get_uleb128(memory, fde, &fde_info->aug_z, &c)) {
-            return false;
-        }
-    }
-    if (cie_info->aug_L && cie_info->aug_L != DW_EH_PE_omit) {
-        if (!read_dwarf(memory, fde, &fde_info->aug_L, cie_info->aug_L, &c)) {
-            return false;
-        }
-    }
-    /* FDE program. */
-    /* Length field itself (4 bytes) is not included into length. */
-    /* Save CIE state as 0 element of stack. Used by DW_CFA_restore. */
-    stack[0] = *dstate;
-    stack_ptr = 1;
-    while (c < fde_length + 4 && state->reg[DWARF_PC] >= dstate->loc) {
-        if (!execute_dwarf(memory, fde, cie_info, dstate, &c, stack, &stack_ptr)) {
-            return false;
-        }
-        ALOGV("PC: %x, LOC: %x", state->reg[DWARF_PC], dstate->loc);
-    }
-
-    return update_state(memory, state, dstate);
-}
-
-static bool heuristic_state_update(const memory_t* memory, unwind_state_t* state)
-{
-    bool found_start = false;
-    int maxcheck = 1024;
-    int32_t stack_size = 0;
-    int32_t ra_offset = 0;
-    dwarf_state_t dwarf_state;
-    dwarf_state_t* dstate = &dwarf_state;
-
-    static struct {
-        uint32_t insn;
-        uint32_t mask;
-    } frame0sig[] = {
-        {0x3c1c0000, 0xffff0000}, /* lui     gp,xxxx */
-        {0x279c0000, 0xffff0000}, /* addiu   gp,gp,xxxx */
-        {0x039fe021, 0xffffffff}, /* addu    gp,gp,ra */
-    };
-    const int nframe0sig = sizeof(frame0sig)/sizeof(frame0sig[0]);
-    int f0 = nframe0sig;
-    memset(dstate, 0, sizeof(dwarf_state_t));
-
-    /* Search code backwards looking for function prologue */
-    for (uint32_t pc = state->reg[DWARF_PC]-4; maxcheck-- > 0 && !found_start; pc -= 4) {
-        uint32_t op;
-        int32_t immediate;
-
-        if (!try_get_word(memory, pc, &op))
-            return false;
-
-        // ALOGV("@0x%08x: 0x%08x\n", pc, op);
-
-        // Check for frame 0 signature
-        if ((op & frame0sig[f0].mask) == frame0sig[f0].insn) {
-            if (f0 == 0)
-                return false;
-            f0--;
-        }
-        else {
-            f0 = nframe0sig;
-        }
-
-        switch (op & 0xffff0000) {
-        case 0x27bd0000: // addiu sp, imm
-            // looking for stack being decremented
-            immediate = (((int32_t)op) << 16) >> 16;
-            if (immediate < 0) {
-                stack_size = -immediate;
-                ALOGV("@0x%08x: found stack adjustment=%d\n", pc, stack_size);
-            }
-            break;
-        case 0x039f0000: // e021
-
-        case 0xafbf0000: // sw ra, imm(sp)
-            ra_offset = (((int32_t)op) << 16) >> 16;
-            ALOGV("@0x%08x: found ra offset=%d\n", pc, ra_offset);
-            break;
-        case 0x3c1c0000: // lui gp
-            ALOGV("@0x%08x: found function boundary", pc);
-            found_start = true;
-            break;
-        default:
-            break;
-        }
-    }
-
-    dstate->cfa_reg = DWARF_SP;
-    dstate->cfa_off = stack_size;
-
-    if (ra_offset) {
-        dstate->regs[DWARF_RA].rule = 'o';
-        dstate->regs[DWARF_RA].value = -stack_size + ra_offset;
-    }
-
-    return update_state(memory, state, dstate);
-}
-
-static ssize_t unwind_backtrace_common(const memory_t* memory,
-        const map_info_t* map_info_list,
-        unwind_state_t* state, backtrace_frame_t* backtrace,
-        size_t ignore_depth, size_t max_depth) {
-
-    size_t ignored_frames = 0;
-    size_t returned_frames = 0;
-
-    ALOGV("Unwinding tid: %d", memory->tid);
-    ALOGV("PC: %x", state->reg[DWARF_PC]);
-    ALOGV("RA: %x", state->reg[DWARF_RA]);
-    ALOGV("FP: %x", state->reg[DWARF_FP]);
-    ALOGV("SP: %x", state->reg[DWARF_SP]);
-
-    for (size_t index = 0; returned_frames < max_depth; index++) {
-        uintptr_t fde = find_fde(memory, map_info_list, state->reg[DWARF_PC]);
-        backtrace_frame_t* frame = add_backtrace_entry(
-            index ? rewind_pc_arch(memory, state->reg[DWARF_PC]) : state->reg[DWARF_PC],
-            backtrace, ignore_depth, max_depth,
-            &ignored_frames, &returned_frames);
-        uint32_t stack_top = state->reg[DWARF_SP];
-
-        if (fde) {
-            /* Use FDE to update state */
-            if (!execute_fde(memory, fde, state))
-                break;
-        }
-        else {
-            /* FDE is not found, update state heuristically */
-            if (!heuristic_state_update(memory, state))
-                break;
-        }
-
-        if (frame) {
-            frame->stack_top = stack_top;
-            if (stack_top < state->reg[DWARF_SP]) {
-                frame->stack_size = state->reg[DWARF_SP] - stack_top;
-            }
-        }
-        ALOGV("Stack: 0x%x ... 0x%x - %d bytes", frame->stack_top, state->reg[DWARF_SP], frame->stack_size);
-    }
-    return returned_frames;
-}
-
-ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo __attribute__((unused)), void* sigcontext,
-        const map_info_t* map_info_list,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-    const ucontext_t* uc = (const ucontext_t*)sigcontext;
-
-    unwind_state_t state;
-    state.reg[DWARF_PC] = uc->uc_mcontext.pc;
-    state.reg[DWARF_RA] = uc->uc_mcontext.gregs[REG_RA];
-    state.reg[DWARF_FP] = uc->uc_mcontext.gregs[REG_S8];
-    state.reg[DWARF_SP] = uc->uc_mcontext.gregs[REG_SP];
-
-    ALOGV("unwind_backtrace_signal_arch: "
-          "ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
-          ignore_depth, max_depth, state.reg[DWARF_PC], state.reg[DWARF_SP], state.reg[DWARF_RA]);
-
-    memory_t memory;
-    init_memory(&memory, map_info_list);
-    return unwind_backtrace_common(&memory, map_info_list,
-                                   &state, backtrace, ignore_depth, max_depth);
-}
-
-ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-
-    user_regs_struct regs;
-    if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
-        return -1;
-    }
-
-    unwind_state_t state;
-    state.reg[DWARF_PC] = regs.epc;
-    state.reg[DWARF_RA] = regs.regs[REG_RA];
-    state.reg[DWARF_FP] = regs.regs[REG_S8];
-    state.reg[DWARF_SP] = regs.regs[REG_SP];
-
-    ALOGV("unwind_backtrace_ptrace_arch: "
-          "ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
-          ignore_depth, max_depth, state.reg[DWARF_PC], state.reg[DWARF_SP], state.reg[DWARF_RA]);
-
-    memory_t memory;
-    init_memory_ptrace(&memory, tid);
-    return unwind_backtrace_common(&memory, context->map_info_list,
-                                   &state, backtrace, ignore_depth, max_depth);
-}
diff --git a/libcorkscrew/arch-mips/dwarf.h b/libcorkscrew/arch-mips/dwarf.h
deleted file mode 100644
index 8504ea0..0000000
--- a/libcorkscrew/arch-mips/dwarf.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Dwarf2 data encoding flags.
- */
-
-#define DW_EH_PE_absptr         0x00
-#define DW_EH_PE_omit           0xff
-#define DW_EH_PE_uleb128        0x01
-#define DW_EH_PE_udata2         0x02
-#define DW_EH_PE_udata4         0x03
-#define DW_EH_PE_udata8         0x04
-#define DW_EH_PE_sleb128        0x09
-#define DW_EH_PE_sdata2         0x0A
-#define DW_EH_PE_sdata4         0x0B
-#define DW_EH_PE_sdata8         0x0C
-#define DW_EH_PE_signed         0x08
-#define DW_EH_PE_pcrel          0x10
-#define DW_EH_PE_textrel        0x20
-#define DW_EH_PE_datarel        0x30
-#define DW_EH_PE_funcrel        0x40
-#define DW_EH_PE_aligned        0x50
-#define DW_EH_PE_indirect       0x80
-
-/*
- * Dwarf2 call frame instructions.
- */
-
-typedef enum {
-    DW_CFA_advance_loc = 0x40,
-    DW_CFA_offset = 0x80,
-    DW_CFA_restore = 0xc0,
-    DW_CFA_nop = 0x00,
-    DW_CFA_set_loc = 0x01,
-    DW_CFA_advance_loc1 = 0x02,
-    DW_CFA_advance_loc2 = 0x03,
-    DW_CFA_advance_loc4 = 0x04,
-    DW_CFA_offset_extended = 0x05,
-    DW_CFA_restore_extended = 0x06,
-    DW_CFA_undefined = 0x07,
-    DW_CFA_same_value = 0x08,
-    DW_CFA_register = 0x09,
-    DW_CFA_remember_state = 0x0a,
-    DW_CFA_restore_state = 0x0b,
-    DW_CFA_def_cfa = 0x0c,
-    DW_CFA_def_cfa_register = 0x0d,
-    DW_CFA_def_cfa_offset = 0x0e
-} dwarf_CFA;
-
-/*
- * eh_frame_hdr information.
-*/
-
-typedef struct {
-      uint8_t version;
-      uint8_t eh_frame_ptr_enc;
-      uint8_t fde_count_enc;
-      uint8_t fde_table_enc;
-      uintptr_t eh_frame_ptr;
-      uint32_t fde_count;
-} eh_frame_hdr_info_t;
-
-/*
- * CIE information.
-*/
-
-typedef struct {
-      uint8_t version;
-      uint32_t code_align;
-      uint32_t data_align;
-      uint32_t reg;
-      uint32_t aug_z;
-      uint8_t aug_L;
-      uint8_t aug_R;
-      uint8_t aug_S;
-      uint32_t aug_P;
-} cie_info_t;
-
-/*
- * FDE information.
-*/
-
-typedef struct {
-      uint32_t start;
-      uint32_t length; // number of instructions covered by FDE
-      uint32_t aug_z;
-      uint32_t aug_L;
-} fde_info_t;
-
-/*
- * Dwarf state.
-*/
-
-/* Stack of states: required for DW_CFA_remember_state/DW_CFA_restore_state
-   30 should be enough */
-#define DWARF_STATES_STACK 30
-
-typedef struct {
-    char rule;         // rule: o - offset(value); r - register(value)
-    uint32_t value;    // value
-} reg_rule_t;
-
-/* Dwarf preserved number of registers for mips */
-typedef enum
-  {
-    UNW_MIPS_R0,
-    UNW_MIPS_R1,
-    UNW_MIPS_R2,
-    UNW_MIPS_R3,
-    UNW_MIPS_R4,
-    UNW_MIPS_R5,
-    UNW_MIPS_R6,
-    UNW_MIPS_R7,
-    UNW_MIPS_R8,
-    UNW_MIPS_R9,
-    UNW_MIPS_R10,
-    UNW_MIPS_R11,
-    UNW_MIPS_R12,
-    UNW_MIPS_R13,
-    UNW_MIPS_R14,
-    UNW_MIPS_R15,
-    UNW_MIPS_R16,
-    UNW_MIPS_R17,
-    UNW_MIPS_R18,
-    UNW_MIPS_R19,
-    UNW_MIPS_R20,
-    UNW_MIPS_R21,
-    UNW_MIPS_R22,
-    UNW_MIPS_R23,
-    UNW_MIPS_R24,
-    UNW_MIPS_R25,
-    UNW_MIPS_R26,
-    UNW_MIPS_R27,
-    UNW_MIPS_R28,
-    UNW_MIPS_R29,
-    UNW_MIPS_R30,
-    UNW_MIPS_R31,
-
-    UNW_MIPS_PC = 34,
-
-    /* FIXME: Other registers!  */
-
-    /* For MIPS, the CFA is the value of SP (r29) at the call site in the
-       previous frame.  */
-    UNW_MIPS_CFA,
-
-    UNW_TDEP_LASTREG,
-
-    UNW_TDEP_LAST_REG = UNW_MIPS_R31,
-
-    UNW_TDEP_IP = UNW_MIPS_R31,
-    UNW_TDEP_SP = UNW_MIPS_R29,
-    UNW_TDEP_EH = UNW_MIPS_R0   /* FIXME.  */
-
-  }
-mips_regnum_t;
-
-#define DWARF_REGISTERS UNW_TDEP_LASTREG
-
-typedef struct {
-    uintptr_t loc;     // location (ip)
-    uint8_t cfa_reg;   // index of register where CFA location stored
-    intptr_t cfa_off;  // offset
-    reg_rule_t regs[DWARF_REGISTERS]; // dwarf preserved registers for mips
-} dwarf_state_t;
-
-/* DWARF registers we are caring about. */
-
-
-#define DWARF_SP      UNW_MIPS_R29
-#define DWARF_RA      UNW_MIPS_R31
-#define DWARF_PC      UNW_MIPS_PC
-#define DWARF_FP      UNW_MIPS_CFA /* FIXME is this correct? */
diff --git a/libcorkscrew/arch-mips/ptrace-mips.c b/libcorkscrew/arch-mips/ptrace-mips.c
deleted file mode 100644
index ba3b60a..0000000
--- a/libcorkscrew/arch-mips/ptrace-mips.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2011 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 "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../ptrace-arch.h"
-
-#include <stddef.h>
-#include <elf.h>
-#include <cutils/log.h>
-
-static void load_eh_frame_hdr(pid_t pid, map_info_t* mi, uintptr_t *eh_frame_hdr) {
-    uint32_t elf_phoff;
-    uint32_t elf_phentsize_ehsize;
-    uint32_t elf_shentsize_phnum;
-
-
-    try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff);
-    ALOGV("reading 0x%08x elf_phoff:%x",  mi->start + offsetof(Elf32_Ehdr, e_phoff), elf_phoff);
-    try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_ehsize), &elf_phentsize_ehsize);
-    ALOGV("reading 0x%08x elf_phentsize_ehsize:%x", mi->start + offsetof(Elf32_Ehdr, e_ehsize), elf_phentsize_ehsize);
-    try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phnum), &elf_shentsize_phnum);
-    ALOGV("reading 0x%08x elf_shentsize_phnum:%x", mi->start + offsetof(Elf32_Ehdr, e_phnum), elf_shentsize_phnum);
-
-
-
-    if (try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff)
-            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_ehsize),
-                    &elf_phentsize_ehsize)
-            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phnum),
-                    &elf_shentsize_phnum)) {
-        uint32_t elf_phentsize = elf_phentsize_ehsize >> 16;
-        uint32_t elf_phnum = elf_shentsize_phnum & 0xffff;
-        for (uint32_t i = 0; i < elf_phnum; i++) {
-            uintptr_t elf_phdr = mi->start + elf_phoff + i * elf_phentsize;
-            uint32_t elf_phdr_type;
-            if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_type), &elf_phdr_type)) {
-                break;
-            }
-            if (elf_phdr_type == PT_GNU_EH_FRAME) {
-                uint32_t elf_phdr_offset;
-                if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_offset),
-                        &elf_phdr_offset)) {
-                    break;
-                }
-                *eh_frame_hdr = mi->start + elf_phdr_offset;
-                ALOGV("Parsed .eh_frame_hdr info for %s: start=0x%08x", mi->name, *eh_frame_hdr);
-                return;
-            }
-        }
-    }
-    *eh_frame_hdr = 0;
-}
-
-void load_ptrace_map_info_data_arch(pid_t pid, map_info_t* mi, map_info_data_t* data) {
-    ALOGV("load_ptrace_map_info_data_arch");
-    load_eh_frame_hdr(pid, mi, &data->eh_frame_hdr);
-}
-
-void free_ptrace_map_info_data_arch(map_info_t* mi __attribute__((unused)),
-                                    map_info_data_t* data __attribute__((unused))) {
-    ALOGV("free_ptrace_map_info_data_arch");
-}
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
deleted file mode 100755
index df486de..0000000
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ /dev/null
@@ -1,823 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Backtracing functions for x86.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../backtrace-arch.h"
-#include "../backtrace-helper.h"
-#include "../ptrace-arch.h"
-#include <corkscrew/ptrace.h>
-#include "dwarf.h"
-
-#include <stdlib.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <limits.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <cutils/log.h>
-
-#if defined(__APPLE__)
-
-#define _XOPEN_SOURCE
-#include <ucontext.h>
-
-#else
-
-// glibc has its own renaming of the Linux kernel's structures.
-#define __USE_GNU // For REG_EBP, REG_ESP, and REG_EIP.
-#include <ucontext.h>
-
-#endif
-
-/* Unwind state. */
-typedef struct {
-    uint32_t reg[DWARF_REGISTERS];
-} unwind_state_t;
-
-typedef struct {
-    backtrace_frame_t* backtrace;
-    size_t ignore_depth;
-    size_t max_depth;
-    size_t ignored_frames;
-    size_t returned_frames;
-    memory_t memory;
-} backtrace_state_t;
-
-uintptr_t rewind_pc_arch(const memory_t* memory __attribute__((unused)), uintptr_t pc) {
-    /* TODO: x86 instructions are 1-16 bytes, to define exact size of previous instruction
-       we have to disassemble from the function entry point up to pc.
-       Returning pc-1 is probably enough for now, the only drawback is that
-       it points somewhere between the first byte of instruction we are looking for and
-       the first byte of the next instruction. */
-
-    return pc-1;
-    /* TODO: We should adjust that for the signal frames and return pc for them instead of pc-1.
-       To recognize signal frames we should read cie_info property. */
-}
-
-/* Read byte through 4 byte cache. Usually we read byte by byte and updating cursor. */
-static bool try_get_byte(const memory_t* memory, uintptr_t ptr, uint8_t* out_value, uint32_t* cursor) {
-    static uintptr_t lastptr;
-    static uint32_t buf;
-
-    ptr += *cursor;
-
-    if (ptr < lastptr || lastptr + 3 < ptr) {
-        lastptr = (ptr >> 2) << 2;
-        if (!try_get_word(memory, lastptr, &buf)) {
-            return false;
-        }
-    }
-    *out_value = (uint8_t)((buf >> ((ptr & 3) * 8)) & 0xff);
-    ++*cursor;
-    return true;
-}
-
-/* Getting X bytes. 4 is maximum for now. */
-static bool try_get_xbytes(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint8_t bytes, uint32_t* cursor) {
-    uint32_t data = 0;
-    if (bytes > 4) {
-        ALOGE("can't read more than 4 bytes, trying to read %d", bytes);
-        return false;
-    }
-    for (int i = 0; i < bytes; i++) {
-        uint8_t buf;
-        if (!try_get_byte(memory, ptr, &buf, cursor)) {
-            return false;
-        }
-        data |= (uint32_t)buf << (i * 8);
-    }
-    *out_value = data;
-    return true;
-}
-
-/* Reads signed/unsigned LEB128 encoded data. From 1 to 4 bytes. */
-static bool try_get_leb128(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint32_t* cursor, bool sign_extend) {
-    uint8_t buf = 0;
-    uint32_t val = 0;
-    uint8_t c = 0;
-    do {
-       if (!try_get_byte(memory, ptr, &buf, cursor)) {
-           return false;
-       }
-       val |= ((uint32_t)buf & 0x7f) << (c * 7);
-       c++;
-    } while (buf & 0x80 && (c * 7) <= 32);
-    if (c * 7 > 32) {
-       ALOGE("%s: data exceeds expected 4 bytes maximum", __FUNCTION__);
-       return false;
-    }
-    if (sign_extend) {
-        if (buf & 0x40) {
-            val |= ((uint32_t)-1 << (c * 7));
-        }
-    }
-    *out_value = val;
-    return true;
-}
-
-/* Reads signed LEB128 encoded data. From 1 to 4 bytes. */
-static bool try_get_sleb128(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint32_t* cursor) {
-  return try_get_leb128(memory, ptr, out_value, cursor, true);
-}
-
-/* Reads unsigned LEB128 encoded data. From 1 to 4 bytes. */
-static bool try_get_uleb128(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint32_t* cursor) {
-  return try_get_leb128(memory, ptr, out_value, cursor, false);
-}
-
-/* Getting data encoded by dwarf encodings. */
-static bool read_dwarf(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint8_t encoding, uint32_t* cursor) {
-    uint32_t data = 0;
-    bool issigned = true;
-    uintptr_t addr = ptr + *cursor;
-    /* Lower 4 bits is data type/size */
-    /* TODO: add more encodings if it becomes necessary */
-    switch (encoding & 0xf) {
-        case DW_EH_PE_absptr:
-            if (!try_get_xbytes(memory, ptr, &data, 4, cursor)) {
-                return false;
-            }
-            *out_value = data;
-            return true;
-        case DW_EH_PE_udata4:
-            issigned = false;
-        case DW_EH_PE_sdata4:
-            if (!try_get_xbytes(memory, ptr, &data, 4, cursor)) {
-                return false;
-            }
-            break;
-        default:
-            ALOGE("unrecognized dwarf lower part encoding: 0x%x", encoding);
-            return false;
-    }
-    /* Higher 4 bits is modifier */
-    /* TODO: add more encodings if it becomes necessary */
-    switch (encoding & 0xf0) {
-        case 0:
-            *out_value = data;
-            break;
-        case DW_EH_PE_pcrel:
-            if (issigned) {
-                *out_value = addr + (int32_t)data;
-            } else {
-                *out_value = addr + data;
-            }
-            break;
-        /* Assuming ptr is correct base to calculate datarel */
-        case DW_EH_PE_datarel:
-            if (issigned) {
-                *out_value = ptr + (int32_t)data;
-            } else {
-                *out_value = ptr + data;
-            }
-            break;
-        default:
-            ALOGE("unrecognized dwarf higher part encoding: 0x%x", encoding);
-            return false;
-    }
-    return true;
-}
-
-/* Having PC find corresponding FDE by reading .eh_frame_hdr section data. */
-static uintptr_t find_fde(const memory_t* memory,
-                          const map_info_t* map_info_list, uintptr_t pc) {
-    if (!pc) {
-        ALOGV("find_fde: pc is zero, no eh_frame");
-        return 0;
-    }
-    const map_info_t* mi = find_map_info(map_info_list, pc);
-    if (!mi) {
-        ALOGV("find_fde: no map info for pc:0x%x", pc);
-        return 0;
-    }
-    const map_info_data_t* midata = mi->data;
-    if (!midata) {
-        ALOGV("find_fde: no eh_frame_hdr for map: start=0x%x, end=0x%x", mi->start, mi->end);
-        return 0;
-    }
-
-    eh_frame_hdr_info_t eh_hdr_info;
-    memset(&eh_hdr_info, 0, sizeof(eh_frame_hdr_info_t));
-
-    /* Getting the first word of eh_frame_hdr:
-        1st byte is version;
-        2nd byte is encoding of pointer to eh_frames;
-        3rd byte is encoding of count of FDEs in lookup table;
-        4th byte is encoding of lookup table entries.
-    */
-    uintptr_t eh_frame_hdr = midata->eh_frame_hdr;
-    uint32_t c = 0;
-    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.version, &c)) return 0;
-    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.eh_frame_ptr_enc, &c)) return 0;
-    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.fde_count_enc, &c)) return 0;
-    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.fde_table_enc, &c)) return 0;
-
-    /* TODO: 3rd byte can be DW_EH_PE_omit, that means no lookup table available and we should
-       try to parse eh_frame instead. Not sure how often it may occur, skipping now.
-    */
-    if (eh_hdr_info.version != 1) {
-        ALOGV("find_fde: eh_frame_hdr version %d is not supported", eh_hdr_info.version);
-        return 0;
-    }
-    /* Getting the data:
-        2nd word is eh_frame pointer (normally not used, because lookup table has all we need);
-        3rd word is count of FDEs in the lookup table;
-        starting from 4 word there is FDE lookup table (pairs of PC and FDE pointer) sorted by PC;
-    */
-    if (!read_dwarf(memory, eh_frame_hdr, &eh_hdr_info.eh_frame_ptr, eh_hdr_info.eh_frame_ptr_enc, &c)) return 0;
-    if (!read_dwarf(memory, eh_frame_hdr, &eh_hdr_info.fde_count, eh_hdr_info.fde_count_enc, &c)) return 0;
-    ALOGV("find_fde: found %d FDEs", eh_hdr_info.fde_count);
-
-    int32_t low = 0;
-    int32_t high = eh_hdr_info.fde_count;
-    uintptr_t start = 0;
-    uintptr_t fde = 0;
-    /* eh_frame_hdr + c points to lookup table at this point. */
-    while (low <= high) {
-        uint32_t mid = (high + low)/2;
-        uint32_t entry = c + mid * 8;
-        if (!read_dwarf(memory, eh_frame_hdr, &start, eh_hdr_info.fde_table_enc, &entry)) return 0;
-        if (pc <= start) {
-            high = mid - 1;
-        } else {
-            low = mid + 1;
-        }
-    }
-    /* Value found is at high. */
-    if (high < 0) {
-        ALOGV("find_fde: pc %x is out of FDE bounds: %x", pc, start);
-        return 0;
-    }
-    c += high * 8;
-    if (!read_dwarf(memory, eh_frame_hdr, &start, eh_hdr_info.fde_table_enc, &c)) return 0;
-    if (!read_dwarf(memory, eh_frame_hdr, &fde, eh_hdr_info.fde_table_enc, &c)) return 0;
-    ALOGV("pc 0x%x, ENTRY %d: start=0x%x, fde=0x%x", pc, high, start, fde);
-    return fde;
-}
-
-/* Execute single dwarf instruction and update dwarf state accordingly. */
-static bool execute_dwarf(const memory_t* memory, uintptr_t ptr, cie_info_t* cie_info,
-                          dwarf_state_t* dstate, uint32_t* cursor,
-                          dwarf_state_t* stack, uint8_t* stack_ptr) {
-    uint8_t inst;
-    uint8_t op = 0;
-
-    if (!try_get_byte(memory, ptr, &inst, cursor)) {
-        return false;
-    }
-    ALOGV("DW_CFA inst: 0x%x", inst);
-
-    /* For some instructions upper 2 bits is opcode and lower 6 bits is operand. See dwarf-2.0 7.23. */
-    if (inst & 0xc0) {
-        op = inst & 0x3f;
-        inst &= 0xc0;
-    }
-
-    switch ((dwarf_CFA)inst) {
-        uint32_t reg = 0;
-        uint32_t offset = 0;
-        case DW_CFA_advance_loc:
-            dstate->loc += op * cie_info->code_align;
-            ALOGV("DW_CFA_advance_loc: %d to 0x%x", op, dstate->loc);
-            break;
-        case DW_CFA_offset:
-            if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
-            dstate->regs[op].rule = 'o';
-            dstate->regs[op].value = offset * cie_info->data_align;
-            ALOGV("DW_CFA_offset: r%d = o(%d)", op, dstate->regs[op].value);
-            break;
-        case DW_CFA_restore:
-            dstate->regs[op].rule = stack->regs[op].rule;
-            dstate->regs[op].value = stack->regs[op].value;
-            ALOGV("DW_CFA_restore: r%d = %c(%d)", op, dstate->regs[op].rule, dstate->regs[op].value);
-            break;
-        case DW_CFA_nop:
-            break;
-        case DW_CFA_set_loc: // probably we don't have it on x86.
-            if (!try_get_xbytes(memory, ptr, &offset, 4, cursor)) return false;
-            if (offset < dstate->loc) {
-                ALOGE("DW_CFA_set_loc: attempt to move location backward");
-                return false;
-            }
-            dstate->loc = offset * cie_info->code_align;
-            ALOGV("DW_CFA_set_loc: %d to 0x%x", offset * cie_info->code_align, dstate->loc);
-            break;
-        case DW_CFA_advance_loc1:
-            if (!try_get_byte(memory, ptr, (uint8_t*)&offset, cursor)) return false;
-            dstate->loc += (uint8_t)offset * cie_info->code_align;
-            ALOGV("DW_CFA_advance_loc1: %d to 0x%x", (uint8_t)offset * cie_info->code_align, dstate->loc);
-            break;
-        case DW_CFA_advance_loc2:
-            if (!try_get_xbytes(memory, ptr, &offset, 2, cursor)) return false;
-            dstate->loc += (uint16_t)offset * cie_info->code_align;
-            ALOGV("DW_CFA_advance_loc2: %d to 0x%x", (uint16_t)offset * cie_info->code_align, dstate->loc);
-            break;
-        case DW_CFA_advance_loc4:
-            if (!try_get_xbytes(memory, ptr, &offset, 4, cursor)) return false;
-            dstate->loc += offset * cie_info->code_align;
-            ALOGV("DW_CFA_advance_loc4: %d to 0x%x", offset * cie_info->code_align, dstate->loc);
-            break;
-        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) {
-                ALOGE("DW_CFA_offset_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
-                return false;
-            }
-            dstate->regs[reg].rule = 'o';
-            dstate->regs[reg].value = offset * cie_info->data_align;
-            ALOGV("DW_CFA_offset_extended: r%d = o(%d)", reg, dstate->regs[reg].value);
-            break;
-        case DW_CFA_restore_extended: // probably we don't have it on x86.
-            if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
-            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;
-            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;
-            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) {
-                ALOGE("DW_CFA_register: r%d or r%d exceeds supported number of registers (%d)", reg, offset, DWARF_REGISTERS);
-                return false;
-            }
-            dstate->regs[reg].rule = 'r';
-            dstate->regs[reg].value = offset;
-            ALOGV("DW_CFA_register: r%d = r(%d)", reg, dstate->regs[reg].value);
-            break;
-        case DW_CFA_remember_state:
-            if (*stack_ptr == DWARF_STATES_STACK) {
-                ALOGE("DW_CFA_remember_state: states stack overflow %d", *stack_ptr);
-                return false;
-            }
-            stack[(*stack_ptr)++] = *dstate;
-            ALOGV("DW_CFA_remember_state: stacktop moves to %d", *stack_ptr);
-            break;
-        case DW_CFA_restore_state:
-            /* We have CIE state saved at 0 position. It's not supposed to be taken
-               by DW_CFA_restore_state. */
-            if (*stack_ptr == 1) {
-                ALOGE("DW_CFA_restore_state: states stack is empty");
-                return false;
-            }
-            /* Don't touch location on restore. */
-            uintptr_t saveloc = dstate->loc;
-            *dstate = stack[--*stack_ptr];
-            dstate->loc = saveloc;
-            ALOGV("DW_CFA_restore_state: stacktop moves to %d", *stack_ptr);
-            break;
-        case DW_CFA_def_cfa:
-            if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
-            if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
-            dstate->cfa_reg = reg;
-            dstate->cfa_off = offset;
-            ALOGV("DW_CFA_def_cfa: %x(r%d)", offset, reg);
-            break;
-        case DW_CFA_def_cfa_register:
-            if (!try_get_uleb128(memory, ptr, &reg, cursor)) {
-                return false;
-            }
-            dstate->cfa_reg = reg;
-            ALOGV("DW_CFA_def_cfa_register: r%d", reg);
-            break;
-        case DW_CFA_def_cfa_offset:
-            if (!try_get_uleb128(memory, ptr, &offset, cursor)) {
-                return false;
-            }
-            dstate->cfa_off = offset;
-            ALOGV("DW_CFA_def_cfa_offset: %x", offset);
-            break;
-        default:
-            ALOGE("unrecognized DW_CFA_* instruction: 0x%x", inst);
-            return false;
-    }
-    return true;
-}
-
-/* Restoring particular register value based on dwarf state. */
-static bool get_old_register_value(const memory_t* memory, uint32_t cfa,
-                                   dwarf_state_t* dstate, uint8_t reg,
-                                   unwind_state_t* state, unwind_state_t* newstate) {
-    uint32_t addr;
-    switch (dstate->regs[reg].rule) {
-        case 0:
-            /* We don't have dstate updated for this register, so assuming value kept the same.
-               Normally we should look into state and return current value as the old one
-               but we don't have all registers in state to handle this properly */
-            ALOGV("get_old_register_value: value of r%d is the same", reg);
-            // for ESP if it's not updated by dwarf rule we assume it's equal to CFA
-            if (reg == DWARF_ESP) {
-                ALOGV("get_old_register_value: adjusting esp to CFA: 0x%x", cfa);
-                newstate->reg[reg] = cfa;
-            } else {
-                newstate->reg[reg] = state->reg[reg];
-            }
-            break;
-        case 'o':
-            addr = cfa + (int32_t)dstate->regs[reg].value;
-            if (!try_get_word(memory, addr, &newstate->reg[reg])) {
-                ALOGE("get_old_register_value: can't read from 0x%x", addr);
-                return false;
-            }
-            ALOGV("get_old_register_value: r%d at 0x%x is 0x%x", reg, addr, newstate->reg[reg]);
-            break;
-        case 'r':
-            /* We don't have all registers in state so don't even try to look at 'r' */
-            ALOGE("get_old_register_value: register lookup not implemented yet");
-            break;
-        default:
-            ALOGE("get_old_register_value: unexpected rule:%c value:%d for register %d",
-                   dstate->regs[reg].rule, (int32_t)dstate->regs[reg].value, reg);
-            return false;
-    }
-    return true;
-}
-
-/* Updaing state based on dwarf state. */
-static bool update_state(const memory_t* memory, unwind_state_t* state,
-                         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. */
-    uintptr_t cfa = 0;
-    if (dstate->cfa_reg == DWARF_ESP) {
-        cfa = state->reg[DWARF_ESP] + dstate->cfa_off;
-    } else if (dstate->cfa_reg == DWARF_EBP) {
-        cfa = state->reg[DWARF_EBP] + dstate->cfa_off;
-    } else {
-        ALOGE("update_state: unexpected CFA register: %d", dstate->cfa_reg);
-        return false;
-    }
-    ALOGV("update_state: new CFA: 0x%x", cfa);
-    /* Getting EIP. */
-    if (!get_old_register_value(memory, cfa, dstate, DWARF_EIP, state, &newstate)) return false;
-    /* Getting EBP. */
-    if (!get_old_register_value(memory, cfa, dstate, DWARF_EBP, state, &newstate)) return false;
-    /* Getting ESP. */
-    if (!get_old_register_value(memory, cfa, dstate, DWARF_ESP, state, &newstate)) return false;
-
-    ALOGV("update_state: IP:  0x%x; restore IP:  0x%x", state->reg[DWARF_EIP], newstate.reg[DWARF_EIP]);
-    ALOGV("update_state: EBP: 0x%x; restore EBP: 0x%x", state->reg[DWARF_EBP], newstate.reg[DWARF_EBP]);
-    ALOGV("update_state: ESP: 0x%x; restore ESP: 0x%x", state->reg[DWARF_ESP], newstate.reg[DWARF_ESP]);
-    *state = newstate;
-    return true;
-}
-
-/* Execute CIE and FDE instructions for FDE found with find_fde. */
-static bool execute_fde(const memory_t* memory,
-                        uintptr_t fde,
-                        unwind_state_t* state) {
-    uint32_t fde_length = 0;
-    uint32_t cie_length = 0;
-    uintptr_t cie = 0;
-    uintptr_t cie_offset = 0;
-    cie_info_t cie_i;
-    cie_info_t* cie_info = &cie_i;
-    fde_info_t fde_i;
-    fde_info_t* fde_info = &fde_i;
-    dwarf_state_t dwarf_state;
-    dwarf_state_t* dstate = &dwarf_state;
-    dwarf_state_t stack[DWARF_STATES_STACK];
-    uint8_t stack_ptr = 0;
-
-    memset(dstate, 0, sizeof(dwarf_state_t));
-    memset(cie_info, 0, sizeof(cie_info_t));
-    memset(fde_info, 0, sizeof(fde_info_t));
-
-    /* Read common CIE or FDE area:
-        1st word is length;
-        2nd word is ID: 0 for CIE, CIE pointer for FDE.
-    */
-    if (!try_get_word(memory, fde, &fde_length)) {
-        return false;
-    }
-    if ((int32_t)fde_length == -1) {
-        ALOGV("execute_fde: 64-bit dwarf detected, not implemented yet");
-        return false;
-    }
-    if (!try_get_word(memory, fde + 4, &cie_offset)) {
-        return false;
-    }
-    if (cie_offset == 0) {
-        /* This is CIE. We shouldn't be here normally. */
-        cie = fde;
-        cie_length = fde_length;
-    } else {
-        /* Find CIE. */
-        /* Positive cie_offset goes backward from current field. */
-        cie = fde + 4 - cie_offset;
-        if (!try_get_word(memory, cie, &cie_length)) {
-           return false;
-        }
-        if ((int32_t)cie_length == -1) {
-           ALOGV("execute_fde: 64-bit dwarf detected, not implemented yet");
-           return false;
-        }
-        if (!try_get_word(memory, cie + 4, &cie_offset)) {
-           return false;
-        }
-        if (cie_offset != 0) {
-           ALOGV("execute_fde: can't find CIE");
-           return false;
-        }
-    }
-    ALOGV("execute_fde: FDE length: %d", fde_length);
-    ALOGV("execute_fde: CIE pointer: %x", cie);
-    ALOGV("execute_fde: CIE length: %d", cie_length);
-
-    /* Read CIE:
-       Augmentation independent:
-        1st byte is version;
-        next x bytes is /0 terminated augmentation string;
-        next x bytes is unsigned LEB128 encoded code alignment factor;
-        next x bytes is signed LEB128 encoded data alignment factor;
-        next 1 (CIE version 1) or x (CIE version 3 unsigned LEB128) bytes is return register column;
-       Augmentation dependent:
-        if 'z' next x bytes is unsigned LEB128 encoded augmentation data size;
-        if 'L' next 1 byte is LSDA encoding;
-        if 'R' next 1 byte is FDE encoding;
-        if 'S' CIE represents signal handler stack frame;
-        if 'P' next 1 byte is personality encoding folowed by personality function pointer;
-       Next x bytes is CIE program.
-    */
-
-    uint32_t c = 8;
-    if (!try_get_byte(memory, cie, &cie_info->version, &c)) {
-       return false;
-    }
-    ALOGV("execute_fde: CIE version: %d", cie_info->version);
-    uint8_t ch;
-    do {
-        if (!try_get_byte(memory, cie, &ch, &c)) {
-           return false;
-        }
-        switch (ch) {
-           case '\0': break;
-           case 'z': cie_info->aug_z = 1; break;
-           case 'L': cie_info->aug_L = 1; break;
-           case 'R': cie_info->aug_R = 1; break;
-           case 'S': cie_info->aug_S = 1; break;
-           case 'P': cie_info->aug_P = 1; break;
-           default:
-              ALOGV("execute_fde: Unrecognized CIE augmentation char: '%c'", ch);
-              return false;
-              break;
-        }
-    } while (ch);
-    if (!try_get_uleb128(memory, cie, &cie_info->code_align, &c)) {
-        return false;
-    }
-    if (!try_get_sleb128(memory, cie, &cie_info->data_align, &c)) {
-        return false;
-    }
-    if (cie_info->version >= 3) {
-        if (!try_get_uleb128(memory, cie, &cie_info->reg, &c)) {
-            return false;
-        }
-    } else {
-        if (!try_get_byte(memory, cie, (uint8_t*)&cie_info->reg, &c)) {
-            return false;
-        }
-    }
-    ALOGV("execute_fde: CIE code alignment factor: %d", cie_info->code_align);
-    ALOGV("execute_fde: CIE data alignment factor: %d", cie_info->data_align);
-    if (cie_info->aug_z) {
-        if (!try_get_uleb128(memory, cie, &cie_info->aug_z, &c)) {
-            return false;
-        }
-    }
-    if (cie_info->aug_L) {
-        if (!try_get_byte(memory, cie, &cie_info->aug_L, &c)) {
-            return false;
-        }
-    } else {
-        /* Default encoding. */
-        cie_info->aug_L = DW_EH_PE_absptr;
-    }
-    if (cie_info->aug_R) {
-        if (!try_get_byte(memory, cie, &cie_info->aug_R, &c)) {
-            return false;
-        }
-    } else {
-        /* Default encoding. */
-        cie_info->aug_R = DW_EH_PE_absptr;
-    }
-    if (cie_info->aug_P) {
-        /* Get encoding of personality routine pointer. We don't use it now. */
-        if (!try_get_byte(memory, cie, (uint8_t*)&cie_info->aug_P, &c)) {
-            return false;
-        }
-        /* Get routine pointer. */
-        if (!read_dwarf(memory, cie, &cie_info->aug_P, (uint8_t)cie_info->aug_P, &c)) {
-            return false;
-        }
-    }
-    /* CIE program. */
-    /* Length field itself (4 bytes) is not included into length. */
-    stack[0] = *dstate;
-    stack_ptr = 1;
-    while (c < cie_length + 4) {
-        if (!execute_dwarf(memory, cie, cie_info, dstate, &c, stack, &stack_ptr)) {
-           return false;
-        }
-    }
-
-    /* We went directly to CIE. Normally it shouldn't occur. */
-    if (cie == fde) return true;
-
-    /* Go back to FDE. */
-    c = 8;
-    /* Read FDE:
-       Augmentation independent:
-        next x bytes (encoded as specified in CIE) is FDE starting address;
-        next x bytes (encoded as specified in CIE) is FDE number of instructions covered;
-       Augmentation dependent:
-        if 'z' next x bytes is unsigned LEB128 encoded augmentation data size;
-        if 'L' next x bytes is LSDA pointer (encoded as specified in CIE);
-       Next x bytes is FDE program.
-     */
-    if (!read_dwarf(memory, fde, &fde_info->start, (uint8_t)cie_info->aug_R, &c)) {
-        return false;
-    }
-    dstate->loc = fde_info->start;
-    ALOGV("execute_fde: FDE start: %x", dstate->loc);
-    if (!read_dwarf(memory, fde, &fde_info->length, 0, &c)) {
-        return false;
-    }
-    ALOGV("execute_fde: FDE length: %x", fde_info->length);
-    if (cie_info->aug_z) {
-        if (!try_get_uleb128(memory, fde, &fde_info->aug_z, &c)) {
-            return false;
-        }
-    }
-    if (cie_info->aug_L && cie_info->aug_L != DW_EH_PE_omit) {
-        if (!read_dwarf(memory, fde, &fde_info->aug_L, cie_info->aug_L, &c)) {
-            return false;
-        }
-    }
-    /* FDE program. */
-    /* Length field itself (4 bytes) is not included into length. */
-    /* Save CIE state as 0 element of stack. Used by DW_CFA_restore. */
-    stack[0] = *dstate;
-    stack_ptr = 1;
-    while (c < fde_length + 4 && state->reg[DWARF_EIP] >= dstate->loc) {
-        if (!execute_dwarf(memory, fde, cie_info, dstate, &c, stack, &stack_ptr)) {
-           return false;
-        }
-        ALOGV("IP: %x, LOC: %x", state->reg[DWARF_EIP], dstate->loc);
-    }
-
-    return update_state(memory, state, dstate);
-}
-
-static ssize_t unwind_backtrace_common(const memory_t* memory,
-        const map_info_t* map_info_list,
-        unwind_state_t* state, backtrace_frame_t* backtrace,
-        size_t ignore_depth, size_t max_depth) {
-
-    size_t ignored_frames = 0;
-    size_t returned_frames = 0;
-
-    ALOGV("Unwinding tid: %d", memory->tid);
-    ALOGV("IP: %x", state->reg[DWARF_EIP]);
-    ALOGV("BP: %x", state->reg[DWARF_EBP]);
-    ALOGV("SP: %x", state->reg[DWARF_ESP]);
-
-    for (size_t index = 0; returned_frames < max_depth; index++) {
-        uintptr_t fde = find_fde(memory, map_info_list, state->reg[DWARF_EIP]);
-        /* FDE is not found, it may happen if stack is corrupted or calling wrong adress.
-           Getting return address from stack.
-        */
-        if (!fde) {
-            uint32_t ip;
-            ALOGV("trying to restore registers from stack");
-            if (!try_get_word(memory, state->reg[DWARF_EBP] + 4, &ip) ||
-                ip == state->reg[DWARF_EIP]) {
-                ALOGV("can't get IP from stack");
-                break;
-            }
-            /* We've been able to get IP from stack so recording the frame before continue. */
-            backtrace_frame_t* frame = add_backtrace_entry(
-                    index ? rewind_pc_arch(memory, state->reg[DWARF_EIP]) : state->reg[DWARF_EIP],
-                    backtrace, ignore_depth, max_depth,
-                    &ignored_frames, &returned_frames);
-            state->reg[DWARF_EIP] = ip;
-            state->reg[DWARF_ESP] = state->reg[DWARF_EBP] + 8;
-            if (!try_get_word(memory, state->reg[DWARF_EBP], &state->reg[DWARF_EBP])) {
-                ALOGV("can't get EBP from stack");
-                break;
-            }
-            ALOGV("restore IP: %x", state->reg[DWARF_EIP]);
-            ALOGV("restore BP: %x", state->reg[DWARF_EBP]);
-            ALOGV("restore SP: %x", state->reg[DWARF_ESP]);
-            continue;
-        }
-        backtrace_frame_t* frame = add_backtrace_entry(
-                index ? rewind_pc_arch(memory, state->reg[DWARF_EIP]) : state->reg[DWARF_EIP],
-                backtrace, ignore_depth, max_depth,
-                &ignored_frames, &returned_frames);
-
-        uint32_t stack_top = state->reg[DWARF_ESP];
-
-        if (!execute_fde(memory, fde, state)) break;
-
-        if (frame) {
-            frame->stack_top = stack_top;
-            if (stack_top < state->reg[DWARF_ESP]) {
-                frame->stack_size = state->reg[DWARF_ESP] - stack_top;
-            }
-        }
-        ALOGV("Stack: 0x%x ... 0x%x - %d bytes", frame->stack_top, state->reg[DWARF_ESP], frame->stack_size);
-    }
-    return returned_frames;
-}
-
-ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo __attribute__((unused)), void* sigcontext,
-        const map_info_t* map_info_list,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-    const ucontext_t* uc = (const ucontext_t*)sigcontext;
-
-    unwind_state_t state;
-#if defined(__APPLE__)
-    state.reg[DWARF_EBP] = uc->uc_mcontext->__ss.__ebp;
-    state.reg[DWARF_ESP] = uc->uc_mcontext->__ss.__esp;
-    state.reg[DWARF_EIP] = uc->uc_mcontext->__ss.__eip;
-#else
-    state.reg[DWARF_EBP] = uc->uc_mcontext.gregs[REG_EBP];
-    state.reg[DWARF_ESP] = uc->uc_mcontext.gregs[REG_ESP];
-    state.reg[DWARF_EIP] = uc->uc_mcontext.gregs[REG_EIP];
-#endif
-
-    memory_t memory;
-    init_memory(&memory, map_info_list);
-    return unwind_backtrace_common(&memory, map_info_list,
-            &state, backtrace, ignore_depth, max_depth);
-}
-
-ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-#if defined(__APPLE__)
-    return -1;
-#else
-    pt_regs_x86_t regs;
-    if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
-        return -1;
-    }
-
-    unwind_state_t state;
-    state.reg[DWARF_EBP] = regs.ebp;
-    state.reg[DWARF_EIP] = regs.eip;
-    state.reg[DWARF_ESP] = regs.esp;
-
-    memory_t memory;
-    init_memory_ptrace(&memory, tid);
-    return unwind_backtrace_common(&memory, context->map_info_list,
-            &state, backtrace, ignore_depth, max_depth);
-#endif
-}
diff --git a/libcorkscrew/arch-x86/dwarf.h b/libcorkscrew/arch-x86/dwarf.h
deleted file mode 100755
index 962fc55..0000000
--- a/libcorkscrew/arch-x86/dwarf.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Dwarf2 data encoding flags.
- */
-
-#define DW_EH_PE_absptr         0x00
-#define DW_EH_PE_omit           0xff
-#define DW_EH_PE_uleb128        0x01
-#define DW_EH_PE_udata2         0x02
-#define DW_EH_PE_udata4         0x03
-#define DW_EH_PE_udata8         0x04
-#define DW_EH_PE_sleb128        0x09
-#define DW_EH_PE_sdata2         0x0A
-#define DW_EH_PE_sdata4         0x0B
-#define DW_EH_PE_sdata8         0x0C
-#define DW_EH_PE_signed         0x08
-#define DW_EH_PE_pcrel          0x10
-#define DW_EH_PE_textrel        0x20
-#define DW_EH_PE_datarel        0x30
-#define DW_EH_PE_funcrel        0x40
-#define DW_EH_PE_aligned        0x50
-#define DW_EH_PE_indirect       0x80
-
-/*
- * Dwarf2 call frame instructions.
- */
-
-typedef enum {
-    DW_CFA_advance_loc = 0x40,
-    DW_CFA_offset = 0x80,
-    DW_CFA_restore = 0xc0,
-    DW_CFA_nop = 0x00,
-    DW_CFA_set_loc = 0x01,
-    DW_CFA_advance_loc1 = 0x02,
-    DW_CFA_advance_loc2 = 0x03,
-    DW_CFA_advance_loc4 = 0x04,
-    DW_CFA_offset_extended = 0x05,
-    DW_CFA_restore_extended = 0x06,
-    DW_CFA_undefined = 0x07,
-    DW_CFA_same_value = 0x08,
-    DW_CFA_register = 0x09,
-    DW_CFA_remember_state = 0x0a,
-    DW_CFA_restore_state = 0x0b,
-    DW_CFA_def_cfa = 0x0c,
-    DW_CFA_def_cfa_register = 0x0d,
-    DW_CFA_def_cfa_offset = 0x0e
-} dwarf_CFA;
-
-/*
- * eh_frame_hdr information.
-*/
-
-typedef struct {
-      uint8_t version;
-      uint8_t eh_frame_ptr_enc;
-      uint8_t fde_count_enc;
-      uint8_t fde_table_enc;
-      uintptr_t eh_frame_ptr;
-      uint32_t fde_count;
-} eh_frame_hdr_info_t;
-
-/*
- * CIE information.
-*/
-
-typedef struct {
-      uint8_t version;
-      uint32_t code_align;
-      uint32_t data_align;
-      uint32_t reg;
-      uint32_t aug_z;
-      uint8_t aug_L;
-      uint8_t aug_R;
-      uint8_t aug_S;
-      uint32_t aug_P;
-} cie_info_t;
-
-/*
- * FDE information.
-*/
-
-typedef struct {
-      uint32_t start;
-      uint32_t length; // number of instructions covered by FDE
-      uint32_t aug_z;
-      uint32_t aug_L;
-} fde_info_t;
-
-/*
- * Dwarf state.
-*/
-
-/* Stack of states: required for DW_CFA_remember_state/DW_CFA_restore_state
-   30 should be enough */
-#define DWARF_STATES_STACK 30
-
-typedef struct {
-    char rule;         // rule: o - offset(value); r - register(value)
-    uint32_t value;    // value
-} reg_rule_t;
-
-/* Dwarf preserved number of registers for x86. */
-
-#define DWARF_REGISTERS 17
-
-typedef struct {
-    uintptr_t loc;     // location (ip)
-    uint8_t cfa_reg;   // index of register where CFA location stored
-    intptr_t cfa_off;  // offset
-    reg_rule_t regs[DWARF_REGISTERS]; // dwarf preserved registers for x86
-} dwarf_state_t;
-
-/* DWARF registers we are caring about. */
-
-#define DWARF_EAX     0
-#define DWARF_ECX     1
-#define DWARF_EDX     2
-#define DWARF_EBX     3
-#define DWARF_ESP     4
-#define DWARF_EBP     5
-#define DWARF_ESI     6
-#define DWARF_EDI     7
-#define DWARF_EIP     8
-
-
diff --git a/libcorkscrew/arch-x86/ptrace-x86.c b/libcorkscrew/arch-x86/ptrace-x86.c
deleted file mode 100755
index 9c49b93..0000000
--- a/libcorkscrew/arch-x86/ptrace-x86.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2011 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 "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../ptrace-arch.h"
-
-#include <stddef.h>
-#include <elf.h>
-#include <cutils/log.h>
-
-static void load_eh_frame_hdr(pid_t pid, map_info_t* mi, uintptr_t *eh_frame_hdr) {
-    uint32_t elf_phoff;
-    uint32_t elf_phentsize_ehsize;
-    uint32_t elf_shentsize_phnum;
-    if (try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff)
-            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_ehsize),
-                    &elf_phentsize_ehsize)
-            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phnum),
-                    &elf_shentsize_phnum)) {
-        uint32_t elf_phentsize = elf_phentsize_ehsize >> 16;
-        uint32_t elf_phnum = elf_shentsize_phnum & 0xffff;
-        for (uint32_t i = 0; i < elf_phnum; i++) {
-            uintptr_t elf_phdr = mi->start + elf_phoff + i * elf_phentsize;
-            uint32_t elf_phdr_type;
-            if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_type), &elf_phdr_type)) {
-                break;
-            }
-            if (elf_phdr_type == PT_GNU_EH_FRAME) {
-                uint32_t elf_phdr_offset;
-                if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_offset),
-                        &elf_phdr_offset)) {
-                    break;
-                }
-                *eh_frame_hdr = mi->start + elf_phdr_offset;
-                ALOGV("Parsed .eh_frame_hdr info for %s: start=0x%08x", mi->name, *eh_frame_hdr);
-                return;
-            }
-        }
-    }
-    *eh_frame_hdr = 0;
-}
-
-void load_ptrace_map_info_data_arch(pid_t pid, map_info_t* mi, map_info_data_t* data) {
-    load_eh_frame_hdr(pid, mi, &data->eh_frame_hdr);
-}
-
-void free_ptrace_map_info_data_arch(map_info_t* mi __attribute__((unused)),
-                                    map_info_data_t* data __attribute__((unused))) {
-}
diff --git a/libcorkscrew/backtrace-arch.h b/libcorkscrew/backtrace-arch.h
deleted file mode 100644
index a46f80b..0000000
--- a/libcorkscrew/backtrace-arch.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/* Architecture dependent functions. */
-
-#ifndef _CORKSCREW_BACKTRACE_ARCH_H
-#define _CORKSCREW_BACKTRACE_ARCH_H
-
-#include "ptrace-arch.h"
-#include <corkscrew/backtrace.h>
-
-#include <signal.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Rewind the program counter by one instruction. */
-uintptr_t rewind_pc_arch(const memory_t* memory, uintptr_t pc);
-
-ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext,
-        const map_info_t* map_info_list,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth);
-
-ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_BACKTRACE_ARCH_H
diff --git a/libcorkscrew/backtrace-helper.c b/libcorkscrew/backtrace-helper.c
deleted file mode 100644
index bf9d3f3..0000000
--- a/libcorkscrew/backtrace-helper.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2011 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 "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "backtrace-helper.h"
-
-#include <cutils/log.h>
-
-backtrace_frame_t* add_backtrace_entry(uintptr_t pc, backtrace_frame_t* backtrace,
-        size_t ignore_depth, size_t max_depth,
-        size_t* ignored_frames, size_t* returned_frames) {
-    if (*ignored_frames < ignore_depth) {
-        *ignored_frames += 1;
-        return NULL;
-    }
-    if (*returned_frames >= max_depth) {
-        return NULL;
-    }
-    backtrace_frame_t* frame = &backtrace[*returned_frames];
-    frame->absolute_pc = pc;
-    frame->stack_top = 0;
-    frame->stack_size = 0;
-    *returned_frames += 1;
-    return frame;
-}
diff --git a/libcorkscrew/backtrace-helper.h b/libcorkscrew/backtrace-helper.h
deleted file mode 100644
index 4d8a874..0000000
--- a/libcorkscrew/backtrace-helper.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/* Backtrace helper functions. */
-
-#ifndef _CORKSCREW_BACKTRACE_HELPER_H
-#define _CORKSCREW_BACKTRACE_HELPER_H
-
-#include <corkscrew/backtrace.h>
-#include <sys/types.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Add a program counter to a backtrace if it will fit.
- * Returns the newly added frame, or NULL if none.
- */
-backtrace_frame_t* add_backtrace_entry(uintptr_t pc,
-        backtrace_frame_t* backtrace,
-        size_t ignore_depth, size_t max_depth,
-        size_t* ignored_frames, size_t* returned_frames);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_BACKTRACE_HELPER_H
diff --git a/libcorkscrew/backtrace.c b/libcorkscrew/backtrace.c
deleted file mode 100644
index f1dd61d..0000000
--- a/libcorkscrew/backtrace.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2011 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 "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "backtrace-arch.h"
-#include "backtrace-helper.h"
-#include "ptrace-arch.h"
-#include <corkscrew/map_info.h>
-#include <corkscrew/symbol_table.h>
-#include <corkscrew/ptrace.h>
-#include <corkscrew/demangle.h>
-
-#include <unistd.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <pthread.h>
-#include <unwind.h>
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-
-#define __USE_GNU // For dladdr(3) in glibc.
-#include <dlfcn.h>
-
-#if defined(__BIONIC__)
-
-// Bionic implements and exports gettid but only implements tgkill.
-extern int tgkill(int tgid, int tid, int sig);
-
-#elif defined(__APPLE__)
-
-#include <sys/syscall.h>
-
-// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
-static pid_t gettid() {
-  return syscall(SYS_thread_selfid);
-}
-
-#else
-
-// glibc doesn't implement or export either gettid or tgkill.
-
-#include <unistd.h>
-#include <sys/syscall.h>
-
-static pid_t gettid() {
-  return syscall(__NR_gettid);
-}
-
-static int tgkill(int tgid, int tid, int sig) {
-  return syscall(__NR_tgkill, tgid, tid, sig);
-}
-
-#endif
-
-typedef struct {
-    backtrace_frame_t* backtrace;
-    size_t ignore_depth;
-    size_t max_depth;
-    size_t ignored_frames;
-    size_t returned_frames;
-    memory_t memory;
-} backtrace_state_t;
-
-static _Unwind_Reason_Code unwind_backtrace_callback(struct _Unwind_Context* context, void* arg) {
-    backtrace_state_t* state = (backtrace_state_t*)arg;
-    uintptr_t pc = _Unwind_GetIP(context);
-    if (pc) {
-        // TODO: Get information about the stack layout from the _Unwind_Context.
-        //       This will require a new architecture-specific function to query
-        //       the appropriate registers.  Current callers of unwind_backtrace
-        //       don't need this information, so we won't bother collecting it just yet.
-        add_backtrace_entry(rewind_pc_arch(&state->memory, pc), state->backtrace,
-                state->ignore_depth, state->max_depth,
-                &state->ignored_frames, &state->returned_frames);
-    }
-    return state->returned_frames < state->max_depth ? _URC_NO_REASON : _URC_END_OF_STACK;
-}
-
-ssize_t unwind_backtrace(backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-    ALOGV("Unwinding current thread %d.", gettid());
-
-    map_info_t* milist = acquire_my_map_info_list();
-
-    backtrace_state_t state;
-    state.backtrace = backtrace;
-    state.ignore_depth = ignore_depth;
-    state.max_depth = max_depth;
-    state.ignored_frames = 0;
-    state.returned_frames = 0;
-    init_memory(&state.memory, milist);
-
-    _Unwind_Reason_Code rc = _Unwind_Backtrace(unwind_backtrace_callback, &state);
-
-    release_my_map_info_list(milist);
-
-    if (state.returned_frames) {
-        return state.returned_frames;
-    }
-    return rc == _URC_END_OF_STACK ? 0 : -1;
-}
-
-#ifdef CORKSCREW_HAVE_ARCH
-static const int32_t STATE_DUMPING = -1;
-static const int32_t STATE_DONE = -2;
-static const int32_t STATE_CANCEL = -3;
-
-static pthread_mutex_t g_unwind_signal_mutex = PTHREAD_MUTEX_INITIALIZER;
-static volatile struct {
-    int32_t tid_state;
-    const map_info_t* map_info_list;
-    backtrace_frame_t* backtrace;
-    size_t ignore_depth;
-    size_t max_depth;
-    size_t returned_frames;
-} g_unwind_signal_state;
-
-static void unwind_backtrace_thread_signal_handler(int n __attribute__((unused)), siginfo_t* siginfo, void* sigcontext) {
-    if (!android_atomic_acquire_cas(gettid(), STATE_DUMPING, &g_unwind_signal_state.tid_state)) {
-        g_unwind_signal_state.returned_frames = unwind_backtrace_signal_arch(
-                siginfo, sigcontext,
-                g_unwind_signal_state.map_info_list,
-                g_unwind_signal_state.backtrace,
-                g_unwind_signal_state.ignore_depth,
-                g_unwind_signal_state.max_depth);
-        android_atomic_release_store(STATE_DONE, &g_unwind_signal_state.tid_state);
-    } else {
-        ALOGV("Received spurious SIGURG on thread %d that was intended for thread %d.",
-                gettid(), android_atomic_acquire_load(&g_unwind_signal_state.tid_state));
-    }
-}
-#endif
-
-ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace,
-        size_t ignore_depth, size_t max_depth) {
-    if (tid == gettid()) {
-        return unwind_backtrace(backtrace, ignore_depth + 1, max_depth);
-    }
-
-    ALOGV("Unwinding thread %d from thread %d.", tid, gettid());
-
-    // TODO: there's no tgkill(2) on Mac OS, so we'd either need the
-    // mach_port_t or the pthread_t rather than the tid.
-#if defined(CORKSCREW_HAVE_ARCH) && !defined(__APPLE__)
-    struct sigaction act;
-    struct sigaction oact;
-    memset(&act, 0, sizeof(act));
-    act.sa_sigaction = unwind_backtrace_thread_signal_handler;
-    act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
-    sigemptyset(&act.sa_mask);
-
-    pthread_mutex_lock(&g_unwind_signal_mutex);
-    map_info_t* milist = acquire_my_map_info_list();
-
-    ssize_t frames = -1;
-    if (!sigaction(SIGURG, &act, &oact)) {
-        g_unwind_signal_state.map_info_list = milist;
-        g_unwind_signal_state.backtrace = backtrace;
-        g_unwind_signal_state.ignore_depth = ignore_depth;
-        g_unwind_signal_state.max_depth = max_depth;
-        g_unwind_signal_state.returned_frames = 0;
-        android_atomic_release_store(tid, &g_unwind_signal_state.tid_state);
-
-        // Signal the specific thread that we want to dump.
-        int32_t tid_state = tid;
-        if (tgkill(getpid(), tid, SIGURG)) {
-            ALOGV("Failed to send SIGURG to thread %d.", tid);
-        } else {
-            // Wait for the other thread to start dumping the stack, or time out.
-            int wait_millis = 250;
-            for (;;) {
-                tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state);
-                if (tid_state != tid) {
-                    break;
-                }
-                if (wait_millis--) {
-                    ALOGV("Waiting for thread %d to start dumping the stack...", tid);
-                    usleep(1000);
-                } else {
-                    ALOGV("Timed out waiting for thread %d to start dumping the stack.", tid);
-                    break;
-                }
-            }
-        }
-
-        // Try to cancel the dump if it has not started yet.
-        if (tid_state == tid) {
-            if (!android_atomic_acquire_cas(tid, STATE_CANCEL, &g_unwind_signal_state.tid_state)) {
-                ALOGV("Canceled thread %d stack dump.", tid);
-                tid_state = STATE_CANCEL;
-            } else {
-                tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state);
-            }
-        }
-
-        // Wait indefinitely for the dump to finish or be canceled.
-        // We cannot apply a timeout here because the other thread is accessing state that
-        // is owned by this thread, such as milist.  It should not take very
-        // long to take the dump once started.
-        while (tid_state == STATE_DUMPING) {
-            ALOGV("Waiting for thread %d to finish dumping the stack...", tid);
-            usleep(1000);
-            tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state);
-        }
-
-        if (tid_state == STATE_DONE) {
-            frames = g_unwind_signal_state.returned_frames;
-        }
-
-        sigaction(SIGURG, &oact, NULL);
-    }
-
-    release_my_map_info_list(milist);
-    pthread_mutex_unlock(&g_unwind_signal_mutex);
-    return frames;
-#else
-    return -1;
-#endif
-}
-
-ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context,
-        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-#ifdef CORKSCREW_HAVE_ARCH
-    return unwind_backtrace_ptrace_arch(tid, context, backtrace, ignore_depth, max_depth);
-#else
-    return -1;
-#endif
-}
-
-static void init_backtrace_symbol(backtrace_symbol_t* symbol, uintptr_t pc) {
-    symbol->relative_pc = pc;
-    symbol->relative_symbol_addr = 0;
-    symbol->map_name = NULL;
-    symbol->symbol_name = NULL;
-    symbol->demangled_name = NULL;
-}
-
-void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames,
-        backtrace_symbol_t* backtrace_symbols) {
-    map_info_t* milist = acquire_my_map_info_list();
-    for (size_t i = 0; i < frames; i++) {
-        const backtrace_frame_t* frame = &backtrace[i];
-        backtrace_symbol_t* symbol = &backtrace_symbols[i];
-        init_backtrace_symbol(symbol, frame->absolute_pc);
-
-        const map_info_t* mi = find_map_info(milist, frame->absolute_pc);
-        if (mi) {
-            symbol->relative_pc = frame->absolute_pc - mi->start;
-            if (mi->name[0]) {
-                symbol->map_name = strdup(mi->name);
-            }
-            Dl_info info;
-            if (dladdr((const void*)frame->absolute_pc, &info) && info.dli_sname) {
-                symbol->relative_symbol_addr = (uintptr_t)info.dli_saddr
-                        - (uintptr_t)info.dli_fbase;
-                symbol->symbol_name = strdup(info.dli_sname);
-                symbol->demangled_name = demangle_symbol_name(symbol->symbol_name);
-            }
-        }
-    }
-    release_my_map_info_list(milist);
-}
-
-void get_backtrace_symbols_ptrace(const ptrace_context_t* context,
-        const backtrace_frame_t* backtrace, size_t frames,
-        backtrace_symbol_t* backtrace_symbols) {
-    for (size_t i = 0; i < frames; i++) {
-        const backtrace_frame_t* frame = &backtrace[i];
-        backtrace_symbol_t* symbol = &backtrace_symbols[i];
-        init_backtrace_symbol(symbol, frame->absolute_pc);
-
-        const map_info_t* mi;
-        const symbol_t* s;
-        find_symbol_ptrace(context, frame->absolute_pc, &mi, &s);
-        if (mi) {
-            symbol->relative_pc = frame->absolute_pc - mi->start;
-            if (mi->name[0]) {
-                symbol->map_name = strdup(mi->name);
-            }
-        }
-        if (s) {
-            symbol->relative_symbol_addr = s->start;
-            symbol->symbol_name = strdup(s->name);
-            symbol->demangled_name = demangle_symbol_name(symbol->symbol_name);
-        }
-    }
-}
-
-void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames) {
-    for (size_t i = 0; i < frames; i++) {
-        backtrace_symbol_t* symbol = &backtrace_symbols[i];
-        free(symbol->map_name);
-        free(symbol->symbol_name);
-        free(symbol->demangled_name);
-        init_backtrace_symbol(symbol, 0);
-    }
-}
-
-void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame __attribute__((unused)),
-        const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize) {
-    const char* mapName = symbol->map_name ? symbol->map_name : "<unknown>";
-    const char* symbolName = symbol->demangled_name ? symbol->demangled_name : symbol->symbol_name;
-    int fieldWidth = (bufferSize - 80) / 2;
-    if (symbolName) {
-        uint32_t pc_offset = symbol->relative_pc - symbol->relative_symbol_addr;
-        if (pc_offset) {
-            snprintf(buffer, bufferSize, "#%02u  pc %08x  %.*s (%.*s+%u)",
-                    frameNumber, (unsigned int) symbol->relative_pc,
-                    fieldWidth, mapName, fieldWidth, symbolName, pc_offset);
-        } else {
-            snprintf(buffer, bufferSize, "#%02u  pc %08x  %.*s (%.*s)",
-                    frameNumber, (unsigned int) symbol->relative_pc,
-                    fieldWidth, mapName, fieldWidth, symbolName);
-        }
-    } else {
-        snprintf(buffer, bufferSize, "#%02u  pc %08x  %.*s",
-                frameNumber, (unsigned int) symbol->relative_pc,
-                fieldWidth, mapName);
-    }
-}
diff --git a/libcorkscrew/demangle.c b/libcorkscrew/demangle.c
deleted file mode 100644
index 30ab1b0..0000000
--- a/libcorkscrew/demangle.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2011 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 "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include <corkscrew/demangle.h>
-
-#include <cutils/log.h>
-
-extern char *__cxa_demangle (const char *mangled, char *buf, size_t *len,
-                             int *status);
-
-char* demangle_symbol_name(const char* name) {
-#if defined(__APPLE__)
-    // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
-    if (name != NULL && name[0] != '_') {
-        return NULL;
-    }
-#endif
-    // __cxa_demangle handles NULL by returning NULL
-    return __cxa_demangle(name, 0, 0, 0);
-}
diff --git a/libcorkscrew/map_info.c b/libcorkscrew/map_info.c
deleted file mode 100644
index 93dffbf..0000000
--- a/libcorkscrew/map_info.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2011 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 "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include <corkscrew/map_info.h>
-
-#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>
-
-#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 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);
-
-    map_info_t* mi = calloc(1, sizeof(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';
-        mi->data = NULL;
-        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;
-}
-
-map_info_t* load_map_info_list(pid_t pid) {
-    char cmd[1024];
-    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];
-    map_info_t* milist = NULL;
-    while (fgets(line, sizeof(line), fp) != NULL) {
-        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 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;
-    }
-
-    map_info_t* mi = calloc(1, sizeof(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';
-        mi->data = NULL;
-        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;
-}
-
-map_info_t* load_map_info_list(pid_t tid) {
-    char path[PATH_MAX];
-    char line[1024];
-    FILE* fp;
-    map_info_t* milist = NULL;
-
-    snprintf(path, PATH_MAX, "/proc/%d/maps", tid);
-    fp = fopen(path, "r");
-    if (fp) {
-        while(fgets(line, sizeof(line), fp)) {
-            map_info_t* mi = parse_maps_line(line);
-            if (mi) {
-                mi->next = milist;
-                milist = mi;
-            }
-        }
-        fclose(fp);
-    }
-    return milist;
-}
-
-#endif
-
-void free_map_info_list(map_info_t* milist) {
-    while (milist) {
-        map_info_t* next = milist->next;
-        free(milist);
-        milist = next;
-    }
-}
-
-const map_info_t* find_map_info(const map_info_t* milist, uintptr_t addr) {
-    const map_info_t* mi = milist;
-    while (mi && !(addr >= mi->start && addr < mi->end)) {
-        mi = mi->next;
-    }
-    return mi;
-}
-
-bool is_readable_map(const map_info_t* milist, uintptr_t addr) {
-    const map_info_t* mi = find_map_info(milist, addr);
-    return mi && mi->is_readable;
-}
-
-bool is_writable_map(const map_info_t* milist, uintptr_t addr) {
-    const map_info_t* mi = find_map_info(milist, addr);
-    return mi && mi->is_writable;
-}
-
-bool is_executable_map(const map_info_t* milist, uintptr_t addr) {
-    const map_info_t* mi = find_map_info(milist, addr);
-    return mi && mi->is_executable;
-}
-
-static pthread_mutex_t g_my_map_info_list_mutex = PTHREAD_MUTEX_INITIALIZER;
-static map_info_t* g_my_map_info_list = NULL;
-
-static const int64_t MAX_CACHE_AGE = 5 * 1000 * 1000000LL;
-
-typedef struct {
-    uint32_t refs;
-    int64_t timestamp;
-} my_map_info_data_t;
-
-static int64_t now_ns() {
-#if defined(HAVE_POSIX_CLOCKS)
-    struct timespec t;
-    t.tv_sec = t.tv_nsec = 0;
-    clock_gettime(CLOCK_MONOTONIC, &t);
-    return t.tv_sec * 1000000000LL + t.tv_nsec;
-#else
-    struct timeval t;
-    gettimeofday(&t, NULL);
-    return t.tv_sec * 1000000000LL + t.tv_usec * 1000LL;
-#endif
-}
-
-static void dec_ref(map_info_t* milist, my_map_info_data_t* data) {
-    if (!--data->refs) {
-        ALOGV("Freed my_map_info_list %p.", milist);
-        free(data);
-        free_map_info_list(milist);
-    }
-}
-
-map_info_t* acquire_my_map_info_list() {
-    pthread_mutex_lock(&g_my_map_info_list_mutex);
-
-    int64_t time = now_ns();
-    if (g_my_map_info_list != NULL) {
-        my_map_info_data_t* data = (my_map_info_data_t*)g_my_map_info_list->data;
-        int64_t age = time - data->timestamp;
-        if (age >= MAX_CACHE_AGE) {
-            ALOGV("Invalidated my_map_info_list %p, age=%lld.", g_my_map_info_list, age);
-            dec_ref(g_my_map_info_list, data);
-            g_my_map_info_list = NULL;
-        } else {
-            ALOGV("Reusing my_map_info_list %p, age=%lld.", g_my_map_info_list, age);
-        }
-    }
-
-    if (g_my_map_info_list == NULL) {
-        my_map_info_data_t* data = (my_map_info_data_t*)malloc(sizeof(my_map_info_data_t));
-        g_my_map_info_list = load_map_info_list(getpid());
-        if (g_my_map_info_list != NULL) {
-            ALOGV("Loaded my_map_info_list %p.", g_my_map_info_list);
-            g_my_map_info_list->data = data;
-            data->refs = 1;
-            data->timestamp = time;
-        } else {
-            free(data);
-        }
-    }
-
-    map_info_t* milist = g_my_map_info_list;
-    if (milist) {
-        my_map_info_data_t* data = (my_map_info_data_t*)g_my_map_info_list->data;
-        data->refs += 1;
-    }
-
-    pthread_mutex_unlock(&g_my_map_info_list_mutex);
-    return milist;
-}
-
-void release_my_map_info_list(map_info_t* milist) {
-    if (milist) {
-        pthread_mutex_lock(&g_my_map_info_list_mutex);
-
-        my_map_info_data_t* data = (my_map_info_data_t*)milist->data;
-        dec_ref(milist, data);
-
-        pthread_mutex_unlock(&g_my_map_info_list_mutex);
-    }
-}
-
-void flush_my_map_info_list() {
-    pthread_mutex_lock(&g_my_map_info_list_mutex);
-
-    if (g_my_map_info_list != NULL) {
-        my_map_info_data_t* data = (my_map_info_data_t*) g_my_map_info_list->data;
-        dec_ref(g_my_map_info_list, data);
-        g_my_map_info_list = NULL;
-    }
-
-    pthread_mutex_unlock(&g_my_map_info_list_mutex);
-}
diff --git a/libcorkscrew/ptrace-arch.h b/libcorkscrew/ptrace-arch.h
deleted file mode 100755
index 0bcff63..0000000
--- a/libcorkscrew/ptrace-arch.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/* Architecture dependent functions. */
-
-#ifndef _CORKSCREW_PTRACE_ARCH_H
-#define _CORKSCREW_PTRACE_ARCH_H
-
-#include <corkscrew/ptrace.h>
-#include <corkscrew/map_info.h>
-#include <corkscrew/symbol_table.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Custom extra data we stuff into map_info_t structures as part
- * of our ptrace_context_t. */
-typedef struct {
-#ifdef __arm__
-    uintptr_t exidx_start;
-    size_t exidx_size;
-#elif __mips__
-    uintptr_t eh_frame_hdr;
-#elif __i386__
-    uintptr_t eh_frame_hdr;
-#endif
-    symbol_table_t* symbol_table;
-} map_info_data_t;
-
-void load_ptrace_map_info_data_arch(pid_t pid, map_info_t* mi, map_info_data_t* data);
-void free_ptrace_map_info_data_arch(map_info_t* mi, map_info_data_t* data);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_PTRACE_ARCH_H
diff --git a/libcorkscrew/ptrace.c b/libcorkscrew/ptrace.c
deleted file mode 100644
index be58f7f..0000000
--- a/libcorkscrew/ptrace.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2011 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 "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "ptrace-arch.h"
-#include <corkscrew/ptrace.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/ptrace.h>
-#include <cutils/log.h>
-
-static const uint32_t ELF_MAGIC = 0x464C457f; // "ELF\0177"
-
-#ifndef PAGE_SIZE
-#define PAGE_SIZE 4096
-#endif
-
-#ifndef PAGE_MASK
-#define PAGE_MASK (~(PAGE_SIZE - 1))
-#endif
-
-void init_memory(memory_t* memory, const map_info_t* map_info_list) {
-    memory->tid = -1;
-    memory->map_info_list = map_info_list;
-}
-
-void init_memory_ptrace(memory_t* memory, pid_t tid) {
-    memory->tid = tid;
-    memory->map_info_list = NULL;
-}
-
-bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value) {
-    ALOGV("try_get_word: reading word at %p", (void*) ptr);
-    if (ptr & 3) {
-        ALOGV("try_get_word: invalid pointer %p", (void*) ptr);
-        *out_value = 0xffffffffL;
-        return false;
-    }
-    if (memory->tid < 0) {
-        if (!is_readable_map(memory->map_info_list, ptr)) {
-            ALOGV("try_get_word: pointer %p not in a readable map", (void*) ptr);
-            *out_value = 0xffffffffL;
-            return false;
-        }
-        *out_value = *(uint32_t*)ptr;
-        return true;
-    } else {
-#if defined(__APPLE__)
-        ALOGV("no ptrace on Mac OS");
-        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, memory->tid, (void*)ptr, NULL);
-        if (*out_value == 0xffffffffL && errno) {
-            ALOGV("try_get_word: invalid pointer 0x%08x reading from tid %d, "
-                    "ptrace() errno=%d", ptr, memory->tid, errno);
-            return false;
-        }
-        return true;
-#endif
-    }
-}
-
-bool try_get_word_ptrace(pid_t tid, uintptr_t ptr, uint32_t* out_value) {
-    memory_t memory;
-    init_memory_ptrace(&memory, tid);
-    return try_get_word(&memory, ptr, out_value);
-}
-
-static void load_ptrace_map_info_data(pid_t pid, map_info_t* mi) {
-    if (mi->is_executable && mi->is_readable) {
-        uint32_t elf_magic;
-        if (try_get_word_ptrace(pid, mi->start, &elf_magic) && elf_magic == ELF_MAGIC) {
-            map_info_data_t* data = (map_info_data_t*)calloc(1, sizeof(map_info_data_t));
-            if (data) {
-                mi->data = data;
-                if (mi->name[0]) {
-                    data->symbol_table = load_symbol_table(mi->name);
-                }
-#ifdef CORKSCREW_HAVE_ARCH
-                load_ptrace_map_info_data_arch(pid, mi, data);
-#endif
-            }
-        }
-    }
-}
-
-ptrace_context_t* load_ptrace_context(pid_t pid) {
-    ptrace_context_t* context =
-            (ptrace_context_t*)calloc(1, sizeof(ptrace_context_t));
-    if (context) {
-        context->map_info_list = load_map_info_list(pid);
-        for (map_info_t* mi = context->map_info_list; mi; mi = mi->next) {
-            load_ptrace_map_info_data(pid, mi);
-        }
-    }
-    return context;
-}
-
-static void free_ptrace_map_info_data(map_info_t* mi) {
-    map_info_data_t* data = (map_info_data_t*)mi->data;
-    if (data) {
-        if (data->symbol_table) {
-            free_symbol_table(data->symbol_table);
-        }
-#ifdef CORKSCREW_HAVE_ARCH
-        free_ptrace_map_info_data_arch(mi, data);
-#endif
-        free(data);
-        mi->data = NULL;
-    }
-}
-
-void free_ptrace_context(ptrace_context_t* context) {
-    for (map_info_t* mi = context->map_info_list; mi; mi = mi->next) {
-        free_ptrace_map_info_data(mi);
-    }
-    free_map_info_list(context->map_info_list);
-    free(context);
-}
-
-void find_symbol_ptrace(const ptrace_context_t* context,
-        uintptr_t addr, const map_info_t** out_map_info, const symbol_t** out_symbol) {
-    const map_info_t* mi = find_map_info(context->map_info_list, addr);
-    const symbol_t* symbol = NULL;
-    if (mi) {
-        const map_info_data_t* data = (const map_info_data_t*)mi->data;
-        if (data && data->symbol_table) {
-            symbol = find_symbol(data->symbol_table, addr - mi->start);
-        }
-    }
-    *out_map_info = mi;
-    *out_symbol = symbol;
-}
diff --git a/libcorkscrew/symbol_table.c b/libcorkscrew/symbol_table.c
deleted file mode 100644
index 982ccc8..0000000
--- a/libcorkscrew/symbol_table.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2011 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 "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include <corkscrew/symbol_table.h>
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <cutils/log.h>
-
-#if defined(__APPLE__)
-#else
-
-#include <elf.h>
-
-static bool is_elf(Elf32_Ehdr* e) {
-    return (e->e_ident[EI_MAG0] == ELFMAG0 &&
-            e->e_ident[EI_MAG1] == ELFMAG1 &&
-            e->e_ident[EI_MAG2] == ELFMAG2 &&
-            e->e_ident[EI_MAG3] == ELFMAG3);
-}
-
-#endif
-
-// Compare function for qsort
-static int qcompar(const void *a, const void *b) {
-    const symbol_t* asym = (const symbol_t*)a;
-    const symbol_t* bsym = (const symbol_t*)b;
-    if (asym->start > bsym->start) return 1;
-    if (asym->start < bsym->start) return -1;
-    return 0;
-}
-
-// Compare function for bsearch
-static int bcompar(const void *key, const void *element) {
-    uintptr_t addr = *(const uintptr_t*)key;
-    const symbol_t* symbol = (const symbol_t*)element;
-    if (addr < symbol->start) return -1;
-    if (addr >= symbol->end) return 1;
-    return 0;
-}
-
-symbol_table_t* load_symbol_table(const char *filename) {
-    symbol_table_t* table = NULL;
-#if !defined(__APPLE__)
-    ALOGV("Loading symbol table from '%s'.", filename);
-
-    int fd = open(filename, O_RDONLY);
-    if (fd < 0) {
-        goto out;
-    }
-
-    struct stat sb;
-    if (fstat(fd, &sb)) {
-        goto out_close;
-    }
-
-    size_t length = sb.st_size;
-    char* base = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
-    if (base == MAP_FAILED) {
-        goto out_close;
-    }
-
-    // Parse the file header
-    Elf32_Ehdr *hdr = (Elf32_Ehdr*)base;
-    if (!is_elf(hdr)) {
-        goto out_close;
-    }
-    Elf32_Shdr *shdr = (Elf32_Shdr*)(base + hdr->e_shoff);
-
-    // Search for the dynamic symbols section
-    int sym_idx = -1;
-    int dynsym_idx = -1;
-    for (Elf32_Half i = 0; i < hdr->e_shnum; i++) {
-        if (shdr[i].sh_type == SHT_SYMTAB) {
-            sym_idx = i;
-        }
-        if (shdr[i].sh_type == SHT_DYNSYM) {
-            dynsym_idx = i;
-        }
-    }
-    if (dynsym_idx == -1 && sym_idx == -1) {
-        goto out_unmap;
-    }
-
-    table = malloc(sizeof(symbol_table_t));
-    if(!table) {
-        goto out_unmap;
-    }
-    table->num_symbols = 0;
-
-    Elf32_Sym *dynsyms = NULL;
-    int dynnumsyms = 0;
-    char *dynstr = NULL;
-    if (dynsym_idx != -1) {
-        dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset);
-        dynnumsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize;
-        int dynstr_idx = shdr[dynsym_idx].sh_link;
-        dynstr = base + shdr[dynstr_idx].sh_offset;
-    }
-
-    Elf32_Sym *syms = NULL;
-    int numsyms = 0;
-    char *str = NULL;
-    if (sym_idx != -1) {
-        syms = (Elf32_Sym*)(base + shdr[sym_idx].sh_offset);
-        numsyms = shdr[sym_idx].sh_size / shdr[sym_idx].sh_entsize;
-        int str_idx = shdr[sym_idx].sh_link;
-        str = base + shdr[str_idx].sh_offset;
-    }
-
-    int dynsymbol_count = 0;
-    if (dynsym_idx != -1) {
-        // Iterate through the dynamic symbol table, and count how many symbols
-        // are actually defined
-        for (int i = 0; i < dynnumsyms; i++) {
-            if (dynsyms[i].st_shndx != SHN_UNDEF) {
-                dynsymbol_count++;
-            }
-        }
-    }
-
-    size_t symbol_count = 0;
-    if (sym_idx != -1) {
-        // Iterate through the symbol table, and count how many symbols
-        // are actually defined
-        for (int i = 0; i < numsyms; i++) {
-            if (syms[i].st_shndx != SHN_UNDEF
-                    && str[syms[i].st_name]
-                    && syms[i].st_value
-                    && syms[i].st_size) {
-                symbol_count++;
-            }
-        }
-    }
-
-    // Now, create an entry in our symbol table structure for each symbol...
-    table->num_symbols += symbol_count + dynsymbol_count;
-    table->symbols = malloc(table->num_symbols * sizeof(symbol_t));
-    if (!table->symbols) {
-        free(table);
-        table = NULL;
-        goto out_unmap;
-    }
-
-    size_t symbol_index = 0;
-    if (dynsym_idx != -1) {
-        // ...and populate them
-        for (int i = 0; i < dynnumsyms; i++) {
-            if (dynsyms[i].st_shndx != SHN_UNDEF) {
-                table->symbols[symbol_index].name = strdup(dynstr + dynsyms[i].st_name);
-                table->symbols[symbol_index].start = dynsyms[i].st_value;
-                table->symbols[symbol_index].end = dynsyms[i].st_value + dynsyms[i].st_size;
-                ALOGV("  [%d] '%s' 0x%08x-0x%08x (DYNAMIC)",
-                        symbol_index, table->symbols[symbol_index].name,
-                        table->symbols[symbol_index].start, table->symbols[symbol_index].end);
-                symbol_index += 1;
-            }
-        }
-    }
-
-    if (sym_idx != -1) {
-        // ...and populate them
-        for (int i = 0; i < numsyms; i++) {
-            if (syms[i].st_shndx != SHN_UNDEF
-                    && str[syms[i].st_name]
-                    && syms[i].st_value
-                    && syms[i].st_size) {
-                table->symbols[symbol_index].name = strdup(str + syms[i].st_name);
-                table->symbols[symbol_index].start = syms[i].st_value;
-                table->symbols[symbol_index].end = syms[i].st_value + syms[i].st_size;
-                ALOGV("  [%d] '%s' 0x%08x-0x%08x",
-                        symbol_index, table->symbols[symbol_index].name,
-                        table->symbols[symbol_index].start, table->symbols[symbol_index].end);
-                symbol_index += 1;
-            }
-        }
-    }
-
-    // Sort the symbol table entries, so they can be bsearched later
-    qsort(table->symbols, table->num_symbols, sizeof(symbol_t), qcompar);
-
-out_unmap:
-    munmap(base, length);
-
-out_close:
-    close(fd);
-#endif
-
-out:
-    return table;
-}
-
-void free_symbol_table(symbol_table_t* table) {
-    if (table) {
-        for (size_t i = 0; i < table->num_symbols; i++) {
-            free(table->symbols[i].name);
-        }
-        free(table->symbols);
-        free(table);
-    }
-}
-
-const symbol_t* find_symbol(const symbol_table_t* table, uintptr_t addr) {
-    if (!table) return NULL;
-    return (const symbol_t*)bsearch(&addr, table->symbols, table->num_symbols,
-            sizeof(symbol_t), bcompar);
-}
diff --git a/libcorkscrew/test.cpp b/libcorkscrew/test.cpp
deleted file mode 100644
index 22dfa7d..0000000
--- a/libcorkscrew/test.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#include <corkscrew/backtrace.h>
-#include <corkscrew/symbol_table.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int do_backtrace(float /* just to test demangling */) {
-  const size_t MAX_DEPTH = 32;
-  backtrace_frame_t* frames = (backtrace_frame_t*) malloc(sizeof(backtrace_frame_t) * MAX_DEPTH);
-  ssize_t frame_count = unwind_backtrace(frames, 0, MAX_DEPTH);
-  fprintf(stderr, "frame_count=%d\n", (int) frame_count);
-  if (frame_count <= 0) {
-    return frame_count;
-  }
-
-  backtrace_symbol_t* backtrace_symbols = (backtrace_symbol_t*) malloc(sizeof(backtrace_symbol_t) * frame_count);
-  get_backtrace_symbols(frames, frame_count, backtrace_symbols);
-
-  for (size_t i = 0; i < (size_t) frame_count; ++i) {
-    char line[MAX_BACKTRACE_LINE_LENGTH];
-    format_backtrace_line(i, &frames[i], &backtrace_symbols[i],
-                          line, MAX_BACKTRACE_LINE_LENGTH);
-    if (backtrace_symbols[i].symbol_name != NULL) {
-      // get_backtrace_symbols found the symbol's name with dladdr(3).
-      fprintf(stderr, "  %s\n", line);
-    } else {
-      // We don't have a symbol. Maybe this is a static symbol, and
-      // we can look it up?
-      symbol_table_t* symbols = NULL;
-      if (backtrace_symbols[i].map_name != NULL) {
-        symbols = load_symbol_table(backtrace_symbols[i].map_name);
-      }
-      const symbol_t* symbol = NULL;
-      if (symbols != NULL) {
-        symbol = find_symbol(symbols, frames[i].absolute_pc);
-      }
-      if (symbol != NULL) {
-        int offset = frames[i].absolute_pc - symbol->start;
-        fprintf(stderr, "  %s (%s%+d)\n", line, symbol->name, offset);
-      } else {
-        fprintf(stderr, "  %s (\?\?\?)\n", line);
-      }
-      free_symbol_table(symbols);
-    }
-  }
-
-  free_backtrace_symbols(backtrace_symbols, frame_count);
-  free(backtrace_symbols);
-  free(frames);
-  return frame_count;
-}
-
-struct C {
-  int g(int i);
-};
-
-__attribute__ ((noinline)) int C::g(int i) {
-  if (i == 0) {
-    return do_backtrace(0.1);
-  }
-  return g(i - 1);
-}
-
-extern "C" __attribute__ ((noinline)) int f() {
-  C c;
-  return c.g(5);
-}
-
-int main() {
-  flush_my_map_info_list();
-  f();
-
-  flush_my_map_info_list();
-  f();
-
-  return 0;
-}
diff --git a/libcutils/debugger.c b/libcutils/debugger.c
index 7d907fc..056de5d 100644
--- a/libcutils/debugger.c
+++ b/libcutils/debugger.c
@@ -15,6 +15,7 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include <cutils/debugger.h>
@@ -28,9 +29,9 @@
     }
 
     debugger_msg_t msg;
+    memset(&msg, 0, sizeof(msg));
     msg.tid = tid;
     msg.action = DEBUGGER_ACTION_DUMP_TOMBSTONE;
-    msg.abort_msg_address = 0;
 
     int result = 0;
     if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
@@ -62,9 +63,9 @@
     }
 
     debugger_msg_t msg;
+    memset(&msg, 0, sizeof(msg));
     msg.tid = tid;
     msg.action = DEBUGGER_ACTION_DUMP_BACKTRACE;
-    msg.abort_msg_address = 0;
 
     int result = 0;
     if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
diff --git a/liblog/Android.mk b/liblog/Android.mk
index a23de2d..5e01903 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -22,10 +22,6 @@
 liblog_sources := logd_write_kern.c
 endif
 
-ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
-liblog_cflags := -DUSERDEBUG_BUILD=1
-endif
-
 # some files must not be compiled when building against Mingw
 # they correspond to features not used by our host development tools
 # which are also hard or even impossible to port to native Win32
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 2dd07e6..11fe848 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -17,6 +17,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <poll.h>
 #include <signal.h>
 #include <stddef.h>
 #define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
@@ -196,7 +197,8 @@
     [LOG_ID_MAIN] = "main",
     [LOG_ID_RADIO] = "radio",
     [LOG_ID_EVENTS] = "events",
-    [LOG_ID_SYSTEM] = "system"
+    [LOG_ID_SYSTEM] = "system",
+    [LOG_ID_CRASH] = "crash",
 };
 
 const char *android_log_id_to_name(log_id_t log_id)
@@ -272,6 +274,8 @@
                             const char *msg, char *buf, size_t buf_size)
 {
     ssize_t ret;
+    size_t len;
+    char *cp;
     int errno_save = 0;
     int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
                                    SOCK_STREAM);
@@ -283,12 +287,44 @@
         snprintf(buf, buf_size, msg, logger ? logger->id : (unsigned) -1);
     }
 
-    ret = write(sock, buf, strlen(buf) + 1);
+    len = strlen(buf) + 1;
+    ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
     if (ret <= 0) {
         goto done;
     }
 
-    ret = read(sock, buf, buf_size);
+    len = buf_size;
+    cp = buf;
+    while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
+        struct pollfd p;
+
+        if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
+            break;
+        }
+
+        len -= ret;
+        cp += ret;
+
+        memset(&p, 0, sizeof(p));
+        p.fd = sock;
+        p.events = POLLIN;
+
+        /* Give other side 20ms to refill pipe */
+        ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
+
+        if (ret <= 0) {
+            break;
+        }
+
+        if (!(p.revents & POLLIN)) {
+            ret = 0;
+            break;
+        }
+    }
+
+    if (ret >= 0) {
+        ret += buf_size - len;
+    }
 
 done:
     if ((ret == -1) && errno) {
@@ -340,8 +376,6 @@
     return atol(buf);
 }
 
-#ifdef USERDEBUG_BUILD
-
 int android_logger_set_log_size(struct logger *logger, unsigned long size)
 {
     char buf[512];
@@ -352,8 +386,6 @@
     return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
 }
 
-#endif /* USERDEBUG_BUILD */
-
 /*
  * returns the readable size of the log's ring buffer (that is, amount of the
  * log consumed)
@@ -408,8 +440,6 @@
     return send_log_msg(NULL, NULL, buf, len);
 }
 
-#ifdef USERDEBUG_BUILD
-
 ssize_t android_logger_get_prune_list(struct logger_list *logger_list UNUSED,
                                       char *buf, size_t len)
 {
@@ -432,8 +462,6 @@
     return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
 }
 
-#endif /* USERDEBUG_BUILD */
-
 struct logger_list *android_logger_list_alloc(int mode,
                                               unsigned int tail,
                                               pid_t pid)
diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c
index 9cccb1d..021fe47 100644
--- a/liblog/log_read_kern.c
+++ b/liblog/log_read_kern.c
@@ -58,7 +58,8 @@
     [LOG_ID_MAIN] = "main",
     [LOG_ID_RADIO] = "radio",
     [LOG_ID_EVENTS] = "events",
-    [LOG_ID_SYSTEM] = "system"
+    [LOG_ID_SYSTEM] = "system",
+    [LOG_ID_CRASH] = "crash"
 };
 
 const char *android_log_id_to_name(log_id_t log_id)
@@ -232,16 +233,12 @@
     return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
 }
 
-#ifdef USERDEBUG_BUILD
-
 int android_logger_set_log_size(struct logger *logger UNUSED,
                                 unsigned long size UNUSED)
 {
     return -ENOTSUP;
 }
 
-#endif /* USERDEBUG_BUILD */
-
 /*
  * returns the readable size of the log's ring buffer (that is, amount of the
  * log consumed)
@@ -272,8 +269,6 @@
     return -ENOTSUP;
 }
 
-#ifdef USERDEBUG_BUILD
-
 ssize_t android_logger_get_prune_list(struct logger_list *logger_list UNUSED,
                                       char *buf, size_t len)
 {
@@ -289,8 +284,6 @@
     return -ENOTSUP;
 }
 
-#endif /* USERDEBUG_BUILD */
-
 struct logger_list *android_logger_list_alloc(int mode,
                                               unsigned int tail,
                                               pid_t pid)
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 9c73dad..bd36a65 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -54,7 +54,7 @@
 static int logd_fd = -1;
 #if FAKE_LOG_DEVICE
 #define WEAK __attribute__((weak))
-static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 };
+static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
 #endif
 
 /*
@@ -146,9 +146,15 @@
             ret = -errno;
         }
     } while (ret == -EINTR);
-
-    return ret;
 #else
+    static const unsigned header_length = 3;
+    struct iovec newVec[nr + header_length];
+    typeof_log_id_t log_id_buf;
+    uint16_t tid;
+    struct timespec ts;
+    log_time realtime_ts;
+    size_t i, payload_size;
+
     if (getuid() == AID_LOGD) {
         /*
          * ignore log messages we send to ourself.
@@ -181,29 +187,33 @@
      *      };
      *  };
      */
-    static const unsigned header_length = 3;
-    struct iovec newVec[nr + header_length];
-    typeof_log_id_t log_id_buf = log_id;
-    uint16_t tid = gettid();
+
+    log_id_buf = log_id;
+    tid = gettid();
 
     newVec[0].iov_base   = (unsigned char *) &log_id_buf;
     newVec[0].iov_len    = sizeof_log_id_t;
     newVec[1].iov_base   = (unsigned char *) &tid;
     newVec[1].iov_len    = sizeof(tid);
 
-    struct timespec ts;
     clock_gettime(CLOCK_REALTIME, &ts);
-    log_time realtime_ts;
     realtime_ts.tv_sec = ts.tv_sec;
     realtime_ts.tv_nsec = ts.tv_nsec;
 
     newVec[2].iov_base   = (unsigned char *) &realtime_ts;
     newVec[2].iov_len    = sizeof(log_time);
 
-    size_t i;
-    for (i = header_length; i < nr + header_length; i++) {
-        newVec[i].iov_base = vec[i-header_length].iov_base;
-        newVec[i].iov_len  = vec[i-header_length].iov_len;
+    for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
+        newVec[i].iov_base = vec[i - header_length].iov_base;
+        payload_size += newVec[i].iov_len = vec[i - header_length].iov_len;
+
+        if (payload_size > LOGGER_ENTRY_MAX_PAYLOAD) {
+            newVec[i].iov_len -= payload_size - LOGGER_ENTRY_MAX_PAYLOAD;
+            if (newVec[i].iov_len) {
+                ++i;
+            }
+            break;
+        }
     }
 
     /*
@@ -212,7 +222,7 @@
      * ENOTCONN occurs if logd dies.
      * EAGAIN occurs if logd is overloaded.
      */
-    ret = writev(logd_fd, newVec, nr + header_length);
+    ret = writev(logd_fd, newVec, i);
     if (ret < 0) {
         ret = -errno;
         if (ret == -ENOTCONN) {
@@ -234,8 +244,13 @@
             }
         }
     }
-    return ret;
+
+    if (ret > (ssize_t)(sizeof_log_id_t + sizeof(tid) + sizeof(log_time))) {
+        ret -= sizeof_log_id_t + sizeof(tid) + sizeof(log_time);
+    }
 #endif
+
+    return ret;
 }
 
 #if FAKE_LOG_DEVICE
@@ -243,7 +258,8 @@
     [LOG_ID_MAIN] = "main",
     [LOG_ID_RADIO] = "radio",
     [LOG_ID_EVENTS] = "events",
-    [LOG_ID_SYSTEM] = "system"
+    [LOG_ID_SYSTEM] = "system",
+    [LOG_ID_CRASH] = "crash"
 };
 
 const WEAK char *android_log_id_to_name(log_id_t log_id)
@@ -406,9 +422,15 @@
             strcpy(buf, "Unspecified assertion failed");
     }
 
+#if __BIONIC__
+    // Ensure debuggerd gets to see what went wrong by keeping the C library in the loop.
+    extern __noreturn void __android_fatal(const char* tag, const char* format, ...) __printflike(2, 3);
+    __android_fatal(tag ? tag : "", "%s", buf);
+#else
     __android_log_write(ANDROID_LOG_FATAL, tag, buf);
-
     __builtin_trap(); /* trap so we have a chance to debug the situation */
+#endif
+    /* NOTREACHED */
 }
 
 int __android_log_bwrite(int32_t tag, const void *payload, size_t len)
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index 5ef349b..8c707ad 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -93,6 +93,9 @@
     int log_fd;
 
     if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
+        if (log_id == LOG_ID_CRASH) {
+            log_id = LOG_ID_MAIN;
+        }
         log_fd = log_fds[(int)log_id];
     } else {
         return -EBADF;
@@ -269,9 +272,15 @@
             strcpy(buf, "Unspecified assertion failed");
     }
 
+#if __BIONIC__
+    // Ensure debuggerd gets to see what went wrong by keeping the C library in the loop.
+    extern __noreturn void __android_fatal(const char* tag, const char* format, ...) __printflike(2, 3);
+    __android_fatal(tag ? tag : "", "%s", buf);
+#else
     __android_log_write(ANDROID_LOG_FATAL, tag, buf);
-
     __builtin_trap(); /* trap so we have a chance to debug the situation */
+#endif
+    /* NOTREACHED */
 }
 
 int __android_log_bwrite(int32_t tag, const void *payload, size_t len)
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index db06cf7..d1d9115 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -32,7 +32,7 @@
 
 benchmark_src_files := \
     benchmark_main.cpp \
-    liblog_benchmark.cpp \
+    liblog_benchmark.cpp
 
 # Build benchmarks for the device. Run with:
 #   adb shell liblog-benchmarks
@@ -59,10 +59,22 @@
     -g \
     -Wall -Wextra \
     -Werror \
-    -fno-builtin \
+    -fno-builtin
 
 test_src_files := \
-    liblog_test.cpp \
+    liblog_test.cpp
+
+# to prevent breaking the build if bionic not relatively visible to us
+ifneq ($(wildcard $(LOCAL_PATH)/../../../../bionic/libc/bionic/libc_logging.cpp),)
+
+test_src_files += \
+    libc_test.cpp
+
+ifndef ($(TARGET_USES_LOGD),false)
+test_c_flags += -DTARGET_USES_LOGD
+endif
+
+endif
 
 # Build tests for the device (with .so). Run with:
 #   adb shell /data/nativetest/liblog-unit-tests/liblog-unit-tests
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
new file mode 100644
index 0000000..0abc375
--- /dev/null
+++ b/liblog/tests/libc_test.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <sys/cdefs.h>
+
+#include <gtest/gtest.h>
+
+// Should be in bionic test suite, *but* we are using liblog to confirm
+// end-to-end logging, so let the overly cute oedipus complex begin ...
+#include "../../../../bionic/libc/bionic/libc_logging.cpp" // not Standalone
+#define _ANDROID_LOG_H // Priorities redefined
+#define _LIBS_LOG_LOG_H // log ids redefined
+typedef unsigned char log_id_t; // log_id_t missing as a result
+#ifdef TARGET_USES_LOGD
+#define _LIBS_LOG_LOG_READ_H // log_time redefined
+#endif
+
+#include <log/log.h>
+#include <log/logger.h>
+#include <log/log_read.h>
+
+TEST(libc, __libc_android_log_event_int) {
+    struct logger_list *logger_list;
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid)));
+
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    int value = ts.tv_nsec;
+
+    __libc_android_log_event_int(0, value);
+    usleep(1000000);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        ASSERT_EQ(log_msg.entry.pid, pid);
+
+        if ((log_msg.entry.len != (4 + 1 + 4))
+         || ((int)log_msg.id() != LOG_ID_EVENTS)) {
+            continue;
+        }
+
+        char *eventData = log_msg.msg();
+
+        int incoming = (eventData[0] & 0xFF) |
+                      ((eventData[1] & 0xFF) << 8) |
+                      ((eventData[2] & 0xFF) << 16) |
+                      ((eventData[3] & 0xFF) << 24);
+
+        if (incoming != 0) {
+            continue;
+        }
+
+        if (eventData[4] != EVENT_TYPE_INT) {
+            continue;
+        }
+
+        incoming = (eventData[4 + 1 + 0] & 0xFF) |
+                  ((eventData[4 + 1 + 1] & 0xFF) << 8) |
+                  ((eventData[4 + 1 + 2] & 0xFF) << 16) |
+                  ((eventData[4 + 1 + 3] & 0xFF) << 24);
+
+        if (incoming == value) {
+            ++count;
+        }
+    }
+
+    EXPECT_EQ(1, count);
+
+    android_logger_list_close(logger_list);
+}
+
+TEST(libc, __libc_fatal_no_abort) {
+    struct logger_list *logger_list;
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        (log_id_t)LOG_ID_MAIN, O_RDONLY | O_NDELAY, 1000, pid)));
+
+    char b[80];
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+
+    __libc_fatal_no_abort("%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
+    snprintf(b, sizeof(b),"%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
+    usleep(1000000);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        ASSERT_EQ(log_msg.entry.pid, pid);
+
+        if ((int)log_msg.id() != LOG_ID_MAIN) {
+            continue;
+        }
+
+        char *data = log_msg.msg();
+
+        if ((*data == ANDROID_LOG_FATAL)
+                && !strcmp(data + 1, "libc")
+                && !strcmp(data + 1 + strlen(data + 1) + 1, b)) {
+            ++count;
+        }
+    }
+
+    EXPECT_EQ(1, count);
+
+    android_logger_list_close(logger_list);
+}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index d726f2d..92b68ac 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -482,11 +482,68 @@
         }
     }
 
+    android_logger_list_close(logger_list);
+
     EXPECT_EQ(true, matches);
 
-    EXPECT_LE(sizeof(max_payload_buf), max_len);
+    EXPECT_LE(sizeof(max_payload_buf), static_cast<size_t>(max_len));
+}
+
+TEST(liblog, too_big_payload) {
+    pid_t pid = getpid();
+    static const char big_payload_tag[] = "TEST_big_payload_XXXX";
+    char tag[sizeof(big_payload_tag)];
+    memcpy(tag, big_payload_tag, sizeof(tag));
+    snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
+
+    std::string longString(3266519, 'x');
+
+    ssize_t ret = LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM,
+                                    ANDROID_LOG_INFO, tag, longString.c_str()));
+
+    struct logger_list *logger_list;
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_SYSTEM, O_RDONLY | O_NDELAY, 100, 0)));
+
+    ssize_t max_len = 0;
+
+    for(;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        if ((log_msg.entry.pid != pid) || (log_msg.id() != LOG_ID_SYSTEM)) {
+            continue;
+        }
+
+        char *data = log_msg.msg() + 1;
+
+        if (strcmp(data, tag)) {
+            continue;
+        }
+
+        data += strlen(data) + 1;
+
+        const char *left = data;
+        const char *right = longString.c_str();
+        while (*left && *right && (*left == *right)) {
+            ++left;
+            ++right;
+        }
+
+        if (max_len <= (left - data)) {
+            max_len = left - data + 1;
+        }
+    }
 
     android_logger_list_close(logger_list);
+
+    EXPECT_LE(LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag),
+              static_cast<size_t>(max_len));
+
+    EXPECT_EQ(ret, max_len + sizeof(big_payload_tag));
 }
 
 TEST(liblog, dual_reader) {
diff --git a/libpixelflinger/codeflinger/disassem.c b/libpixelflinger/codeflinger/disassem.c
index aeb8034..39dd614 100644
--- a/libpixelflinger/codeflinger/disassem.c
+++ b/libpixelflinger/codeflinger/disassem.c
@@ -301,19 +301,14 @@
 static void disassemble_printaddr(u_int address);
 
 u_int
-disasm(const disasm_interface_t *di, u_int loc, int altfmt)
+disasm(const disasm_interface_t *di, u_int loc, int __unused altfmt)
 {
 	const struct arm32_insn *i_ptr = &arm32_i[0];
-
-	u_int insn;
-	int matchp;
+	u_int insn = di->di_readword(loc);
+	int matchp = 0;
 	int branch;
 	char* f_ptr;
-	int fmt;
-
-	fmt = 0;
-	matchp = 0;
-	insn = di->di_readword(loc);
+	int fmt = 0;
 
 /*	di->di_printf("loc=%08x insn=%08x : ", loc, insn);*/
 
@@ -670,7 +665,7 @@
 }
 
 static void
-disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn, u_int loc)
+disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn, u_int __unused loc)
 {
 	if (((insn >> 8) & 0xf) == 1)
 		di->di_printf("f%d, ", (insn >> 12) & 0x07);
diff --git a/libpixelflinger/codeflinger/disassem.h b/libpixelflinger/codeflinger/disassem.h
index 02747cd..c7c60b6 100644
--- a/libpixelflinger/codeflinger/disassem.h
+++ b/libpixelflinger/codeflinger/disassem.h
@@ -49,8 +49,8 @@
 
 typedef struct {
 	u_int	(*di_readword)(u_int);
-	void	(*di_printaddr)(u_int);	
-	void	(*di_printf)(const char *, ...);
+	void	(*di_printaddr)(u_int);
+	int	(*di_printf)(const char *, ...);
 } disasm_interface_t;
 
 /* Prototypes for callable functions */
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 17d085c..8b757d2 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -20,6 +20,10 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
 struct sparse_file;
 
 /**
@@ -273,4 +277,8 @@
  */
 extern void (*sparse_print_verbose)(const char *fmt, ...);
 
+#ifdef	__cplusplus
+}
+#endif
+
 #endif
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
index 1df8c6a..2bece4c 100644
--- a/libsuspend/autosuspend_earlysuspend.c
+++ b/libsuspend/autosuspend_earlysuspend.c
@@ -75,13 +75,8 @@
     return err < 0 ? err : 0;
 }
 
-static void *earlysuspend_thread_func(void *arg)
+static void *earlysuspend_thread_func(void __unused *arg)
 {
-    char buf[80];
-    char wakeup_count[20];
-    int wakeup_count_len;
-    int ret;
-
     while (1) {
         if (wait_for_fb_sleep()) {
             ALOGE("Failed reading wait_for_fb_sleep, exiting earlysuspend thread\n");
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index 1451b0d..246f954 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_C_INCLUDES :=
 
-LOCAL_CFLAGS :=
+LOCAL_CFLAGS := -Werror
 
 LOCAL_SHARED_LIBRARIES := libcutils liblog
 
diff --git a/libsysutils/EventLogTags.logtags b/libsysutils/EventLogTags.logtags
index 7aa5cad..713f8cd 100644
--- a/libsysutils/EventLogTags.logtags
+++ b/libsysutils/EventLogTags.logtags
@@ -1,5 +1,5 @@
 # See system/core/logcat/event.logtags for a description of the format of this file.
 
 # FrameworkListener dispatchCommand overflow
-78001 dispatchCommand_overflow
-65537 netlink_failure (uid|1)
+78001 exp_det_dispatchCommand_overflow
+65537 exp_det_netlink_failure (uid|1)
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index a5ffda2..e7b3dd6 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -39,6 +39,11 @@
     init(socketName, false);
 }
 
+FrameworkListener::FrameworkListener(int sock) :
+                            SocketListener(sock, true) {
+    init(NULL, false);
+}
+
 void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {
     mCommands = new FrameworkCommandCollection();
     errorRate = 0;
@@ -87,7 +92,6 @@
     char *qlimit = tmp + sizeof(tmp) - 1;
     bool esc = false;
     bool quote = false;
-    int k;
     bool haveCmdNum = !mWithSeq;
 
     memset(argv, 0, sizeof(argv));
@@ -161,7 +165,7 @@
         goto overflow;
     argv[argc++] = strdup(tmp);
 #if 0
-    for (k = 0; k < argc; k++) {
+    for (int k = 0; k < argc; k++) {
         SLOGD("arg[%d] = '%s'", k, argv[k]);
     }
 #endif
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 34f2016..1c9c70a 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -109,7 +109,7 @@
             if (ifaddr->ifa_family == AF_INET) {
                 struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta);
                 if (RTA_PAYLOAD(rta) < sizeof(*addr4)) {
-                    SLOGE("Short IPv4 address (%d bytes) in %s",
+                    SLOGE("Short IPv4 address (%zu bytes) in %s",
                           RTA_PAYLOAD(rta), msgtype);
                     continue;
                 }
@@ -117,7 +117,7 @@
             } else if (ifaddr->ifa_family == AF_INET6) {
                 struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta);
                 if (RTA_PAYLOAD(rta) < sizeof(*addr6)) {
-                    SLOGE("Short IPv6 address (%d bytes) in %s",
+                    SLOGE("Short IPv6 address (%zu bytes) in %s",
                           RTA_PAYLOAD(rta), msgtype);
                     continue;
                 }
@@ -152,7 +152,7 @@
             }
 
             if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
-                SLOGE("Short IFA_CACHEINFO (%d vs. %d bytes) in %s",
+                SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s",
                       RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype);
                 continue;
             }
@@ -174,7 +174,6 @@
 }
 
 /*
-<<<<<<< HEAD
  * Parse a RTM_NEWNDUSEROPT message.
  */
 bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) {
@@ -399,7 +398,6 @@
     const char *s = buffer;
     const char *end;
     int param_idx = 0;
-    int i;
     int first = 1;
 
     if (size == 0)
diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp
index 0fb1d8e..660917b 100644
--- a/libutils/BlobCache.cpp
+++ b/libutils/BlobCache.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "BlobCache"
 //#define LOG_NDEBUG 0
 
+#include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -54,18 +55,18 @@
 void BlobCache::set(const void* key, size_t keySize, const void* value,
         size_t valueSize) {
     if (mMaxKeySize < keySize) {
-        ALOGV("set: not caching because the key is too large: %d (limit: %d)",
+        ALOGV("set: not caching because the key is too large: %zu (limit: %zu)",
                 keySize, mMaxKeySize);
         return;
     }
     if (mMaxValueSize < valueSize) {
-        ALOGV("set: not caching because the value is too large: %d (limit: %d)",
+        ALOGV("set: not caching because the value is too large: %zu (limit: %zu)",
                 valueSize, mMaxValueSize);
         return;
     }
     if (mMaxTotalSize < keySize + valueSize) {
         ALOGV("set: not caching because the combined key/value size is too "
-                "large: %d (limit: %d)", keySize + valueSize, mMaxTotalSize);
+                "large: %zu (limit: %zu)", keySize + valueSize, mMaxTotalSize);
         return;
     }
     if (keySize == 0) {
@@ -94,15 +95,15 @@
                     continue;
                 } else {
                     ALOGV("set: not caching new key/value pair because the "
-                            "total cache size limit would be exceeded: %d "
-                            "(limit: %d)",
+                            "total cache size limit would be exceeded: %zu "
+                            "(limit: %zu)",
                             keySize + valueSize, mMaxTotalSize);
                     break;
                 }
             }
             mCacheEntries.add(CacheEntry(keyBlob, valueBlob));
             mTotalSize = newTotalSize;
-            ALOGV("set: created new cache entry with %d byte key and %d byte value",
+            ALOGV("set: created new cache entry with %zu byte key and %zu byte value",
                     keySize, valueSize);
         } else {
             // Update the existing cache entry.
@@ -116,14 +117,14 @@
                     continue;
                 } else {
                     ALOGV("set: not caching new value because the total cache "
-                            "size limit would be exceeded: %d (limit: %d)",
+                            "size limit would be exceeded: %zu (limit: %zu)",
                             keySize + valueSize, mMaxTotalSize);
                     break;
                 }
             }
             mCacheEntries.editItemAt(index).setValue(valueBlob);
             mTotalSize = newTotalSize;
-            ALOGV("set: updated existing cache entry with %d byte key and %d byte "
+            ALOGV("set: updated existing cache entry with %zu byte key and %zu byte "
                     "value", keySize, valueSize);
         }
         break;
@@ -133,7 +134,7 @@
 size_t BlobCache::get(const void* key, size_t keySize, void* value,
         size_t valueSize) {
     if (mMaxKeySize < keySize) {
-        ALOGV("get: not searching because the key is too large: %d (limit %d)",
+        ALOGV("get: not searching because the key is too large: %zu (limit %zu)",
                 keySize, mMaxKeySize);
         return 0;
     }
@@ -141,7 +142,7 @@
     CacheEntry dummyEntry(dummyKey, NULL);
     ssize_t index = mCacheEntries.indexOf(dummyEntry);
     if (index < 0) {
-        ALOGV("get: no cache entry found for key of size %d", keySize);
+        ALOGV("get: no cache entry found for key of size %zu", keySize);
         return 0;
     }
 
@@ -150,10 +151,10 @@
     sp<Blob> valueBlob(mCacheEntries[index].getValue());
     size_t valueBlobSize = valueBlob->getSize();
     if (valueBlobSize <= valueSize) {
-        ALOGV("get: copying %d bytes to caller's buffer", valueBlobSize);
+        ALOGV("get: copying %zu bytes to caller's buffer", valueBlobSize);
         memcpy(value, valueBlob->getData(), valueBlobSize);
     } else {
-        ALOGV("get: caller's buffer is too small for value: %d (needs %d)",
+        ALOGV("get: caller's buffer is too small for value: %zu (needs %zu)",
                 valueSize, valueBlobSize);
     }
     return valueBlobSize;
@@ -229,7 +230,7 @@
     }
     const Header* header = reinterpret_cast<const Header*>(buffer);
     if (header->mMagicNumber != blobCacheMagic) {
-        ALOGE("unflatten: bad magic number: %d", header->mMagicNumber);
+        ALOGE("unflatten: bad magic number: %" PRIu32, header->mMagicNumber);
         return BAD_VALUE;
     }
     if (header->mBlobCacheVersion != blobCacheVersion ||
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 9ce370e..933e7aa 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -23,6 +23,7 @@
 #include <utils/FileMap.h>
 #include <utils/Log.h>
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -39,37 +40,32 @@
 
 /*static*/ long FileMap::mPageSize = -1;
 
-
-/*
- * Constructor.  Create an empty object.
- */
+// Constructor.  Create an empty object.
 FileMap::FileMap(void)
     : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
       mDataPtr(NULL), mDataLength(0)
 {
 }
 
-/*
- * Destructor.
- */
+// Destructor.
 FileMap::~FileMap(void)
 {
     assert(mRefCount == 0);
 
-    //printf("+++ removing FileMap %p %u\n", mDataPtr, mDataLength);
+    //printf("+++ removing FileMap %p %zu\n", mDataPtr, mDataLength);
 
     mRefCount = -100;       // help catch double-free
     if (mFileName != NULL) {
         free(mFileName);
     }
-#ifdef HAVE_POSIX_FILEMAP    
+#ifdef HAVE_POSIX_FILEMAP
     if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) {
-        ALOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength);
+        ALOGD("munmap(%p, %zu) failed\n", mBasePtr, mBaseLength);
     }
 #endif
 #ifdef HAVE_WIN32_FILEMAP
     if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) {
-        ALOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr,
+        ALOGD("UnmapViewOfFile(%p) failed, error = %" PRId32 "\n", mBasePtr,
               GetLastError() );
     }
     if (mFileMapping != INVALID_HANDLE_VALUE) {
@@ -80,14 +76,12 @@
 }
 
 
-/*
- * Create a new mapping on an open file.
- *
- * Closing the file descriptor does not unmap the pages, so we don't
- * claim ownership of the fd.
- *
- * Returns "false" on failure.
- */
+// Create a new mapping on an open file.
+//
+// Closing the file descriptor does not unmap the pages, so we don't
+// claim ownership of the fd.
+//
+// Returns "false" on failure.
 bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length,
         bool readOnly)
 {
@@ -98,32 +92,32 @@
 
     if (mPageSize == -1) {
         SYSTEM_INFO  si;
-        
+
         GetSystemInfo( &si );
         mPageSize = si.dwAllocationGranularity;
     }
 
     DWORD  protect = readOnly ? PAGE_READONLY : PAGE_READWRITE;
-    
+
     mFileHandle  = (HANDLE) _get_osfhandle(fd);
     mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL);
     if (mFileMapping == NULL) {
-        ALOGE("CreateFileMapping(%p, %lx) failed with error %ld\n",
+        ALOGE("CreateFileMapping(%p, %" PRIx32 ") failed with error %" PRId32 "\n",
               mFileHandle, protect, GetLastError() );
         return false;
     }
-    
+
     adjust    = offset % mPageSize;
     adjOffset = offset - adjust;
     adjLength = length + adjust;
-    
-    mBasePtr = MapViewOfFile( mFileMapping, 
+
+    mBasePtr = MapViewOfFile( mFileMapping,
                               readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
                               0,
                               (DWORD)(adjOffset),
                               adjLength );
     if (mBasePtr == NULL) {
-        ALOGE("MapViewOfFile(%ld, %ld) failed with error %ld\n",
+        ALOGE("MapViewOfFile(%" PRId64 ", %zu) failed with error %" PRId32 "\n",
               adjOffset, adjLength, GetLastError() );
         CloseHandle(mFileMapping);
         mFileMapping = INVALID_HANDLE_VALUE;
@@ -142,7 +136,7 @@
     assert(offset >= 0);
     assert(length > 0);
 
-    /* init on first use */
+    // init on first use
     if (mPageSize == -1) {
 #if NOT_USING_KLIBC
         mPageSize = sysconf(_SC_PAGESIZE);
@@ -151,7 +145,7 @@
             return false;
         }
 #else
-        /* this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM */
+        // this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM
         mPageSize = 4096;
 #endif
     }
@@ -168,19 +162,19 @@
 
     ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset);
     if (ptr == MAP_FAILED) {
-    	// Cygwin does not seem to like file mapping files from an offset.
-    	// So if we fail, try again with offset zero
-    	if (adjOffset > 0) {
-    		adjust = offset;
-    		goto try_again;
-    	}
-    
-        ALOGE("mmap(%ld,%ld) failed: %s\n",
-            (long) adjOffset, (long) adjLength, strerror(errno));
+        // Cygwin does not seem to like file mapping files from an offset.
+        // So if we fail, try again with offset zero
+        if (adjOffset > 0) {
+            adjust = offset;
+            goto try_again;
+        }
+
+        ALOGE("mmap(%" PRId64 ",%zu) failed: %s\n",
+            adjOffset, adjLength, strerror(errno));
         return false;
     }
     mBasePtr = ptr;
-#endif /* HAVE_POSIX_FILEMAP */
+#endif // HAVE_POSIX_FILEMAP
 
     mFileName = origFileName != NULL ? strdup(origFileName) : NULL;
     mBaseLength = adjLength;
@@ -190,15 +184,13 @@
 
     assert(mBasePtr != NULL);
 
-    ALOGV("MAP: base %p/%d data %p/%d\n",
-        mBasePtr, (int) mBaseLength, mDataPtr, (int) mDataLength);
+    ALOGV("MAP: base %p/%zu data %p/%zu\n",
+        mBasePtr, mBaseLength, mDataPtr, mDataLength);
 
     return true;
 }
 
-/*
- * Provide guidance to the system.
- */
+// Provide guidance to the system.
 int FileMap::advise(MapAdvice advice)
 {
 #if HAVE_MADVISE
@@ -220,6 +212,6 @@
         ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
     return cc;
 #else
-	return -1;
+    return -1;
 #endif // HAVE_MADVISE
 }
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index 5293cd2..a431e92 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -34,7 +34,7 @@
 
 nsecs_t systemTime(int clock)
 {
-#if defined(HAVE_POSIX_CLOCKS)
+#if defined(HAVE_ANDROID_OS)
     static const clockid_t clocks[] = {
             CLOCK_REALTIME,
             CLOCK_MONOTONIC,
@@ -47,7 +47,9 @@
     clock_gettime(clocks[clock], &t);
     return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
 #else
-    // we don't support the clocks here.
+    // Clock support varies widely across hosts. Mac OS doesn't support
+    // posix clocks, older glibcs don't support CLOCK_BOOTTIME and Windows
+    // is windows.
     struct timeval t;
     t.tv_sec = t.tv_usec = 0;
     gettimeofday(&t, NULL);
diff --git a/libutils/tests/BasicHashtable_test.cpp b/libutils/tests/BasicHashtable_test.cpp
index 7dcf750..a61b1e1 100644
--- a/libutils/tests/BasicHashtable_test.cpp
+++ b/libutils/tests/BasicHashtable_test.cpp
@@ -397,7 +397,7 @@
         const SimpleEntry& entry = h.entryAt(index);
         ASSERT_GE(entry.key, 0);
         ASSERT_LT(entry.key, N);
-        ASSERT_EQ(false, set[entry.key]);
+        ASSERT_FALSE(set[entry.key]);
         ASSERT_EQ(entry.key * 10, entry.value);
 
         set[entry.key] = true;
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index e573952..bcbea32 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -184,7 +184,7 @@
 
     for (size_t i = 0; i < kNumKeys; i++) {
         strings[i] = (char *)malloc(16);
-        sprintf(strings[i], "%d", i);
+        sprintf(strings[i], "%zu", i);
     }
 
     srandom(12345);
diff --git a/logcat/Android.mk b/logcat/Android.mk
index dd15cb3..b5e27eb 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -3,10 +3,6 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
-LOCAL_CFLAGS += -DUSERDEBUG_BUILD=1
-endif
-
 LOCAL_SRC_FILES:= logcat.cpp event.logtags
 
 LOCAL_SHARED_LIBRARIES := liblog
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 5a80efe..995a42e 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -227,22 +227,20 @@
                     "  -T <count>      print only the most recent <count> lines (does not imply -d)\n"
                     "  -g              get the size of the log's ring buffer and exit\n"
                     "  -b <buffer>     Request alternate ring buffer, 'main', 'system', 'radio',\n"
-                    "                  'events' or 'all'. Multiple -b parameters are allowed and\n"
-                    "                  results are interleaved. The default is -b main -b system.\n"
+                    "                  'events', 'crash' or 'all'. Multiple -b parameters are\n"
+                    "                  allowed and results are interleaved. The default is\n"
+                    "                  -b main -b system -b crash.\n"
                     "  -B              output the log in binary.\n"
-                    "  -S              output statistics.\n");
-
-#ifdef USERDEBUG_BUILD
-
-    fprintf(stderr, "--------------------- eng & userdebug builds only ---------------------------\n"
-                    "  -G <count>      set size of log's ring buffer and exit\n"
-                    "  -p              output prune white and ~black list\n"
-                    "  -P '<list> ...' set prune white and ~black list; UID, /PID or !(worst UID)\n"
-                    "                  default is ~!, prune worst UID.\n"
-                    "-----------------------------------------------------------------------------\n"
-    );
-
-#endif
+                    "  -S              output statistics.\n"
+                    "  -G <size>       set size of log ring buffer, may suffix with K or M.\n"
+                    "  -p              print prune white and ~black list. Service is specified as\n"
+                    "                  UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
+                    "                  with ~, otherwise weighed for longevity if unadorned. All\n"
+                    "                  other pruning activity is oldest first. Special case ~!\n"
+                    "                  represents an automatic quicker pruning for the noisiest\n"
+                    "                  UID as determined by the current statistics.\n"
+                    "  -P '<list> ...' set prune white and ~black list, using same format as\n"
+                    "                  printed above. Must be quoted.\n");
 
     fprintf(stderr,"\nfilterspecs are a series of \n"
                    "  <tag>[:priority]\n\n"
@@ -291,11 +289,9 @@
     int hasSetLogFormat = 0;
     int clearLog = 0;
     int getLogSize = 0;
-#ifdef USERDEBUG_BUILD
     unsigned long setLogSize = 0;
     int getPruneList = 0;
     char *setPruneList = NULL;
-#endif
     int printStatistics = 0;
     int mode = O_RDONLY;
     const char *forceFilters = NULL;
@@ -323,13 +319,7 @@
     for (;;) {
         int ret;
 
-        ret = getopt(argc, argv,
-#ifdef USERDEBUG_BUILD
-            "cdt:T:gG:sQf:r::n:v:b:BSpP:"
-#else
-            "cdt:T:gsQf:r::n:v:b:BS"
-#endif
-        );
+        ret = getopt(argc, argv, "cdt:T:gG:sQf:r::n:v:b:BSpP:");
 
         if (ret < 0) {
             break;
@@ -386,8 +376,6 @@
                 getLogSize = 1;
             break;
 
-#ifdef USERDEBUG_BUILD
-
             case 'G': {
                 // would use atol if not for the multiplier
                 char *cp = optarg;
@@ -433,8 +421,6 @@
                 setPruneList = optarg;
             break;
 
-#endif
-
             case 'b': {
                 if (strcmp(optarg, "all") == 0) {
                     while (devices) {
@@ -462,10 +448,17 @@
                     if (android_name_to_log_id("events") == LOG_ID_EVENTS) {
                         dev->next = new log_device_t("events", true, 'e');
                         if (dev->next) {
+                            dev = dev->next;
                             android::g_devCount++;
                             needBinary = true;
                         }
                     }
+                    if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
+                        dev->next = new log_device_t("crash", false, 'c');
+                        if (dev->next) {
+                            android::g_devCount++;
+                        }
+                    }
                     break;
                 }
 
@@ -622,6 +615,14 @@
             devices->next = new log_device_t("system", false, 's');
             android::g_devCount++;
         }
+        if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
+            if (devices->next) {
+                devices->next->next = new log_device_t("crash", false, 'c');
+            } else {
+                devices->next = new log_device_t("crash", false, 'c');
+            }
+            android::g_devCount++;
+        }
     }
 
     if (android::g_logRotateSizeKBytes != 0
@@ -704,15 +705,11 @@
             }
         }
 
-#ifdef USERDEBUG_BUILD
-
         if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) {
             perror("failed to set the log size");
             exit(EXIT_FAILURE);
         }
 
-#endif
-
         if (getLogSize) {
             long size, readable;
 
@@ -737,8 +734,6 @@
         dev = dev->next;
     }
 
-#ifdef USERDEBUG_BUILD
-
     if (setPruneList) {
         size_t len = strlen(setPruneList) + 32; // margin to allow rc
         char *buf = (char *) malloc(len);
@@ -753,30 +748,18 @@
         }
     }
 
-#endif
-
-    if (
-#ifdef USERDEBUG_BUILD
-        printStatistics || getPruneList
-#else
-        printStatistics
-#endif
-    ) {
+    if (printStatistics || getPruneList) {
         size_t len = 8192;
         char *buf;
 
         for(int retry = 32;
                 (retry >= 0) && ((buf = new char [len]));
                 delete [] buf, --retry) {
-#ifdef USERDEBUG_BUILD
             if (getPruneList) {
                 android_logger_get_prune_list(logger_list, buf, len);
             } else {
                 android_logger_get_statistics(logger_list, buf, len);
             }
-#else
-            android_logger_get_statistics(logger_list, buf, len);
-#endif
             buf[len-1] = '\0';
             size_t ret = atol(buf) + 1;
             if (ret < 4) {
@@ -824,11 +807,9 @@
     if (getLogSize) {
         exit(0);
     }
-#ifdef USERDEBUG_BUILD
     if (setLogSize || setPruneList) {
         exit(0);
     }
-#endif
     if (clearLog) {
         exit(0);
     }
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index 733af31..d42b3d0 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -30,10 +30,6 @@
     -Werror \
     -fno-builtin
 
-ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
-test_c_flags += -DUSERDEBUG_BUILD=1
-endif
-
 test_src_files := \
     logcat_test.cpp \
 
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 0165073..b07cc8b 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -609,7 +609,6 @@
     EXPECT_EQ(1, signals);
 }
 
-#ifdef USERDEBUG_BUILD
 static bool get_white_black(char **list) {
     FILE *fp;
 
@@ -705,4 +704,3 @@
     free(list);
     list = NULL;
 }
-#endif // USERDEBUG_BUILD
diff --git a/logd/Android.mk b/logd/Android.mk
index 61895c4..0235478 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -4,10 +4,6 @@
 
 LOCAL_MODULE:= logd
 
-ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
-LOCAL_CFLAGS += -DUSERDEBUG_BUILD=1
-endif
-
 LOCAL_SRC_FILES := \
     main.cpp \
     LogCommand.cpp \
@@ -32,3 +28,5 @@
 LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_EXECUTABLE)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 12b10ca..1f3fd0e 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -21,9 +21,11 @@
 #include <netinet/in.h>
 #include <string.h>
 #include <stdlib.h>
+#include <sys/prctl.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 
+#include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
 #include <sysutils/SocketClient.h>
 
@@ -32,20 +34,16 @@
 
 CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
                                  LogListener * /*swl*/)
-        : FrameworkListener("logd")
+        : FrameworkListener(getLogSocket())
         , mBuf(*buf) {
     // registerCmd(new ShutdownCmd(buf, writer, swl));
     registerCmd(new ClearCmd(buf));
     registerCmd(new GetBufSizeCmd(buf));
-#ifdef USERDEBUG_BUILD
     registerCmd(new SetBufSizeCmd(buf));
-#endif
     registerCmd(new GetBufSizeUsedCmd(buf));
     registerCmd(new GetStatisticsCmd(buf));
-#ifdef USERDEBUG_BUILD
     registerCmd(new SetPruneListCmd(buf));
     registerCmd(new GetPruneListCmd(buf));
-#endif
 }
 
 CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
@@ -69,8 +67,13 @@
         , mBuf(*buf)
 { }
 
+static void setname() {
+    prctl(PR_SET_NAME, "logd.control");
+}
+
 int CommandListener::ClearCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
+    setname();
     if (!clientHasLogCredentials(cli)) {
         cli->sendMsg("Permission Denied");
         return 0;
@@ -99,6 +102,7 @@
 
 int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
+    setname();
     if (argc < 2) {
         cli->sendMsg("Missing Argument");
         return 0;
@@ -117,8 +121,6 @@
     return 0;
 }
 
-#ifdef USERDEBUG_BUILD
-
 CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf)
         : LogCommand("setLogSize")
         , mBuf(*buf)
@@ -126,6 +128,7 @@
 
 int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
+    setname();
     if (!clientHasLogCredentials(cli)) {
         cli->sendMsg("Permission Denied");
         return 0;
@@ -152,8 +155,6 @@
     return 0;
 }
 
-#endif // USERDEBUG_BUILD
-
 CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf)
         : LogCommand("getLogSizeUsed")
         , mBuf(*buf)
@@ -161,6 +162,7 @@
 
 int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
+    setname();
     if (argc < 2) {
         cli->sendMsg("Missing Argument");
         return 0;
@@ -204,6 +206,7 @@
 
 int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
+    setname();
     uid_t uid = cli->getUid();
     gid_t gid = cli->getGid();
     if (clientHasLogCredentials(cli)) {
@@ -236,8 +239,6 @@
     return 0;
 }
 
-#ifdef USERDEBUG_BUILD
-
 CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf)
         : LogCommand("getPruneList")
         , mBuf(*buf)
@@ -245,6 +246,7 @@
 
 int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
                                          int /*argc*/, char ** /*argv*/) {
+    setname();
     char *buf = NULL;
     mBuf.formatPrune(&buf);
     if (!buf) {
@@ -264,6 +266,7 @@
 
 int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
                                          int argc, char **argv) {
+    setname();
     if (!clientHasLogCredentials(cli)) {
         cli->sendMsg("Permission Denied");
         return 0;
@@ -294,4 +297,15 @@
     return 0;
 }
 
-#endif // USERDEBUG_BUILD
+int CommandListener::getLogSocket() {
+    static const char socketName[] = "logd";
+    int sock = android_get_control_socket(socketName);
+
+    if (sock < 0) {
+        sock = socket_local_server(socketName,
+                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_STREAM);
+    }
+
+    return sock;
+}
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index de1dcb9..cd1c306 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -31,6 +31,8 @@
     virtual ~CommandListener() {}
 
 private:
+    static int getLogSocket();
+
     class ShutdownCmd : public LogCommand {
         LogBuffer &mBuf;
         LogReader &mReader;
@@ -53,15 +55,11 @@
 
     LogBufferCmd(Clear)
     LogBufferCmd(GetBufSize)
-#ifdef USERDEBUG_BUILD
     LogBufferCmd(SetBufSize)
-#endif
     LogBufferCmd(GetBufSizeUsed)
     LogBufferCmd(GetStatistics)
-#ifdef USERDEBUG_BUILD
     LogBufferCmd(GetPruneList)
     LogBufferCmd(SetPruneList)
-#endif
 };
 
 #endif
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index ea6eece..add0f0e 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -16,9 +16,11 @@
 
 #include <ctype.h>
 #include <errno.h>
+#include <limits.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <sys/klog.h>
+#include <sys/prctl.h>
 #include <sys/uio.h>
 
 #include "libaudit.h"
@@ -34,8 +36,14 @@
 }
 
 bool LogAudit::onDataAvailable(SocketClient *cli) {
+    prctl(PR_SET_NAME, "logd.auditd");
+
     struct audit_message rep;
 
+    rep.nlh.nlmsg_type = 0;
+    rep.nlh.nlmsg_len = 0;
+    rep.data[0] = '\0';
+
     if (audit_get_reply(cli->getSocket(), &rep, GET_REPLY_BLOCKING, 0) < 0) {
         SLOGE("Failed on audit_get_reply with error: %s", strerror(errno));
         return false;
@@ -143,11 +151,8 @@
     strcpy(newstr + 1 + l, str);
     free(str);
 
-    unsigned short len = n; // cap to internal maximum
-    if (len != n) {
-        len = -1;
-    }
-    logbuf->log(AUDIT_LOG_ID, now, uid, pid, tid, newstr, len);
+    logbuf->log(AUDIT_LOG_ID, now, uid, pid, tid, newstr,
+                (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
     reader->notifyNewLog();
 
     free(newstr);
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 81eb091..38a237c 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -28,22 +28,16 @@
 
 // Default
 #define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
-#ifdef USERDEBUG_BUILD
 #define log_buffer_size(id) mMaxSize[id]
-#else
-#define log_buffer_size(id) LOG_BUFFER_SIZE
-#endif
 
 LogBuffer::LogBuffer(LastLogTimes *times)
         : mTimes(*times) {
     pthread_mutex_init(&mLogElementsLock, NULL);
     dgram_qlen_statistics = false;
 
-#ifdef USERDEBUG_BUILD
     log_id_for_each(i) {
         mMaxSize[i] = LOG_BUFFER_SIZE;
     }
-#endif
 }
 
 void LogBuffer::log(log_id_t log_id, log_time realtime,
@@ -171,22 +165,16 @@
         size_t worst_sizes = 0;
         size_t second_worst_sizes = 0;
 
-#ifdef USERDEBUG_BUILD
-        if (mPrune.worstUidEnabled())
-#endif
-        {
+        if ((id != LOG_ID_CRASH) && mPrune.worstUidEnabled()) {
             LidStatistics &l = stats.id(id);
-            UidStatisticsCollection::iterator iu;
-            for (iu = l.begin(); iu != l.end(); ++iu) {
-                UidStatistics *u = (*iu);
-                size_t sizes = u->sizes();
-                if (worst_sizes < sizes) {
-                    second_worst_sizes = worst_sizes;
-                    worst_sizes = sizes;
-                    worst = u->getUid();
-                }
-                if ((second_worst_sizes < sizes) && (sizes < worst_sizes)) {
-                    second_worst_sizes = sizes;
+            l.sort();
+            UidStatisticsCollection::iterator iu = l.begin();
+            if (iu != l.end()) {
+                UidStatistics *u = *iu;
+                worst = u->getUid();
+                worst_sizes = u->sizes();
+                if (++iu != l.end()) {
+                    second_worst_sizes = (*iu)->sizes();
                 }
             }
         }
@@ -217,9 +205,7 @@
                     break;
                 }
                 worst_sizes -= len;
-            }
-#ifdef USERDEBUG_BUILD
-            else if (mPrune.naughty(e)) { // BlackListed
+            } else if (mPrune.naughty(e)) { // BlackListed
                 it = mLogElements.erase(it);
                 stats.subtract(e->getMsgLen(), id, uid, e->getPid());
                 delete e;
@@ -227,34 +213,23 @@
                 if (pruneRows == 0) {
                     break;
                 }
-            }
-#endif
-            else {
+            } else {
                 ++it;
             }
         }
 
-        if (!kick
-#ifdef USERDEBUG_BUILD
-                || !mPrune.worstUidEnabled()
-#endif
-        ) {
+        if (!kick || !mPrune.worstUidEnabled()) {
             break; // the following loop will ask bad clients to skip/drop
         }
     }
 
-#ifdef USERDEBUG_BUILD
     bool whitelist = false;
-#endif
     it = mLogElements.begin();
     while((pruneRows > 0) && (it != mLogElements.end())) {
         LogBufferElement *e = *it;
         if (e->getLogId() == id) {
             if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
-#ifdef USERDEBUG_BUILD
-                if (!whitelist)
-#endif
-                {
+                if (!whitelist) {
                     if (stats.sizes(id) > (2 * log_buffer_size(id))) {
                         // kick a misbehaving log reader client off the island
                         oldest->release_Locked();
@@ -264,13 +239,13 @@
                 }
                 break;
             }
-#ifdef USERDEBUG_BUILD
+
             if (mPrune.nice(e)) { // WhiteListed
                 whitelist = true;
                 it++;
                 continue;
             }
-#endif
+
             it = mLogElements.erase(it);
             stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
             delete e;
@@ -280,7 +255,6 @@
         }
     }
 
-#ifdef USERDEBUG_BUILD
     if (whitelist && (pruneRows > 0)) {
         it = mLogElements.begin();
         while((it != mLogElements.end()) && (pruneRows > 0)) {
@@ -304,7 +278,6 @@
             }
         }
     }
-#endif
 
     LogTimeEntry::unlock();
 }
@@ -324,8 +297,6 @@
     return retval;
 }
 
-#ifdef USERDEBUG_BUILD
-
 // set the total space allocated to "id"
 int LogBuffer::setSize(log_id_t id, unsigned long size) {
     // Reasonable limits ...
@@ -346,15 +317,6 @@
     return retval;
 }
 
-#else // ! USERDEBUG_BUILD
-
-// get the total space allocated to "id"
-unsigned long LogBuffer::getSize(log_id_t /*id*/) {
-    return log_buffer_size(id);
-}
-
-#endif
-
 log_time LogBuffer::flushTo(
         SocketClient *reader, const log_time start, bool privileged,
         bool (*filter)(const LogBufferElement *element, void *arg), void *arg) {
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index bdb3179..b8a54b9 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -38,11 +38,9 @@
 
     bool dgram_qlen_statistics;
 
-#ifdef USERDEBUG_BUILD
     PruneList mPrune;
 
     unsigned long mMaxSize[LOG_ID_MAX];
-#endif
 
 public:
     LastLogTimes &mTimes;
@@ -59,9 +57,7 @@
 
     void clear(log_id_t id);
     unsigned long getSize(log_id_t id);
-#ifdef USERDEBUG_BUILD
     int setSize(log_id_t id, unsigned long size);
-#endif
     unsigned long getSizeUsed(log_id_t id);
     // *strp uses malloc, use free to release.
     void formatStatistics(char **strp, uid_t uid, unsigned int logMask);
@@ -71,11 +67,9 @@
         dgram_qlen_statistics = true;
     }
 
-#ifdef USERDEBUG_BUILD
     int initPrune(char *cp) { return mPrune.init(cp); }
     // *strp uses malloc, use free to release.
     void formatPrune(char **strp) { mPrune.format(strp); }
-#endif
 
     // helper
     char *pidToName(pid_t pid) { return stats.pidToName(pid); }
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index b835b4f..6ff4d3a 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <limits.h>
+#include <sys/prctl.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/un.h>
@@ -31,7 +33,9 @@
 {  }
 
 bool LogListener::onDataAvailable(SocketClient *cli) {
-    char buffer[sizeof_log_id_t + sizeof(log_time) + sizeof(char)
+    prctl(PR_SET_NAME, "logd.writer");
+
+    char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time)
         + LOGGER_ENTRY_MAX_PAYLOAD];
     struct iovec iov = { buffer, sizeof(buffer) };
     memset(buffer, 0, sizeof(buffer));
@@ -97,17 +101,24 @@
 
     // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
     // truncated message to the logs.
-    unsigned short len = n; // cap to internal maximum
-    if (len == n) {
-        logbuf->log(log_id, realtime, cred->uid, cred->pid, tid, msg, len);
-        reader->notifyNewLog();
-    }
+
+    logbuf->log(log_id, realtime, cred->uid, cred->pid, tid, msg,
+        (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+    reader->notifyNewLog();
 
     return true;
 }
 
 int LogListener::getLogSocket() {
-    int sock = android_get_control_socket("logdw");
+    static const char socketName[] = "logdw";
+    int sock = android_get_control_socket(socketName);
+
+    if (sock < 0) {
+        sock = socket_local_server(socketName,
+                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_DGRAM);
+    }
+
     int on = 1;
     if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
         return -1;
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 60a3507..8458c19 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -16,14 +16,16 @@
 
 #include <ctype.h>
 #include <poll.h>
+#include <sys/prctl.h>
 #include <sys/socket.h>
+
 #include <cutils/sockets.h>
 
 #include "LogReader.h"
 #include "FlushCommand.h"
 
 LogReader::LogReader(LogBuffer *logbuf)
-        : SocketListener("logdr", true)
+        : SocketListener(getLogSocket(), true)
         , mLogbuf(*logbuf)
 { }
 
@@ -35,6 +37,8 @@
 }
 
 bool LogReader::onDataAvailable(SocketClient *cli) {
+    prctl(PR_SET_NAME, "logd.reader");
+
     char buffer[255];
 
     int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
@@ -167,3 +171,16 @@
     }
     LogTimeEntry::unlock();
 }
+
+int LogReader::getLogSocket() {
+    static const char socketName[] = "logdr";
+    int sock = android_get_control_socket(socketName);
+
+    if (sock < 0) {
+        sock = socket_local_server(socketName,
+                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_SEQPACKET);
+    }
+
+    return sock;
+}
diff --git a/logd/LogReader.h b/logd/LogReader.h
index b267c75..91559a3 100644
--- a/logd/LogReader.h
+++ b/logd/LogReader.h
@@ -34,6 +34,8 @@
     virtual bool onDataAvailable(SocketClient *cli);
 
 private:
+    static int getLogSocket();
+
     void doSocketDelete(SocketClient *cli);
 
 };
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 82a3a90..f2b9a26 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -31,6 +31,7 @@
         , mSizes(0)
         , mElements(0)
         , name(name)
+        , mGone(false)
 { }
 
 #ifdef DO_NOT_ERROR_IF_PIDSTATISTICS_USES_A_COPY_CONSTRUCTOR
@@ -41,6 +42,7 @@
         , mElementsTotal(copy->mElementsTotal)
         , mSizes(copy->mSizes)
         , mElements(copy->mElements)
+        , mGone(copy->mGone)
 { }
 #endif
 
@@ -48,6 +50,20 @@
     free(name);
 }
 
+bool PidStatistics::pidGone() {
+    if (mGone) {
+        return true;
+    }
+    if (pid == gone) {
+        return true;
+    }
+    if (kill(pid, 0) && (errno != EPERM)) {
+        mGone = true;
+        return true;
+    }
+    return false;
+}
+
 void PidStatistics::setName(char *new_name) {
     free(name);
     name = new_name;
@@ -63,7 +79,7 @@
 bool PidStatistics::subtract(unsigned short size) {
     mSizes -= size;
     --mElements;
-    return mElements == 0 && kill(pid, 0);
+    return (mElements == 0) && pidGone();
 }
 
 void PidStatistics::addTotal(size_t size, size_t element) {
@@ -76,7 +92,7 @@
 // must call free to release return value
 char *PidStatistics::pidToName(pid_t pid) {
     char *retval = NULL;
-    if (pid != PidStatistics::gone) {
+    if (pid != gone) {
         char buffer[512];
         snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
         int fd = open(buffer, O_RDONLY);
@@ -96,7 +112,9 @@
 }
 
 UidStatistics::UidStatistics(uid_t uid)
-        : uid(uid) {
+        : uid(uid)
+        , mSizes(0)
+        , mElements(0) {
     Pids.clear();
 }
 
@@ -109,6 +127,9 @@
 }
 
 void UidStatistics::add(unsigned short size, pid_t pid) {
+    mSizes += size;
+    ++mElements;
+
     PidStatistics *p;
     PidStatisticsCollection::iterator last;
     PidStatisticsCollection::iterator it;
@@ -116,18 +137,11 @@
         p = *it;
         if (pid == p->getPid()) {
             p->add(size);
-            // poor-man sort, bubble upwards if bigger than last
-            if ((last != it) && ((*last)->sizesTotal() < p->sizesTotal())) {
-                Pids.erase(it);
-                Pids.insert(last, p);
-            }
             return;
         }
     }
-    // poor-man sort, insert if bigger than last or last is the gone entry.
-    bool insert = (last != it)
-        && ((p->getPid() == p->gone)
-            || ((*last)->sizesTotal() < (size_t) size));
+    // insert if the gone entry.
+    bool insert = (last != it) && (p->getPid() == p->gone);
     p = new PidStatistics(pid, pidToName(pid));
     if (insert) {
         Pids.insert(last, p);
@@ -138,6 +152,9 @@
 }
 
 void UidStatistics::subtract(unsigned short size, pid_t pid) {
+    mSizes -= size;
+    --mElements;
+
     PidStatisticsCollection::iterator it;
     for (it = begin(); it != end(); ++it) {
         PidStatistics *p = *it;
@@ -166,28 +183,57 @@
     }
 }
 
+void UidStatistics::sort() {
+    for (bool pass = true; pass;) {
+        pass = false;
+        PidStatisticsCollection::iterator it = begin();
+        if (it != end()) {
+            PidStatisticsCollection::iterator lt = it;
+            PidStatistics *l = (*lt);
+            while (++it != end()) {
+                PidStatistics *n = (*it);
+                if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) {
+                    pass = true;
+                    Pids.erase(it);
+                    Pids.insert(lt, n);
+                    it = lt;
+                    n = l;
+                }
+                lt = it;
+                l = n;
+            }
+        }
+    }
+}
+
 size_t UidStatistics::sizes(pid_t pid) {
-    size_t sizes = 0;
+    if (pid == pid_all) {
+        return sizes();
+    }
+
     PidStatisticsCollection::iterator it;
     for (it = begin(); it != end(); ++it) {
         PidStatistics *p = *it;
-        if ((pid == pid_all) || (pid == p->getPid())) {
-            sizes += p->sizes();
+        if (pid == p->getPid()) {
+            return p->sizes();
         }
     }
-    return sizes;
+    return 0;
 }
 
 size_t UidStatistics::elements(pid_t pid) {
-    size_t elements = 0;
+    if (pid == pid_all) {
+        return elements();
+    }
+
     PidStatisticsCollection::iterator it;
     for (it = begin(); it != end(); ++it) {
         PidStatistics *p = *it;
-        if ((pid == pid_all) || (pid == p->getPid())) {
-            elements += p->elements();
+        if (pid == p->getPid()) {
+            return p->elements();
         }
     }
-    return elements;
+    return 0;
 }
 
 size_t UidStatistics::sizesTotal(pid_t pid) {
@@ -266,6 +312,29 @@
     }
 }
 
+void LidStatistics::sort() {
+    for (bool pass = true; pass;) {
+        pass = false;
+        UidStatisticsCollection::iterator it = begin();
+        if (it != end()) {
+            UidStatisticsCollection::iterator lt = it;
+            UidStatistics *l = (*lt);
+            while (++it != end()) {
+                UidStatistics *n = (*it);
+                if (n->sizes() > l->sizes()) {
+                    pass = true;
+                    Uids.erase(it);
+                    Uids.insert(lt, n);
+                    it = lt;
+                    n = l;
+                }
+                lt = it;
+                l = n;
+            }
+        }
+    }
+}
+
 size_t LidStatistics::sizes(uid_t uid, pid_t pid) {
     size_t sizes = 0;
     UidStatisticsCollection::iterator it;
@@ -446,7 +515,7 @@
     static const unsigned short spaces_total = 19;
 
     if (*buf) {
-        free(buf);
+        free(*buf);
         *buf = NULL;
     }
 
@@ -455,13 +524,22 @@
     short spaces = 2;
 
     log_id_for_each(i) {
-        if (logMask & (1 << i)) {
-            oldLength = string.length();
-            if (spaces < 0) {
-                spaces = 0;
-            }
-            string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
-            spaces += spaces_total + oldLength - string.length();
+        if (!logMask & (1 << i)) {
+            continue;
+        }
+        oldLength = string.length();
+        if (spaces < 0) {
+            spaces = 0;
+        }
+        string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
+        spaces += spaces_total + oldLength - string.length();
+
+        LidStatistics &l = id(i);
+        l.sort();
+
+        UidStatisticsCollection::iterator iu;
+        for (iu = l.begin(); iu != l.end(); ++iu) {
+            (*iu)->sort();
         }
     }
 
@@ -508,6 +586,106 @@
         spaces += spaces_total;
     }
 
+    // Construct list of worst spammers by Pid
+    static const unsigned char num_spammers = 10;
+    bool header = false;
+
+    log_id_for_each(i) {
+        if (!(logMask & (1 << i))) {
+            continue;
+        }
+
+        PidStatisticsCollection pids;
+        pids.clear();
+
+        LidStatistics &l = id(i);
+        UidStatisticsCollection::iterator iu;
+        for (iu = l.begin(); iu != l.end(); ++iu) {
+            UidStatistics &u = *(*iu);
+            PidStatisticsCollection::iterator ip;
+            for (ip = u.begin(); ip != u.end(); ++ip) {
+                PidStatistics *p = (*ip);
+                if (p->getPid() == p->gone) {
+                    break;
+                }
+
+                size_t mySizes = p->sizes();
+
+                PidStatisticsCollection::iterator q;
+                unsigned char num = 0;
+                for (q = pids.begin(); q != pids.end(); ++q) {
+                    if (mySizes > (*q)->sizes()) {
+                        pids.insert(q, p);
+                        break;
+                    }
+                    // do we need to traverse deeper in the list?
+                    if (++num > num_spammers) {
+                        break;
+                    }
+                }
+                if (q == pids.end()) {
+                   pids.push_back(p);
+                }
+            }
+        }
+
+        size_t threshold = sizes(i);
+        if (threshold < 65536) {
+            threshold = 65536;
+        }
+        threshold /= 100;
+
+        PidStatisticsCollection::iterator pt = pids.begin();
+
+        for(int line = 0;
+                (pt != pids.end()) && (line < num_spammers);
+                ++line, pt = pids.erase(pt)) {
+            PidStatistics *p = *pt;
+
+            size_t sizes = p->sizes();
+            if (sizes < threshold) {
+                break;
+            }
+
+            char *name = p->getName();
+            pid_t pid = p->getPid();
+            if (!name || !*name) {
+                name = pidToName(pid);
+                if (name) {
+                    if (*name) {
+                        p->setName(name);
+                    } else {
+                        free(name);
+                        name = NULL;
+                    }
+                }
+            }
+
+            if (!header) {
+                string.appendFormat("\n\nChattiest clients:\n"
+                                    "log id %-*s PID[?] name",
+                                    spaces_total, "size/total");
+                header = true;
+            }
+
+            size_t sizesTotal = p->sizesTotal();
+
+            android::String8 sz("");
+            sz.appendFormat((sizes != sizesTotal) ? "%zu/%zu" : "%zu",
+                            sizes, sizesTotal);
+
+            android::String8 pd("");
+            pd.appendFormat("%u%c", pid, p->pidGone() ? '?' : ' ');
+
+            string.appendFormat("\n%-7s%-*s %-7s%s",
+                                line ? "" : android_log_id_to_name(i),
+                                spaces_total, sz.string(), pd.string(),
+                                name ? name : "");
+        }
+
+        pids.clear();
+    }
+
     if (dgram_qlen_statistics) {
         const unsigned short spaces_time = 6;
         const unsigned long long max_seconds = 100000;
@@ -562,7 +740,7 @@
             continue;
         }
 
-        bool header = false;
+        header = false;
         bool first = true;
 
         UidStatisticsCollection::iterator ut;
@@ -602,15 +780,16 @@
             spaces = 0;
 
             uid_t u = up->getUid();
-            pid_t p = (*pt)->getPid();
+            PidStatistics *pp = *pt;
+            pid_t p = pp->getPid();
 
             intermediate = string.format(oneline
                                              ? ((p == PidStatistics::gone)
                                                  ? "%d/?"
-                                                 : "%d/%d")
+                                                 : "%d/%d%c")
                                              : "%d",
-                                         u, p);
-            string.appendFormat((first) ? "\n%-12s" : "%-12s",
+                                         u, p, pp->pidGone() ? '?' : '\0');
+            string.appendFormat(first ? "\n%-12s" : "%-12s",
                                 intermediate.string());
             intermediate.clear();
 
@@ -646,8 +825,8 @@
             size_t gone_els = 0;
 
             for(; pt != up->end(); ++pt) {
-                PidStatistics *pp = *pt;
-                pid_t p = pp->getPid();
+                pp = *pt;
+                p = pp->getPid();
 
                 // If a PID no longer has any current logs, and is not
                 // active anymore, skip & report totals for gone.
@@ -659,7 +838,7 @@
                     continue;
                 }
                 els = pp->elements();
-                bool gone = kill(p, 0);
+                bool gone = pp->pidGone();
                 if (gone && (els == 0)) {
                     // ToDo: garbage collection: move this statistical bucket
                     //       from its current UID/PID to UID/? (races and
@@ -676,8 +855,8 @@
                 }
                 spaces = 0;
 
-                intermediate = string.format((gone) ? "%d/%d?" : "%d/%d", u, p);
-                string.appendFormat((first) ? "\n%-12s" : "%-12s",
+                intermediate = string.format(gone ? "%d/%d?" : "%d/%d", u, p);
+                string.appendFormat(first ? "\n%-12s" : "%-12s",
                                     intermediate.string());
                 intermediate.clear();
 
@@ -711,7 +890,7 @@
                 }
 
                 intermediate = string.format("%d/?", u);
-                string.appendFormat((first) ? "\n%-12s" : "%-12s",
+                string.appendFormat(first ? "\n%-12s" : "%-12s",
                                     intermediate.string());
                 intermediate.clear();
 
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 12c68d5..3733137 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -37,6 +37,7 @@
     size_t mElements;
 
     char *name;
+    bool mGone;
 
 public:
     static const pid_t gone = (pid_t) -1;
@@ -46,6 +47,7 @@
     ~PidStatistics();
 
     pid_t getPid() const { return pid; }
+    bool pidGone();
     char *getName() const { return name; }
     void setName(char *name);
 
@@ -70,6 +72,9 @@
 
     PidStatisticsCollection Pids;
 
+    size_t mSizes;
+    size_t mElements;
+
 public:
     UidStatistics(uid_t uid);
     ~UidStatistics();
@@ -81,11 +86,17 @@
 
     void add(unsigned short size, pid_t pid);
     void subtract(unsigned short size, pid_t pid);
+    void sort();
 
     static const pid_t pid_all = (pid_t) -1;
 
-    size_t sizes(pid_t pid = pid_all);
-    size_t elements(pid_t pid = pid_all);
+    // fast track current value
+    size_t sizes() const { return mSizes; };
+    size_t elements() const { return mElements; };
+
+    // statistical track
+    size_t sizes(pid_t pid);
+    size_t elements(pid_t pid);
 
     size_t sizesTotal(pid_t pid = pid_all);
     size_t elementsTotal(pid_t pid = pid_all);
@@ -108,6 +119,7 @@
 
     void add(unsigned short size, uid_t uid, pid_t pid);
     void subtract(unsigned short size, uid_t uid, pid_t pid);
+    void sort();
 
     static const pid_t pid_all = (pid_t) -1;
     static const uid_t uid_all = (uid_t) -1;
@@ -145,6 +157,7 @@
 
     void add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
     void subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
+    void sort();
 
     // fast track current value by id only
     size_t sizes(log_id_t id) const { return mSizes[id]; }
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index c32ac2d..1a9a548 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <sys/prctl.h>
+
 #include "FlushCommand.h"
 #include "LogBuffer.h"
 #include "LogTimes.h"
@@ -107,6 +109,8 @@
 }
 
 void *LogTimeEntry::threadStart(void *obj) {
+    prctl(PR_SET_NAME, "logd.reader.per");
+
     LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
 
     pthread_cleanup_push(threadStop, obj);
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index 2c10861..c6c7b23 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#ifdef USERDEBUG_BUILD
-
 #include <ctype.h>
 
 #include <utils/String8.h>
@@ -49,7 +47,7 @@
 }
 
 PruneList::PruneList()
-        : mWorstUidEnabled(false) {
+        : mWorstUidEnabled(true) {
     mNaughty.clear();
     mNice.clear();
 }
@@ -239,5 +237,3 @@
     }
     return false;
 }
-
-#endif // USERDEBUG_BUILD
diff --git a/logd/README.property b/logd/README.property
new file mode 100644
index 0000000..5d92d09
--- /dev/null
+++ b/logd/README.property
@@ -0,0 +1,12 @@
+The properties that logd responds to are:
+
+name                       type default  description
+logd.auditd                 bool  true   Enable selinux audit daemon
+logd.auditd.dmesg           bool  true   selinux audit messages duplicated and
+                                         sent on to dmesg log
+logd.statistics.dgram_qlen  bool  false  Record dgram_qlen statistics. This
+                                         represents a performance impact and
+                                         is used to determine the platform's
+                                         minimum domain socket network FIFO
+                                         size (see source for details) based
+                                         on typical load (logcat -S to view)
diff --git a/logd/main.cpp b/logd/main.cpp
index 7346e2f..ece5a3a 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -36,6 +36,35 @@
 #include "LogListener.h"
 #include "LogAudit.h"
 
+//
+//  The service is designed to be run by init, it does not respond well
+// to starting up manually. When starting up manually the sockets will
+// fail to open typically for one of the following reasons:
+//     EADDRINUSE if logger is running.
+//     EACCESS if started without precautions (below)
+//
+// Here is a cookbook procedure for starting up logd manually assuming
+// init is out of the way, pedantically all permissions and selinux
+// security is put back in place:
+//
+//    setenforce 0
+//    rm /dev/socket/logd*
+//    chmod 777 /dev/socket
+//        # here is where you would attach the debugger or valgrind for example
+//    runcon u:r:logd:s0 /system/bin/logd </dev/null >/dev/null 2>&1 &
+//    sleep 1
+//    chmod 755 /dev/socket
+//    chown logd.logd /dev/socket/logd*
+//    restorecon /dev/socket/logd*
+//    setenforce 1
+//
+// If minimalism prevails, typical for debugging and security is not a concern:
+//
+//    setenforce 0
+//    chmod 777 /dev/socket
+//    logd
+//
+
 static int drop_privs() {
     struct sched_param param;
     memset(&param, 0, sizeof(param));
@@ -78,16 +107,31 @@
     return 0;
 }
 
+// Property helper
+static bool property_get_bool(const char *key, bool def) {
+    char property[PROPERTY_VALUE_MAX];
+    property_get(key, property, "");
+
+    if (!strcasecmp(property, "true")) {
+        return true;
+    }
+    if (!strcasecmp(property, "false")) {
+        return false;
+    }
+
+    return def;
+}
+
 // Foreground waits for exit of the three main persistent threads that
 // are started here.  The three threads are created to manage UNIX
 // domain client sockets for writing, reading and controlling the user
 // space logger.  Additional transitory per-client threads are created
 // for each reader once they register.
 int main() {
+    bool auditd = property_get_bool("logd.auditd", true);
+
     int fdDmesg = -1;
-    char dmesg[PROPERTY_VALUE_MAX];
-    property_get("logd.auditd.dmesg", dmesg, "1");
-    if (atol(dmesg)) {
+    if (auditd && property_get_bool("logd.auditd.dmesg", true)) {
         fdDmesg = open("/dev/kmsg", O_WRONLY);
     }
 
@@ -106,9 +150,7 @@
 
     LogBuffer *logBuf = new LogBuffer(times);
 
-    char dgram_qlen_statistics[PROPERTY_VALUE_MAX];
-    property_get("logd.dgram_qlen.statistics", dgram_qlen_statistics, "");
-    if (atol(dgram_qlen_statistics)) {
+    if (property_get_bool("logd.statistics.dgram_qlen", false)) {
         logBuf->enableDgramQlenStatistics();
     }
 
@@ -142,11 +184,13 @@
     // initiated log messages. New log entries are added to LogBuffer
     // and LogReader is notified to send updates to connected clients.
 
-    // failure is an option ... messages are in dmesg (required by standard)
-    LogAudit *al = new LogAudit(logBuf, reader, fdDmesg);
-    if (al->startListener()) {
-        delete al;
-        close(fdDmesg);
+    if (auditd) {
+        // failure is an option ... messages are in dmesg (required by standard)
+        LogAudit *al = new LogAudit(logBuf, reader, fdDmesg);
+        if (al->startListener()) {
+            delete al;
+            close(fdDmesg);
+        }
     }
 
     pause();
diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk
new file mode 100644
index 0000000..123e317
--- /dev/null
+++ b/logd/tests/Android.mk
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# -----------------------------------------------------------------------------
+# Benchmarks. (see ../../liblog/tests)
+# -----------------------------------------------------------------------------
+
+test_module_prefix := logd-
+test_tags := tests
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
+
+test_c_flags := \
+    -fstack-protector-all \
+    -g \
+    -Wall -Wextra \
+    -Werror \
+    -fno-builtin \
+
+ifeq ($(TARGET_USES_LOGD),true)
+test_c_flags += -DTARGET_USES_LOGD=1
+endif
+
+test_src_files := \
+    logd_test.cpp
+
+# Build tests for the logger. Run with:
+#   adb shell /data/nativetest/logd-unit-tests/logd-unit-tests
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(test_module_prefix)unit-tests
+LOCAL_MODULE_TAGS := $(test_tags)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += $(test_c_flags)
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_SRC_FILES := $(test_src_files)
+include $(BUILD_NATIVE_TEST)
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
new file mode 100644
index 0000000..731aff6
--- /dev/null
+++ b/logd/tests/logd_test.cpp
@@ -0,0 +1,679 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gtest/gtest.h>
+
+#include "cutils/sockets.h"
+#include "log/log.h"
+#include "log/logger.h"
+
+#define __unused __attribute__((__unused__))
+
+/*
+ * returns statistics
+ */
+static void my_android_logger_get_statistics(char *buf, size_t len)
+{
+    snprintf(buf, len, "getStatistics 0 1 2 3 4");
+    int sock = socket_local_client("logd",
+                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_STREAM);
+    if (sock >= 0) {
+        if (write(sock, buf, strlen(buf) + 1) > 0) {
+            ssize_t ret;
+            while ((ret = read(sock, buf, len)) > 0) {
+                if ((size_t)ret == len) {
+                    break;
+                }
+                len -= ret;
+                buf += ret;
+
+                struct pollfd p = {
+                    .fd = sock,
+                    .events = POLLIN,
+                    .revents = 0
+                };
+
+                ret = poll(&p, 1, 20);
+                if ((ret <= 0) || !(p.revents & POLLIN)) {
+                    break;
+                }
+            }
+        }
+        close(sock);
+    }
+}
+
+static void alloc_statistics(char **buffer, size_t *length)
+{
+    size_t len = 8192;
+    char *buf;
+
+    for(int retry = 32; (retry >= 0); delete [] buf, --retry) {
+        buf = new char [len];
+        my_android_logger_get_statistics(buf, len);
+
+        buf[len-1] = '\0';
+        size_t ret = atol(buf) + 1;
+        if (ret < 4) {
+            delete [] buf;
+            buf = NULL;
+            break;
+        }
+        bool check = ret <= len;
+        len = ret;
+        if (check) {
+            break;
+        }
+        len += len / 8; // allow for some slop
+    }
+    *buffer = buf;
+    *length = len;
+}
+
+static char *find_benchmark_spam(char *cp)
+{
+    // liblog_benchmarks has been run designed to SPAM.  The signature of
+    // a noisiest UID statistics is one of the following:
+    //
+    // main: UID/PID Total size/num   Now          UID/PID[?]  Total
+    // 0           7500306/304207     71608/3183   0/4225?     7454388/303656
+    //    <wrap>                                                     93432/1012
+    // -or-
+    // 0/gone      7454388/303656     93432/1012
+    //
+    // basically if we see a *large* number of 0/????? entries
+    unsigned long value;
+    do {
+        char *benchmark = strstr(cp, " 0/");
+        char *benchmark_newline = strstr(cp, "\n0/");
+        if (!benchmark) {
+            benchmark = benchmark_newline;
+        }
+        if (benchmark_newline && (benchmark > benchmark_newline)) {
+            benchmark = benchmark_newline;
+        }
+        cp = benchmark;
+        if (!cp) {
+            break;
+        }
+        cp += 3;
+        while (isdigit(*cp) || (*cp == 'g') || (*cp == 'o') || (*cp == 'n')) {
+            ++cp;
+        }
+        value = 0;
+        // ###? or gone
+        if ((*cp == '?') || (*cp == 'e')) {
+            while (*++cp == ' ');
+            while (isdigit(*cp)) {
+                value = value * 10ULL + *cp - '0';
+                ++cp;
+            }
+            if (*cp != '/') {
+                value = 0;
+                continue;
+            }
+            while (isdigit(*++cp));
+            while (*cp == ' ') ++cp;
+            if (!isdigit(*cp)) {
+                value = 0;
+            }
+        }
+    } while ((value < 900000ULL) && *cp);
+    return cp;
+}
+
+TEST(logd, statistics) {
+    size_t len;
+    char *buf;
+
+    alloc_statistics(&buf, &len);
+
+#ifdef TARGET_USES_LOGD
+    ASSERT_TRUE(NULL != buf);
+#else
+    if (!buf) {
+        return;
+    }
+#endif
+
+    // remove trailing FF
+    char *cp = buf + len - 1;
+    *cp = '\0';
+    bool truncated = *--cp != '\f';
+    if (!truncated) {
+        *cp = '\0';
+    }
+
+    // squash out the byte count
+    cp = buf;
+    if (!truncated) {
+        while (isdigit(*cp) || (*cp == '\n')) {
+            ++cp;
+        }
+    }
+
+    fprintf(stderr, "%s", cp);
+
+    EXPECT_LT((size_t)64, strlen(cp));
+
+    EXPECT_EQ(0, truncated);
+
+#ifdef TARGET_USES_LOGD
+    char *main_logs = strstr(cp, "\nmain:");
+    EXPECT_TRUE(NULL != main_logs);
+
+    char *radio_logs = strstr(cp, "\nradio:");
+    EXPECT_TRUE(NULL != radio_logs);
+
+    char *system_logs = strstr(cp, "\nsystem:");
+    EXPECT_TRUE(NULL != system_logs);
+
+    char *events_logs = strstr(cp, "\nevents:");
+    EXPECT_TRUE(NULL != events_logs);
+#endif
+
+    // Parse timing stats
+
+    cp = strstr(cp, "Minimum time between log events per dgram_qlen:");
+
+    char *log_events_per_span = cp;
+
+    if (cp) {
+        while (*cp && (*cp != '\n')) {
+            ++cp;
+        }
+        if (*cp == '\n') {
+            ++cp;
+        }
+
+        char *list_of_spans = cp;
+        EXPECT_NE('\0', *list_of_spans);
+
+        unsigned short number_of_buckets = 0;
+        unsigned short *dgram_qlen = NULL;
+        unsigned short bucket = 0;
+        while (*cp && (*cp != '\n')) {
+            bucket = 0;
+            while (isdigit(*cp)) {
+                bucket = bucket * 10 + *cp - '0';
+                ++cp;
+            }
+            while (*cp == ' ') {
+                ++cp;
+            }
+            if (!bucket) {
+                break;
+            }
+            unsigned short *new_dgram_qlen = new unsigned short[number_of_buckets + 1];
+            EXPECT_TRUE(new_dgram_qlen != NULL);
+            if (dgram_qlen) {
+                memcpy(new_dgram_qlen, dgram_qlen, sizeof(*dgram_qlen) * number_of_buckets);
+                delete [] dgram_qlen;
+            }
+
+            dgram_qlen = new_dgram_qlen;
+            dgram_qlen[number_of_buckets++] = bucket;
+        }
+
+        char *end_of_spans = cp;
+        EXPECT_NE('\0', *end_of_spans);
+
+        EXPECT_LT(5, number_of_buckets);
+
+        unsigned long long *times = new unsigned long long [number_of_buckets];
+        ASSERT_TRUE(times != NULL);
+
+        memset(times, 0, sizeof(*times) * number_of_buckets);
+
+        while (*cp == '\n') {
+            ++cp;
+        }
+
+        unsigned short number_of_values = 0;
+        unsigned long long value;
+        while (*cp && (*cp != '\n')) {
+            EXPECT_GE(number_of_buckets, number_of_values);
+
+            value = 0;
+            while (isdigit(*cp)) {
+                value = value * 10ULL + *cp - '0';
+                ++cp;
+            }
+
+            switch(*cp) {
+            case ' ':
+            case '\n':
+                value *= 1000ULL;
+                /* FALLTHRU */
+            case 'm':
+                value *= 1000ULL;
+                /* FALLTHRU */
+            case 'u':
+                value *= 1000ULL;
+                /* FALLTHRU */
+            case 'n':
+            default:
+                break;
+            }
+            while (*++cp == ' ');
+
+            if (!value) {
+                break;
+            }
+
+            times[number_of_values] = value;
+            ++number_of_values;
+        }
+
+#ifdef TARGET_USES_LOGD
+        EXPECT_EQ(number_of_values, number_of_buckets);
+#endif
+
+        FILE *fp;
+        ASSERT_TRUE(NULL != (fp = fopen("/proc/sys/net/unix/max_dgram_qlen", "r")));
+
+        unsigned max_dgram_qlen = 0;
+        fscanf(fp, "%u", &max_dgram_qlen);
+
+        fclose(fp);
+
+        // Find launch point
+        unsigned short launch = 0;
+        unsigned long long total = 0;
+        do {
+            total += times[launch];
+        } while (((++launch < number_of_buckets)
+                && ((total / launch) >= (times[launch] / 8ULL)))
+            || (launch == 1)); // too soon
+
+        bool failure = number_of_buckets <= launch;
+        if (!failure) {
+            unsigned short l = launch;
+            if (l >= number_of_buckets) {
+                l = number_of_buckets - 1;
+            }
+            failure = max_dgram_qlen < dgram_qlen[l];
+        }
+
+        // We can get failure if at any time liblog_benchmarks has been run
+        // because designed to overload /proc/sys/net/unix/max_dgram_qlen even
+        // at excessive values like 20000. It does so to measure the raw processing
+        // performance of logd.
+        if (failure) {
+            cp = find_benchmark_spam(cp);
+        }
+
+        if (cp) {
+            // Fake a failure, but without the failure code
+            if (number_of_buckets <= launch) {
+                printf ("Expected: number_of_buckets > launch, actual: %u vs %u\n",
+                        number_of_buckets, launch);
+            }
+            if (launch >= number_of_buckets) {
+                launch = number_of_buckets - 1;
+            }
+            if (max_dgram_qlen < dgram_qlen[launch]) {
+                printf ("Expected: max_dgram_qlen >= dgram_qlen[%d],"
+                            " actual: %u vs %u\n",
+                        launch, max_dgram_qlen, dgram_qlen[launch]);
+            }
+        } else
+#ifndef TARGET_USES_LOGD
+        if (total)
+#endif
+        {
+            EXPECT_GT(number_of_buckets, launch);
+            if (launch >= number_of_buckets) {
+                launch = number_of_buckets - 1;
+            }
+            EXPECT_GE(max_dgram_qlen, dgram_qlen[launch]);
+        }
+
+        delete [] dgram_qlen;
+        delete [] times;
+    }
+    delete [] buf;
+}
+
+static void caught_signal(int signum __unused) { }
+
+static void dump_log_msg(const char *prefix,
+                         log_msg *msg, unsigned int version, int lid) {
+    switch(msg->entry.hdr_size) {
+    case 0:
+        version = 1;
+        break;
+
+    case sizeof(msg->entry_v2):
+        if (version == 0) {
+            version = 2;
+        }
+        break;
+    }
+
+    fprintf(stderr, "%s: v%u[%u] ", prefix, version, msg->len());
+    if (version != 1) {
+        fprintf(stderr, "hdr_size=%u ", msg->entry.hdr_size);
+    }
+    fprintf(stderr, "pid=%u tid=%u %u.%09u ",
+            msg->entry.pid, msg->entry.tid, msg->entry.sec, msg->entry.nsec);
+    switch(version) {
+    case 1:
+         break;
+    case 2:
+        fprintf(stderr, "euid=%u ", msg->entry_v2.euid);
+        break;
+    case 3:
+    default:
+        lid = msg->entry.lid;
+        break;
+    }
+
+    switch(lid) {
+    case 0:
+        fprintf(stderr, "lid=main ");
+        break;
+    case 1:
+        fprintf(stderr, "lid=radio ");
+        break;
+    case 2:
+        fprintf(stderr, "lid=events ");
+        break;
+    case 3:
+        fprintf(stderr, "lid=system ");
+        break;
+    default:
+        if (lid >= 0) {
+            fprintf(stderr, "lid=%d ", lid);
+        }
+    }
+
+    unsigned int len = msg->entry.len;
+    fprintf(stderr, "msg[%u]={", len);
+    unsigned char *cp = reinterpret_cast<unsigned char *>(msg->msg());
+    while(len) {
+        unsigned char *p = cp;
+        while (*p && (((' ' <= *p) && (*p < 0x7F)) || (*p == '\n'))) {
+            ++p;
+        }
+        if (((p - cp) > 3) && !*p && ((unsigned int)(p - cp) < len)) {
+            fprintf(stderr, "\"");
+            while (*cp) {
+                fprintf(stderr, (*cp != '\n') ? "%c" : "\\n", *cp);
+                ++cp;
+                --len;
+            }
+            fprintf(stderr, "\"");
+        } else {
+            fprintf(stderr, "%02x", *cp);
+        }
+        ++cp;
+        if (--len) {
+            fprintf(stderr, ", ");
+        }
+    }
+    fprintf(stderr, "}\n");
+}
+
+TEST(logd, both) {
+    log_msg msg;
+
+    // check if we can read any logs from logd
+    bool user_logger_available = false;
+    bool user_logger_content = false;
+
+    int fd = socket_local_client("logdr",
+                                 ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                 SOCK_SEQPACKET);
+    if (fd >= 0) {
+        struct sigaction ignore, old_sigaction;
+        memset(&ignore, 0, sizeof(ignore));
+        ignore.sa_handler = caught_signal;
+        sigemptyset(&ignore.sa_mask);
+        sigaction(SIGALRM, &ignore, &old_sigaction);
+        unsigned int old_alarm = alarm(10);
+
+        static const char ask[] = "dumpAndClose lids=0,1,2,3";
+        user_logger_available = write(fd, ask, sizeof(ask)) == sizeof(ask);
+
+        user_logger_content = recv(fd, msg.buf, sizeof(msg), 0) > 0;
+
+        if (user_logger_content) {
+            dump_log_msg("user", &msg, 3, -1);
+        }
+
+        alarm(0);
+        sigaction(SIGALRM, &old_sigaction, NULL);
+
+        close(fd);
+    }
+
+    // check if we can read any logs from kernel logger
+    bool kernel_logger_available = false;
+    bool kernel_logger_content = false;
+
+    static const char *loggers[] = {
+        "/dev/log/main",   "/dev/log_main",
+        "/dev/log/radio",  "/dev/log_radio",
+        "/dev/log/events", "/dev/log_events",
+        "/dev/log/system", "/dev/log_system",
+    };
+
+    for (unsigned int i = 0; i < (sizeof(loggers) / sizeof(loggers[0])); ++i) {
+        fd = open(loggers[i], O_RDONLY);
+        if (fd < 0) {
+            continue;
+        }
+        kernel_logger_available = true;
+        fcntl(fd, F_SETFL, O_RDONLY | O_NONBLOCK);
+        int result = TEMP_FAILURE_RETRY(read(fd, msg.buf, sizeof(msg)));
+        if (result > 0) {
+            kernel_logger_content = true;
+            dump_log_msg("kernel", &msg, 0, i / 2);
+        }
+        close(fd);
+    }
+
+    static const char yes[] = "\xE2\x9C\x93";
+    static const char no[] = "\xE2\x9c\x98";
+    fprintf(stderr,
+            "LOGGER  Available  Content\n"
+            "user    %-13s%s\n"
+            "kernel  %-13s%s\n"
+            " status %-11s%s\n",
+            (user_logger_available)   ? yes : no,
+            (user_logger_content)     ? yes : no,
+            (kernel_logger_available) ? yes : no,
+            (kernel_logger_content)   ? yes : no,
+            (user_logger_available && kernel_logger_available) ? "WARNING" : "ok",
+            (user_logger_content && kernel_logger_content) ? "ERROR" : "ok");
+
+    if (user_logger_available && kernel_logger_available) {
+        printf("WARNING: kernel & user logger; both consuming resources!!!\n");
+    }
+
+    EXPECT_EQ(0, user_logger_content && kernel_logger_content);
+    EXPECT_EQ(0, !user_logger_content && !kernel_logger_content);
+}
+
+// BAD ROBOT
+//   Benchmark threshold are generally considered bad form unless there is
+//   is some human love applied to the continued maintenance and whether the
+//   thresholds are tuned on a per-target basis. Here we check if the values
+//   are more than double what is expected. Doubling will not prevent failure
+//   on busy or low-end systems that could have a tendency to stretch values.
+//
+//   The primary goal of this test is to simulate a spammy app (benchmark
+//   being the worst) and check to make sure the logger can deal with it
+//   appropriately by checking all the statistics are in an expected range.
+//
+TEST(logd, benchmark) {
+    size_t len;
+    char *buf;
+
+    alloc_statistics(&buf, &len);
+    bool benchmark_already_run = buf && find_benchmark_spam(buf);
+    delete [] buf;
+
+    if (benchmark_already_run) {
+        fprintf(stderr, "WARNING: spam already present and too much history\n"
+                        "         false OK for prune by worst UID check\n");
+    }
+
+    FILE *fp;
+
+    // Introduce some extreme spam for the worst UID filter
+    ASSERT_TRUE(NULL != (fp = popen(
+        "/data/nativetest/liblog-benchmarks/liblog-benchmarks",
+        "r")));
+
+    char buffer[5120];
+
+    static const char *benchmarks[] = {
+        "BM_log_maximum_retry ",
+        "BM_log_maximum ",
+        "BM_clock_overhead ",
+        "BM_log_overhead ",
+        "BM_log_latency ",
+        "BM_log_delay "
+    };
+    static const unsigned int log_maximum_retry = 0;
+    static const unsigned int log_maximum = 1;
+    static const unsigned int clock_overhead = 2;
+    static const unsigned int log_overhead = 3;
+    static const unsigned int log_latency = 4;
+    static const unsigned int log_delay = 5;
+
+    unsigned long ns[sizeof(benchmarks) / sizeof(benchmarks[0])];
+
+    memset(ns, 0, sizeof(ns));
+
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
+            if (strncmp(benchmarks[i], buffer, strlen(benchmarks[i]))) {
+                continue;
+            }
+            sscanf(buffer, "%*s %lu %lu", &ns[i], &ns[i]);
+            fprintf(stderr, "%-22s%8lu\n", benchmarks[i], ns[i]);
+        }
+    }
+    int ret = pclose(fp);
+
+    if (!WIFEXITED(ret) || (WEXITSTATUS(ret) == 127)) {
+        fprintf(stderr,
+                "WARNING: "
+                "/data/nativetest/liblog-benchmarks/liblog-benchmarks missing\n"
+                "         can not perform test\n");
+        return;
+    }
+
+#ifdef TARGET_USES_LOGD
+    EXPECT_GE(100000UL, ns[log_maximum_retry]); // 42777 user
+#else
+    EXPECT_GE(10000UL, ns[log_maximum_retry]); // 5636 kernel
+#endif
+
+#ifdef TARGET_USES_LOGD
+    EXPECT_GE(25000UL, ns[log_maximum]); // 14055 user
+#else
+    EXPECT_GE(10000UL, ns[log_maximum]); // 5637 kernel
+#endif
+
+    EXPECT_GE(4000UL, ns[clock_overhead]); // 2008
+
+#ifdef TARGET_USES_LOGD
+    EXPECT_GE(250000UL, ns[log_overhead]); // 113219 user
+#else
+    EXPECT_GE(100000UL, ns[log_overhead]); // 50945 kernel
+#endif
+
+#ifdef TARGET_USES_LOGD
+    EXPECT_GE(7500UL, ns[log_latency]); // 3718 user space
+#else
+    EXPECT_GE(500000UL, ns[log_latency]); // 254200 kernel
+#endif
+
+#ifdef TARGET_USES_LOGD
+    EXPECT_GE(20000000UL, ns[log_delay]); // 9542541 user
+#else
+    EXPECT_GE(55000UL, ns[log_delay]); // 27341 kernel
+#endif
+
+    for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
+        EXPECT_NE(0UL, ns[i]);
+    }
+
+    alloc_statistics(&buf, &len);
+
+#ifdef TARGET_USES_LOGD
+    bool collected_statistics = !!buf;
+    EXPECT_EQ(true, collected_statistics);
+#else
+    if (!buf) {
+        return;
+    }
+#endif
+
+    ASSERT_TRUE(NULL != buf);
+
+    char *benchmark_statistics_found = find_benchmark_spam(buf);
+    ASSERT_TRUE(benchmark_statistics_found != NULL);
+
+    // Check how effective the SPAM filter is, parse out Now size.
+    //             Total               Now
+    // 0/4225?     7454388/303656      31488/755
+    //                                 ^-- benchmark_statistics_found
+
+    unsigned long nowSize = atol(benchmark_statistics_found);
+
+    delete [] buf;
+
+    ASSERT_NE(0UL, nowSize);
+
+    int sock = socket_local_client("logd",
+                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_STREAM);
+    static const unsigned long expected_absolute_minimum_log_size = 65536UL;
+    unsigned long totalSize = expected_absolute_minimum_log_size;
+    if (sock >= 0) {
+        static const char getSize[] = {
+            'g', 'e', 't', 'L', 'o', 'g', 'S', 'i', 'z', 'e', ' ',
+            LOG_ID_MAIN + '0', '\0'
+        };
+        if (write(sock, getSize, sizeof(getSize)) > 0) {
+            char buffer[80];
+            memset(buffer, 0, sizeof(buffer));
+            read(sock, buffer, sizeof(buffer));
+            totalSize = atol(buffer);
+            if (totalSize < expected_absolute_minimum_log_size) {
+                totalSize = expected_absolute_minimum_log_size;
+            }
+        }
+        close(sock);
+    }
+    // logd allows excursions to 110% of total size
+    totalSize = (totalSize * 11 ) / 10;
+
+    // 50% threshold for SPAM filter (<20% typical, lots of engineering margin)
+    ASSERT_GT(totalSize, nowSize * 2);
+}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a07790a..0ef097c 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -177,6 +177,9 @@
     chown system log /proc/last_kmsg
     chmod 0440 /proc/last_kmsg
 
+    # make the selinux kernel policy world-readable
+    chmod 0444 /sys/fs/selinux/policy
+
     # create the lost+found directories, so as to enforce our permissions
     mkdir /cache/lost+found 0770 root root
 
@@ -369,13 +372,13 @@
     setprop net.tcp.buffersize.wifi     524288,1048576,2097152,262144,524288,1048576
     setprop net.tcp.buffersize.ethernet 524288,1048576,3145728,524288,1048576,2097152
     setprop net.tcp.buffersize.lte      524288,1048576,2097152,262144,524288,1048576
-    setprop net.tcp.buffersize.umts     4094,87380,110208,4096,16384,110208
-    setprop net.tcp.buffersize.hspa     4094,87380,262144,4096,16384,262144
-    setprop net.tcp.buffersize.hsupa    4094,87380,262144,4096,16384,262144
-    setprop net.tcp.buffersize.hsdpa    4094,87380,262144,4096,16384,262144
-    setprop net.tcp.buffersize.hspap    4094,87380,1220608,4096,16384,1220608
-    setprop net.tcp.buffersize.edge     4093,26280,35040,4096,16384,35040
-    setprop net.tcp.buffersize.gprs     4092,8760,11680,4096,8760,11680
+    setprop net.tcp.buffersize.umts     58254,349525,1048576,58254,349525,1048576
+    setprop net.tcp.buffersize.hspa     40778,244668,734003,16777,100663,301990
+    setprop net.tcp.buffersize.hsupa    40778,244668,734003,16777,100663,301990
+    setprop net.tcp.buffersize.hsdpa    61167,367002,1101005,8738,52429,262114
+    setprop net.tcp.buffersize.hspap    122334,734003,2202010,32040,192239,576717
+    setprop net.tcp.buffersize.edge     4093,26280,70800,4096,16384,70800
+    setprop net.tcp.buffersize.gprs     4092,8760,48000,4096,8760,48000
     setprop net.tcp.buffersize.evdo     4094,87380,262144,4096,16384,262144
 
     class_start core
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
new file mode 100644
index 0000000..3d60a31
--- /dev/null
+++ b/rootdir/init.zygote32_64.rc
@@ -0,0 +1,12 @@
+service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
+    class main
+    socket zygote stream 660 root system
+    onrestart write /sys/android_power/request_state wake
+    onrestart write /sys/power/state on
+    onrestart restart media
+    onrestart restart netd
+
+service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
+    class main
+    socket zygote_secondary stream 660 root system
+    onrestart restart zygote
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index b8fe716..eff24c3 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -91,3 +91,5 @@
 /sys/devices/virtual/input/input*   enable      0660  root   input
 /sys/devices/virtual/input/input*   poll_delay  0660  root   input
 /sys/devices/virtual/usb_composite/*   enable      0664  root   system
+/sys/devices/system/cpu/cpu*   cpufreq/scaling_max_freq   0664  system system
+/sys/devices/system/cpu/cpu*   cpufreq/scaling_min_freq   0664  system system
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 3deb3e7..5383b83 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -95,6 +95,7 @@
 LOCAL_C_INCLUDES := bionic/libc/bionic
 
 LOCAL_CFLAGS += \
+    -std=gnu99 \
     -Wno-unused-parameter \
     -include bsd-compatibility.h \
 
diff --git a/toolbox/date.c b/toolbox/date.c
index d6c9052..aa3b72e 100644
--- a/toolbox/date.c
+++ b/toolbox/date.c
@@ -1,10 +1,13 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <string.h>
-#include <errno.h>
 #include <time.h>
+#include <unistd.h>
+
 #include <linux/android_alarm.h>
 #include <linux/rtc.h>
 #include <sys/ioctl.h>
@@ -108,6 +111,33 @@
         settime_rtc_tm(&tm);
 }
 
+static char *parse_time(const char *str, struct timeval *ts) {
+  char *s;
+  long fs = 0; /* fractional seconds */
+
+  ts->tv_sec = strtoumax(str, &s, 10);
+
+  if (*s == '.') {
+    s++;
+    int count = 0;
+
+    /* read up to 6 digits (microseconds) */
+    while (*s && isdigit(*s)) {
+      if (++count < 7) {
+        fs = fs*10 + (*s - '0');
+      }
+      s++;
+    }
+
+    for (; count < 6; count++) {
+      fs *= 10;
+    }
+  }
+
+  ts->tv_usec = fs;
+  return s;
+}
+
 int date_main(int argc, char *argv[])
 {
 	int c;
@@ -181,7 +211,7 @@
         //strptime(argv[optind], NULL, &tm);
         //tv.tv_sec = mktime(&tm);
         //tv.tv_usec = 0;
-        strtotimeval(argv[optind], &tv);
+        parse_time(argv[optind], &tv);
         printf("time %s -> %lu.%lu\n", argv[optind], tv.tv_sec, tv.tv_usec);
         res = settime_alarm_timeval(&tv);
         if (res < 0)
diff --git a/toolbox/syren.c b/toolbox/syren.c
index 06e329e..47c2460 100644
--- a/toolbox/syren.c
+++ b/toolbox/syren.c
@@ -123,7 +123,11 @@
 
 	r = find_reg(argv[2]);
 	if (r == NULL) {
-		strcpy(name, argv[2]);
+		if(strlen(argv[2]) >= sizeof(name)){
+			fprintf(stderr, "REGNAME too long\n");
+			return 0;
+		}
+		strlcpy(name, argv[2], sizeof(name));
 		char *addr_str = strchr(argv[2], ':');
 		if (addr_str == NULL)
 			return usage();
@@ -131,7 +135,7 @@
 		sio.page = strtoul(argv[2], 0, 0);
 		sio.addr = strtoul(addr_str, 0, 0);
 	} else {
-		strcpy(name, r->name);
+		strlcpy(name, r->name, sizeof(name));
 		sio.page = r->page;
 		sio.addr = r->addr;
 	}
diff --git a/toolbox/top.c b/toolbox/top.c
index 7642522..7382f1f 100644
--- a/toolbox/top.c
+++ b/toolbox/top.c
@@ -9,7 +9,7 @@
  *    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 
+ *    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
@@ -22,7 +22,7 @@
  * 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 
+ * 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
@@ -108,16 +108,20 @@
 static int numcmp(long long a, long long b);
 static void usage(char *cmd);
 
-int top_main(int argc, char *argv[]) {
-    int i;
+static void exit_top(int signal) {
+  exit(EXIT_FAILURE);
+}
 
+int top_main(int argc, char *argv[]) {
     num_used_procs = num_free_procs = 0;
 
+    signal(SIGPIPE, exit_top);
+
     max_procs = 0;
     delay = 3;
     iterations = -1;
     proc_cmp = &proc_cpu_cmp;
-    for (i = 1; i < argc; i++) {
+    for (int i = 1; i < argc; i++) {
         if (!strcmp(argv[i], "-m")) {
             if (i + 1 >= argc) {
                 fprintf(stderr, "Option -m expects an argument.\n");
@@ -249,9 +253,9 @@
             continue;
 
         pid = atoi(pid_dir->d_name);
-        
+
         struct proc_info cur_proc;
-        
+
         if (!threads) {
             proc = alloc_proc();
 
@@ -275,7 +279,7 @@
 
             sprintf(filename, "/proc/%d/status", pid);
             read_status(filename, &cur_proc);
-            
+
             proc = NULL;
         }
 
@@ -310,7 +314,7 @@
         }
 
         closedir(task_dir);
-        
+
         if (!threads)
             add_proc(proc_num++, proc);
     }
@@ -339,7 +343,7 @@
     *open_paren = *close_paren = '\0';
     strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN);
     proc->tname[THREAD_NAME_LEN-1] = 0;
-    
+
     /* Scan rest of string. */
     sscanf(close_paren + 1, " %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
                  "%lu %lu %*d %*d %*d %*d %*d %*d %*d %lu %ld "
@@ -452,7 +456,7 @@
             new_cpu.sirqtime - old_cpu.sirqtime,
             total_delta_time);
     printf("\n");
-    if (!threads) 
+    if (!threads)
         printf("%5s %2s %4s %1s %5s %7s %7s %3s %-8s %s\n", "PID", "PR", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "UID", "Name");
     else
         printf("%5s %5s %2s %4s %1s %7s %7s %3s %-8s %-15s %s\n", "PID", "TID", "PR", "CPU%", "S", "VSS", "RSS", "PCY", "UID", "Thread", "Proc");
@@ -476,7 +480,7 @@
             snprintf(group_buf, 20, "%d", proc->gid);
             group_str = group_buf;
         }
-        if (!threads) 
+        if (!threads)
             printf("%5d %2d %3ld%% %c %5d %6ldK %6ldK %3s %-8.8s %s\n", proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
                 proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
         else