Merge "Add const for first argument of sigismember for fit POSIX spec"
diff --git a/libc/Android.mk b/libc/Android.mk
index c98d2ff..ee7fece 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -182,7 +182,6 @@
 	bionic/logd_write.c \
 	bionic/lseek64.c \
 	bionic/md5.c \
-	bionic/memccpy.c \
 	bionic/memchr.c \
 	bionic/memmem.c \
 	bionic/memmove_words.c \
@@ -224,7 +223,6 @@
 	bionic/sigsuspend.c \
 	bionic/sleep.c \
 	bionic/statfs.c \
-	bionic/strcoll.c \
 	bionic/strndup.c \
 	bionic/strnlen.c \
 	bionic/strntoimax.c \
@@ -272,6 +270,7 @@
 
 libc_bionic_src_files := \
     bionic/assert.cpp \
+    bionic/debug_format.cpp \
     bionic/dirent.cpp \
     bionic/eventfd.cpp \
     bionic/__fgets_chk.cpp \
@@ -342,7 +341,9 @@
     upstream-netbsd/libc/stdlib/tdelete.c \
     upstream-netbsd/libc/stdlib/tfind.c \
     upstream-netbsd/libc/stdlib/tsearch.c \
+    upstream-netbsd/libc/string/memccpy.c \
     upstream-netbsd/libc/string/strcasestr.c \
+    upstream-netbsd/libc/string/strcoll.c \
     upstream-netbsd/libc/string/strxfrm.c \
     upstream-netbsd/libc/unistd/killpg.c \
 
@@ -881,7 +882,7 @@
 	$(libc_static_common_src_files) \
 	bionic/dlmalloc.c \
 	bionic/malloc_debug_common.cpp \
-	bionic/pthread_debug.c \
+	bionic/pthread_debug.cpp \
 	bionic/libc_init_dynamic.c
 
 ifeq ($(TARGET_ARCH),arm)
@@ -934,10 +935,10 @@
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
 
 LOCAL_SRC_FILES := \
+	bionic/debug_mapinfo.cpp \
+	bionic/debug_stacktrace.cpp \
 	bionic/malloc_debug_leak.cpp \
 	bionic/malloc_debug_check.cpp \
-	bionic/malloc_debug_check_mapinfo.cpp \
-	bionic/malloc_debug_stacktrace.cpp
 
 LOCAL_MODULE:= libc_malloc_debug_leak
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/libc/arch-arm/bionic/atexit_legacy.c b/libc/arch-arm/bionic/atexit_legacy.c
index 4abe839..6e299ac 100644
--- a/libc/arch-arm/bionic/atexit_legacy.c
+++ b/libc/arch-arm/bionic/atexit_legacy.c
@@ -50,10 +50,9 @@
      * calling library may have been dlclose()'d, causing the program to
      * crash.
      */
-    static char const warning[] =
-        "WARNING: generic atexit() called from legacy shared library\n";
+    static char const warning[] = "WARNING: generic atexit() called from legacy shared library\n";
 
-    __libc_android_log_print(ANDROID_LOG_WARN, "libc", warning);
+    __libc_android_log_write(ANDROID_LOG_WARN, "libc", warning);
     fprintf(stderr, warning);
 
     return (__cxa_atexit((void (*)(void *))func, NULL, NULL));
diff --git a/libc/arch-mips/bionic/cacheflush.c b/libc/arch-mips/bionic/cacheflush.c
index 05085b6..1911687 100644
--- a/libc/arch-mips/bionic/cacheflush.c
+++ b/libc/arch-mips/bionic/cacheflush.c
@@ -29,9 +29,9 @@
 #include <sys/cachectl.h>
 
 #ifdef DEBUG
-#include <logd.h>
-#define  XLOG(...)   \
-	__libc_android_log_print(ANDROID_LOG_DEBUG,"libc-cacheflush",__VA_ARGS__)
+#include <private/logd.h>
+#include <private/debug_format.h>
+#define  XLOG(...) __libc_format_log(ANDROID_LOG_DEBUG,"libc-cacheflush",__VA_ARGS__)
 #endif
 
 /*
diff --git a/libc/bionic/assert.cpp b/libc/bionic/assert.cpp
index 7c0a860..e38c16d 100644
--- a/libc/bionic/assert.cpp
+++ b/libc/bionic/assert.cpp
@@ -32,6 +32,7 @@
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <private/debug_format.h>
 #include <private/logd.h>
 
 // We log to stderr for the benefit of "adb shell" users, and the log for the benefit
@@ -39,7 +40,7 @@
 
 void __assert(const char* file, int line, const char* failed_expression) {
   const char* fmt = "%s:%d: assertion \"%s\" failed\n";
-  __libc_android_log_print(ANDROID_LOG_FATAL, "libc", fmt, file, line, failed_expression);
+  __libc_format_log(ANDROID_LOG_FATAL, "libc", fmt, file, line, failed_expression);
   fprintf(stderr, fmt, file, line, failed_expression);
   abort();
   /* NOTREACHED */
@@ -47,7 +48,7 @@
 
 void __assert2(const char* file, int line, const char* function, const char* failed_expression) {
   const char* fmt = "%s:%d: %s: assertion \"%s\" failed\n";
-  __libc_android_log_print(ANDROID_LOG_FATAL, "libc", fmt, file, line, function, failed_expression);
+  __libc_format_log(ANDROID_LOG_FATAL, "libc", fmt, file, line, function, failed_expression);
   fprintf(stderr, fmt, file, line, function, failed_expression);
   abort();
   /* NOTREACHED */
diff --git a/linker/linker_format.cpp b/libc/bionic/debug_format.cpp
similarity index 83%
rename from linker/linker_format.cpp
rename to libc/bionic/debug_format.cpp
index e631ca1..e8d6a45 100644
--- a/linker/linker_format.cpp
+++ b/libc/bionic/debug_format.cpp
@@ -30,7 +30,7 @@
 // compile under GCC 4.7
 #undef _FORTIFY_SOURCE
 
-#include "linker_format.h"
+#include "debug_format.h"
 
 #include <assert.h>
 #include <errno.h>
@@ -40,8 +40,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "linker_debug.h"
-
 /* define UNIT_TESTS to build this file as a single executable that runs
  * the formatter's unit tests
  */
@@ -150,47 +148,14 @@
     return buf_out_length(&bo);
 }
 
-int
-format_buffer(char *buff, size_t buffsize, const char *format, ...)
-{
-    va_list args;
-    int ret;
-
-    va_start(args, format);
-    ret = vformat_buffer(buff, buffsize, format, args);
-    va_end(args);
-
-    return ret;
+int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  int result = vformat_buffer(buffer, buffer_size, format, args);
+  va_end(args);
+  return result;
 }
 
-/* The __stack_chk_fail() function calls __libc_android_log_print()
- * which calls vsnprintf().
- *
- * We define our version of the function here to avoid dragging
- * about 25 KB of C library routines related to formatting.
- */
-int
-vsnprintf(char *buff, size_t bufsize, const char *format, va_list args)
-{
-    return format_buffer(buff, bufsize, format, args);
-}
-
-/* The pthread implementation uses snprintf(). If we define it here, we
- * avoid pulling the stdio vfprintf() implementation into the linker
- * saving about 19KB of machine code.
- */
-int
-snprintf(char* buff, size_t bufsize, const char* format, ...)
-{
-    va_list args;
-    int ret;
-    va_start(args, format);
-    ret = vsnprintf(buff, bufsize, format, args);
-    va_end(args);
-    return ret;
-}
-
-#if !LINKER_DEBUG_TO_LOG
 
 /*** File descriptor output
  ***/
@@ -204,7 +169,7 @@
 static void
 fd_out_send(void *opaque, const char *data, int len)
 {
-    FdOut *fdo = opaque;
+    FdOut *fdo = reinterpret_cast<FdOut*>(opaque);
 
     if (len < 0)
         len = strlen(data);
@@ -240,96 +205,61 @@
 }
 
 
-int
-format_fd(int fd, const char *format, ...)
-{
-    FdOut fdo;
-    Out* out;
-    va_list args;
+int __libc_format_fd(int fd, const char* format, ...) {
+  FdOut fdo;
+  Out* out = fd_out_init(&fdo, fd);
+  if (out == NULL) {
+    return 0;
+  }
 
-    out = fd_out_init(&fdo, fd);
-    if (out == NULL)
-        return 0;
+  va_list args;
+  va_start(args, format);
+  out_vformat(out, format, args);
+  va_end(args);
 
-    va_start(args, format);
-    out_vformat(out, format, args);
-    va_end(args);
-
-    return fd_out_length(&fdo);
+  return fd_out_length(&fdo);
 }
 
-#else /* LINKER_DEBUG_TO_LOG */
-
 /*** Log output
  ***/
 
-/* We need our own version of __libc_android_log_vprint, otherwise
- * the log output is completely broken. Probably due to the fact
- * that the C library is not initialized yet.
- *
- * You can test that by setting CUSTOM_LOG_VPRINT to 0
- */
-#define  CUSTOM_LOG_VPRINT  1
-
-#if CUSTOM_LOG_VPRINT
-
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/uio.h>
 
-static int log_vprint(int prio, const char *tag, const char *fmt, va_list  args)
-{
-    char buf[1024];
-    int result;
-    static int log_fd = -1;
+int __libc_format_log_va_list(int priority, const char* tag, const char* fmt, va_list args) {
+  char buf[1024];
+  int result = vformat_buffer(buf, sizeof buf, fmt, args);
 
-    result = vformat_buffer(buf, sizeof buf, fmt, args);
-
-    if (log_fd < 0) {
-        log_fd = open("/dev/log/main", O_WRONLY);
-        if (log_fd < 0)
-            return result;
+  static int log_fd = -1;
+  if (log_fd == -1) {
+    log_fd = open("/dev/log/main", O_WRONLY);
+    if (log_fd == -1) {
+      return result;
     }
+  }
 
-    {
-        ssize_t ret;
-        struct iovec vec[3];
+  struct iovec vec[3];
+  vec[0].iov_base = (unsigned char *) &priority;
+  vec[0].iov_len = 1;
+  vec[1].iov_base = (void *) tag;
+  vec[1].iov_len = strlen(tag) + 1;
+  vec[2].iov_base = (void *) buf;
+  vec[2].iov_len = strlen(buf) + 1;
 
-        vec[0].iov_base = (unsigned char *) &prio;
-        vec[0].iov_len = 1;
-        vec[1].iov_base = (void *) tag;
-        vec[1].iov_len = strlen(tag) + 1;
-        vec[2].iov_base = (void *) buf;
-        vec[2].iov_len = strlen(buf) + 1;
+  TEMP_FAILURE_RETRY(writev(log_fd, vec, 3));
 
-        do {
-            ret = writev(log_fd, vec, 3);
-        } while ((ret < 0) && (errno == EINTR));
-    }
-    return result;
+  return result;
 }
 
-#define  __libc_android_log_vprint  log_vprint
-
-#else /* !CUSTOM_LOG_VPRINT */
-
-extern "C" int __libc_android_log_vprint(int  prio, const char* tag, const char*  format, va_list ap);
-
-#endif /* !CUSTOM_LOG_VPRINT */
-
-int
-format_log(int prio, const char *tag, const char *format, ...)
-{
-    int ret;
-    va_list  args;
-    va_start(args, format);
-    ret = __libc_android_log_vprint(prio, tag, format, args);
-    va_end(args);
-    return ret;
+int __libc_format_log(int priority, const char* tag, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  int result = __libc_format_log_va_list(priority, tag, format, args);
+  va_end(args);
+  return result;
 }
 
-#endif /* LINKER_DEBUG_TO_LOG */
-
 /*** formatted output implementation
  ***/
 
diff --git a/libc/bionic/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp
new file mode 100644
index 0000000..174cc28
--- /dev/null
+++ b/libc/bionic/debug_mapinfo.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "dlmalloc.h"
+#include "debug_mapinfo.h"
+
+// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so
+// 012345678901234567890123456789012345678901234567890123456789
+// 0         1         2         3         4         5
+
+static mapinfo_t* parse_maps_line(char* line) {
+  int len = strlen(line);
+
+  if (len < 1) return 0;
+  line[--len] = 0;
+
+  if (len < 50) return 0;
+  if (line[20] != 'x') return 0;
+
+  mapinfo_t* mi = static_cast<mapinfo_t*>(dlmalloc(sizeof(mapinfo_t) + (len - 47)));
+  if (mi == 0) return 0;
+
+  mi->start = strtoul(line, 0, 16);
+  mi->end = strtoul(line + 9, 0, 16);
+  mi->next = 0;
+  strcpy(mi->name, line + 49);
+
+  return mi;
+}
+
+__LIBC_HIDDEN__ mapinfo_t* mapinfo_create(int pid) {
+  struct mapinfo_t* milist = NULL;
+  char data[1024]; // Used to read lines as well as to construct the filename.
+  snprintf(data, sizeof(data), "/proc/%d/maps", pid);
+  FILE* fp = fopen(data, "r");
+  if (fp != NULL) {
+    while (fgets(data, sizeof(data), fp) != NULL) {
+      mapinfo_t* mi = parse_maps_line(data);
+      if (mi) {
+        mi->next = milist;
+        milist = mi;
+      }
+    }
+    fclose(fp);
+  }
+  return milist;
+}
+
+__LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi) {
+  while (mi) {
+    mapinfo_t* del = mi;
+    mi = mi->next;
+    dlfree(del);
+  }
+}
+
+// Find the containing map info for the PC.
+__LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, unsigned pc, unsigned* rel_pc) {
+  *rel_pc = pc;
+  for (; mi != NULL; mi = mi->next) {
+    if ((pc >= mi->start) && (pc < mi->end)) {
+      *rel_pc -= mi->start;
+      return mi;
+    }
+  }
+  return NULL;
+}
diff --git a/libc/bionic/malloc_debug_check_mapinfo.h b/libc/bionic/debug_mapinfo.h
similarity index 77%
rename from libc/bionic/malloc_debug_check_mapinfo.h
rename to libc/bionic/debug_mapinfo.h
index e19f71e..6df55c5 100644
--- a/libc/bionic/malloc_debug_check_mapinfo.h
+++ b/libc/bionic/debug_mapinfo.h
@@ -26,21 +26,20 @@
  * SUCH DAMAGE.
  */
 
-#ifndef MALLOC_DEBUG_CHECK_MAPINFO_H
-#define MALLOC_DEBUG_CHECK_MAPINFO_H
+#ifndef DEBUG_MAPINFO_H
+#define DEBUG_MAPINFO_H
 
 #include <sys/cdefs.h>
 
-struct mapinfo {
-  struct mapinfo* next;
+struct mapinfo_t {
+  struct mapinfo_t* next;
   unsigned start;
   unsigned end;
   char name[];
 };
 
-__LIBC_HIDDEN__ mapinfo *init_mapinfo(int pid);
-__LIBC_HIDDEN__ void deinit_mapinfo(mapinfo *mi);
-__LIBC_HIDDEN__ const char *map_to_name(mapinfo *mi, unsigned pc, const char* def);
-__LIBC_HIDDEN__ const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc);
+__LIBC_HIDDEN__ mapinfo_t* mapinfo_create(int pid);
+__LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi);
+__LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, unsigned pc, unsigned* rel_pc);
 
-#endif /*MALLOC_DEBUG_CHECK_MAPINFO_H*/
+#endif /* DEBUG_MAPINFO_H */
diff --git a/libc/bionic/debug_stacktrace.cpp b/libc/bionic/debug_stacktrace.cpp
new file mode 100644
index 0000000..4b080a4
--- /dev/null
+++ b/libc/bionic/debug_stacktrace.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "debug_stacktrace.h"
+
+#include <dlfcn.h>
+#include <unistd.h>
+#include <unwind.h>
+#include <sys/types.h>
+
+#include "debug_format.h"
+#include "debug_mapinfo.h"
+#include "logd.h"
+
+/* depends how the system includes define this */
+#ifdef HAVE_UNWIND_CONTEXT_STRUCT
+typedef struct _Unwind_Context __unwind_context;
+#else
+typedef _Unwind_Context __unwind_context;
+#endif
+
+static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg) {
+  stack_crawl_state_t* state = static_cast<stack_crawl_state_t*>(arg);
+  if (state->count) {
+    intptr_t ip = (intptr_t)_Unwind_GetIP(context);
+    if (ip) {
+      state->addrs[0] = ip;
+      state->addrs++;
+      state->count--;
+      return _URC_NO_REASON;
+    }
+  }
+  // If we run out of space to record the address or 0 has been seen, stop
+  // unwinding the stack.
+  return _URC_END_OF_STACK;
+}
+
+__LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries) {
+  stack_crawl_state_t state;
+  state.count = max_entries;
+  state.addrs = addrs;
+  _Unwind_Backtrace(trace_function, &state);
+  return max_entries - state.count;
+}
+
+__LIBC_HIDDEN__ void log_backtrace(mapinfo_t* map_info, intptr_t* addrs, size_t c) {
+  intptr_t self_bt[16];
+  if (addrs == NULL) {
+    c = get_backtrace(self_bt, 16);
+    addrs = self_bt;
+  }
+
+  __libc_format_log(ANDROID_LOG_ERROR, "libc",
+                    "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
+
+  int index = 0;
+  for (size_t i = 0 ; i < c; ++i) {
+    void* offset = 0;
+    const char* symbol = NULL;
+
+    Dl_info info;
+    if (dladdr((void*) addrs[i], &info) != 0) {
+      offset = info.dli_saddr;
+      symbol = info.dli_sname;
+    }
+
+    // This test is a bit sketchy, but it allows us to skip the
+    // stack trace entries due to this debugging code. it works
+    // because those don't have a symbol (they're not exported).
+    if (symbol != NULL || index > 0) {
+      unsigned int rel_pc;
+      const mapinfo_t* mi = mapinfo_find(map_info, addrs[i], &rel_pc);
+      const char* soname = mi ? mi->name : info.dli_fname;
+      if (soname == NULL) {
+        soname = "unknown";
+      }
+      if (symbol) {
+        __libc_format_log(ANDROID_LOG_ERROR, "libc", "          #%02d  pc %08x  %s (%s+0x%x)",
+                          index, rel_pc, soname, symbol, addrs[i] - (intptr_t)offset);
+      } else {
+        __libc_format_log(ANDROID_LOG_ERROR, "libc", "          #%02d  pc %08x  %s",
+                          index, rel_pc, soname);
+      }
+      ++index;
+    }
+  }
+}
diff --git a/libc/bionic/strcoll.c b/libc/bionic/debug_stacktrace.h
old mode 100755
new mode 100644
similarity index 74%
rename from libc/bionic/strcoll.c
rename to libc/bionic/debug_stacktrace.h
index e3b1ec3..3c66ea6
--- a/libc/bionic/strcoll.c
+++ b/libc/bionic/debug_stacktrace.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,16 +25,21 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <string.h>
 
-/*
- * Compare strings using the current locale.  Since Bionic really does not
- * support locales, we assume we always use the C locale and call strcmp.
- *
- * This function is provided to make libstdc++-v3 usable.
- */
-int
-strcoll(const char *s1, const char *s2)
-{
-	return strcmp(s1, s2);
-}
+#ifndef DEBUG_STACKTRACE_H
+#define DEBUG_STACKTRACE_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+struct stack_crawl_state_t {
+  size_t count;
+  intptr_t* addrs;
+};
+
+struct mapinfo_t;
+
+__LIBC_HIDDEN__ int get_backtrace(intptr_t* stack_frames, size_t max_entries);
+__LIBC_HIDDEN__ void log_backtrace(mapinfo_t* map_info, intptr_t* stack_frames, size_t frame_count);
+
+#endif /* DEBUG_STACKTRACE_H */
diff --git a/libc/bionic/dlmalloc.c b/libc/bionic/dlmalloc.c
index 6287549..1ed3205 100644
--- a/libc/bionic/dlmalloc.c
+++ b/libc/bionic/dlmalloc.c
@@ -16,102 +16,68 @@
 
 #include "dlmalloc.h"
 
-/* Bionic error handling declarations */
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/ashmem.h>
+
+#include <private/debug_format.h>
+#include <private/logd.h>
+
+// Send dlmalloc errors to the log.
+static void __bionic_heap_corruption_error(const char* function);
+static void __bionic_heap_usage_error(const char* function, void* address);
 #define PROCEED_ON_ERROR 0
-static void __bionic_heap_error(const char* msg, const char* function, void* p);
-#define CORRUPTION_ERROR_ACTION(m) \
-    __bionic_heap_error("HEAP MEMORY CORRUPTION", __FUNCTION__, NULL)
-#define USAGE_ERROR_ACTION(m,p) \
-    __bionic_heap_error("ARGUMENT IS INVALID HEAP ADDRESS", __FUNCTION__, p)
+#define CORRUPTION_ERROR_ACTION(m) __bionic_heap_corruption_error(__FUNCTION__)
+#define USAGE_ERROR_ACTION(m,p) __bionic_heap_usage_error(__FUNCTION__, p)
 
-/* Bionic named anonymous memory declarations */
-static void* named_anonymous_mmap(size_t length);
-#define MMAP(s) named_anonymous_mmap(s)
+// We use ashmem to name the anonymous private regions created by dlmalloc.
+static void* __bionic_named_anonymous_mmap(size_t length);
+#define MMAP(s) __bionic_named_anonymous_mmap(s)
 
-/*
- * Ugly inclusion of C file so that bionic specific #defines configure
- * dlmalloc.
- */
+// Ugly inclusion of C file so that bionic specific #defines configure dlmalloc.
 #include "../upstream-dlmalloc/malloc.c"
 
-
-/* Bionic error handling definitions */
-/* Convert a pointer into hex string */
-static void __bionic_itox(char* hex, void* ptr)
-{
-    intptr_t val = (intptr_t) ptr;
-    /* Terminate with NULL */
-    hex[8] = 0;
-    int i;
-
-    for (i = 7; i >= 0; i--) {
-        int digit = val & 15;
-        hex[i] = (digit <= 9) ? digit + '0' : digit - 10 + 'a';
-        val >>= 4;
-    }
+static void __bionic_heap_corruption_error(const char* function) {
+  __libc_format_log(ANDROID_LOG_FATAL, "libc", "@@@ ABORTING: heap corruption detected by %s",
+                    function);
+  abort();
 }
 
-#include <private/logd.h>
-static void __bionic_heap_error(const char* msg, const char* function, void* p)
-{
-    /* We format the buffer explicitely, i.e. without using snprintf()
-     * which may use malloc() internally. Not something we can trust
-     * if we just detected a corrupted heap.
-     */
-    char buffer[256];
-    strlcpy(buffer, "@@@ ABORTING: LIBC: ", sizeof(buffer));
-    strlcat(buffer, msg, sizeof(buffer));
-    if (function != NULL) {
-        strlcat(buffer, " IN ", sizeof(buffer));
-        strlcat(buffer, function, sizeof(buffer));
-    }
-
-    if (p != NULL) {
-        char hexbuffer[9];
-        __bionic_itox(hexbuffer, p);
-        strlcat(buffer, " addr=0x", sizeof(buffer));
-        strlcat(buffer, hexbuffer, sizeof(buffer));
-    }
-
-    __libc_android_log_write(ANDROID_LOG_FATAL, "libc", buffer);
-
-    /* So that we can get a memory dump around p */
-    *((int **) 0xdeadbaad) = (int *) p;
+static void __bionic_heap_usage_error(const char* function, void* address) {
+  __libc_format_log(ANDROID_LOG_FATAL, "libc", "@@@ ABORTING: invalid address %p passed to %s",
+                    address, function);
+  // So that we can get a memory dump around the specific address.
+  *((int**) 0xdeadbaad) = (int*) address;
 }
 
-/* Bionic named anonymous memory definitions */
-#include <linux/ashmem.h>
-static int __ashmem_create_region(const char* name, size_t size)
-{
-    int fd, ret;
-    fd = open("/dev/ashmem", O_RDWR);
-    if (fd < 0)
-        return fd;
-    if (name != NULL) {
-        char buf[ASHMEM_NAME_LEN];
-
-        strlcpy(buf, name, sizeof(buf));
-        ret = ioctl(fd, ASHMEM_SET_NAME, buf);
-        if (ret < 0) {  /* error */
-            close(fd);
-            return ret;
-        }
-    }
-    ret = ioctl(fd, ASHMEM_SET_SIZE, size);
-    if (ret < 0) {  /* error */
-        close(fd);
-        return ret;
-    }
+static int __ashmem_create_region(const char* name, size_t size) {
+  int fd = open("/dev/ashmem", O_RDWR);
+  if (fd == -1) {
     return fd;
+  }
+  int rc = ioctl(fd, ASHMEM_SET_NAME, name);
+  if (rc < 0) {
+    close(fd);
+    return rc;
+  }
+  rc = ioctl(fd, ASHMEM_SET_SIZE, size);
+  if (rc < 0) {
+    close(fd);
+    return rc;
+  }
+  return fd;
 }
 
-static void* named_anonymous_mmap(size_t length)
-{
-    void* ret;
-    int fd = __ashmem_create_region("libc malloc", length);
-    if (fd < 0)
-        return MAP_FAILED;
-    ret = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-    close (fd);
-    return ret;
+static void* __bionic_named_anonymous_mmap(size_t length) {
+  int fd = __ashmem_create_region("libc malloc", length);
+  if (fd < 0) {
+    return MAP_FAILED;
+  }
+  void* result = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+  close (fd);
+  return result;
 }
diff --git a/libc/bionic/logd_write.c b/libc/bionic/logd_write.c
index 71a6f8e..11c0e68 100644
--- a/libc/bionic/logd_write.c
+++ b/libc/bionic/logd_write.c
@@ -250,9 +250,7 @@
 
 __LIBC_HIDDEN__
 void __fortify_chk_fail(const char *msg, uint32_t tag) {
-    __libc_android_log_print(ANDROID_LOG_FATAL, "libc",
-                             "FORTIFY_SOURCE: %s. Calling abort().\n",
-                             msg);
+    __libc_format_log(ANDROID_LOG_FATAL, "libc", "FORTIFY_SOURCE: %s. Calling abort().\n", msg);
     if (tag != 0) {
         __libc_android_log_event_uid(tag);
     }
diff --git a/libc/bionic/malloc_debug_check.cpp b/libc/bionic/malloc_debug_check.cpp
index 5ad3486..60ee0cc 100644
--- a/libc/bionic/malloc_debug_check.cpp
+++ b/libc/bionic/malloc_debug_check.cpp
@@ -45,18 +45,19 @@
 #include <unistd.h>
 #include <unwind.h>
 
+#include "debug_mapinfo.h"
+#include "debug_stacktrace.h"
 #include "dlmalloc.h"
 #include "logd.h"
-#include "malloc_debug_check_mapinfo.h"
 #include "malloc_debug_common.h"
 #include "ScopedPthreadMutexLocker.h"
 
-static mapinfo *milist;
+static mapinfo_t* gMapInfo;
 
 /* libc.debug.malloc.backlog */
 extern unsigned int malloc_double_free_backlog;
 
-#define MAX_BACKTRACE_DEPTH 15
+#define MAX_BACKTRACE_DEPTH 16
 #define ALLOCATION_TAG      0x1ee7d00d
 #define BACKLOG_TAG         0xbabecafe
 #define FREE_POISON         0xa5
@@ -67,20 +68,10 @@
 #define REAR_GUARD_LEN      (1<<5)
 
 static void log_message(const char* format, ...) {
-    extern const MallocDebug __libc_malloc_default_dispatch;
-    extern const MallocDebug* __libc_malloc_dispatch;
-    extern pthread_mutex_t gAllocationsMutex;
-
-    va_list args;
-    {
-        ScopedPthreadMutexLocker locker(&gAllocationsMutex);
-        const MallocDebug* current_dispatch = __libc_malloc_dispatch;
-        __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
-        va_start(args, format);
-        __libc_android_log_vprint(ANDROID_LOG_ERROR, "libc", format, args);
-        va_end(args);
-        __libc_malloc_dispatch = current_dispatch;
-    }
+  va_list args;
+  va_start(args, format);
+  __libc_format_log_va_list(ANDROID_LOG_ERROR, "libc", format, args);
+  va_end(args);
 }
 
 struct hdr_t {
@@ -121,28 +112,6 @@
 static hdr_t *backlog_head;
 static pthread_mutex_t backlog_lock = PTHREAD_MUTEX_INITIALIZER;
 
-extern __LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries);
-
-static void print_backtrace(const intptr_t *bt, unsigned int depth) {
-    const mapinfo *mi;
-    unsigned int cnt;
-    unsigned int rel_pc;
-    intptr_t self_bt[MAX_BACKTRACE_DEPTH];
-
-    if (!bt) {
-        depth = get_backtrace(self_bt, MAX_BACKTRACE_DEPTH);
-        bt = self_bt;
-    }
-
-    log_message("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
-    for (cnt = 0; cnt < depth && cnt < MAX_BACKTRACE_DEPTH; cnt++) {
-        mi = pc_to_mapinfo(milist, bt[cnt], &rel_pc);
-        log_message("\t#%02d  pc %08x  %s\n", cnt,
-                   mi ? (intptr_t)rel_pc : bt[cnt],
-                   mi ? mi->name : "(unknown)");
-    }
-}
-
 static inline void init_front_guard(hdr_t *hdr) {
     memset(hdr->front_guard, FRONT_GUARD, FRONT_GUARD_LEN);
 }
@@ -292,11 +261,11 @@
     if (!valid && *safe) {
         log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
                         user(hdr), hdr->size);
-        print_backtrace(hdr->bt, hdr->bt_depth);
+        log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth);
         if (hdr->tag == BACKLOG_TAG) {
             log_message("+++ ALLOCATION %p SIZE %d FREED HERE:\n",
                        user(hdr), hdr->size);
-            print_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
+            log_backtrace(gMapInfo, hdr->freed_bt, hdr->freed_bt_depth);
         }
     }
 
@@ -381,18 +350,18 @@
                        user(hdr), hdr->size);
             log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
                        user(hdr), hdr->size);
-            print_backtrace(hdr->bt, hdr->bt_depth);
+            log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth);
             /* hdr->freed_bt_depth should be nonzero here */
             log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n",
                        user(hdr), hdr->size);
-            print_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
+            log_backtrace(gMapInfo, hdr->freed_bt, hdr->freed_bt_depth);
             log_message("+++ ALLOCATION %p SIZE %d NOW BEING FREED HERE:\n",
                        user(hdr), hdr->size);
-            print_backtrace(bt, depth);
+            log_backtrace(gMapInfo, bt, depth);
         } else {
             log_message("+++ ALLOCATION %p IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
                        user(hdr));
-            print_backtrace(bt, depth);
+            log_backtrace(gMapInfo, bt, depth);
             /* Leak here so that we do not crash */
             //dlfree(user(hdr));
         }
@@ -428,14 +397,14 @@
                        user(hdr), size, hdr->size);
             log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
                        user(hdr), hdr->size);
-            print_backtrace(hdr->bt, hdr->bt_depth);
+            log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth);
             /* hdr->freed_bt_depth should be nonzero here */
             log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n",
                        user(hdr), hdr->size);
-            print_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
+            log_backtrace(gMapInfo, hdr->freed_bt, hdr->freed_bt_depth);
             log_message("+++ ALLOCATION %p SIZE %d NOW BEING REALLOCATED HERE:\n",
                        user(hdr), hdr->size);
-            print_backtrace(bt, depth);
+            log_backtrace(gMapInfo, bt, depth);
 
              /* We take the memory out of the backlog and fall through so the
              * reallocation below succeeds.  Since we didn't really free it, we
@@ -445,7 +414,7 @@
         } else {
             log_message("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
                        user(hdr), size);
-            print_backtrace(bt, depth);
+            log_backtrace(gMapInfo, bt, depth);
             // just get a whole new allocation and leak the old one
             return dlrealloc(0, size);
             // return dlrealloc(user(hdr), size); // assuming it was allocated externally
@@ -467,8 +436,7 @@
     size_t total_size = nmemb * size;
     hdr_t* hdr = static_cast<hdr_t*>(dlcalloc(1, sizeof(hdr_t) + total_size + sizeof(ftr_t)));
     if (hdr) {
-        hdr->bt_depth = get_backtrace(
-                            hdr->bt, MAX_BACKTRACE_DEPTH);
+        hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
         add(hdr, total_size);
         return user(hdr);
     }
@@ -476,21 +444,20 @@
 }
 
 static void heaptracker_free_leaked_memory() {
+    size_t total = num;
     if (num) {
-        log_message("+++ THERE ARE %d LEAKED ALLOCATIONS\n", num);
+        log_message("+++ Leaked allocations: %d\n", num);
     }
 
     hdr_t *del = NULL;
     while (head) {
         int safe;
         del = head;
-        log_message("+++ DELETING %d BYTES OF LEAKED MEMORY AT %p (%d REMAINING)\n",
-                del->size, user(del), num);
+        log_message("+++ Leaked block of size %d at %p (leak %d of %d)\n",
+                del->size, user(del), 1 + total - num, total);
         if (del_leak(del, &safe)) {
             /* safe == 1, because the allocation is valid */
-            log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
-                        user(del), del->size);
-            print_backtrace(del->bt, del->bt_depth);
+            log_backtrace(gMapInfo, del->bt, del->bt_depth);
         }
         dlfree(del);
     }
@@ -507,13 +474,14 @@
  * See comments on MallocDebugInit in malloc_debug_common.h
  */
 extern "C" int malloc_debug_initialize() {
-    if (!malloc_double_free_backlog)
-        malloc_double_free_backlog = BACKLOG_DEFAULT_LEN;
-    milist = init_mapinfo(getpid());
-    return 0;
+  if (!malloc_double_free_backlog) {
+    malloc_double_free_backlog = BACKLOG_DEFAULT_LEN;
+  }
+  gMapInfo = mapinfo_create(getpid());
+  return 0;
 }
 
 extern "C" void malloc_debug_finalize() {
-    heaptracker_free_leaked_memory();
-    deinit_mapinfo(milist);
+  heaptracker_free_leaked_memory();
+  mapinfo_destroy(gMapInfo);
 }
diff --git a/libc/bionic/malloc_debug_check_mapinfo.cpp b/libc/bionic/malloc_debug_check_mapinfo.cpp
deleted file mode 100644
index 8cc2c99..0000000
--- a/libc/bionic/malloc_debug_check_mapinfo.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "dlmalloc.h"
-#include "malloc_debug_check_mapinfo.h"
-
-// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so
-// 012345678901234567890123456789012345678901234567890123456789
-// 0         1         2         3         4         5
-
-static mapinfo* parse_maps_line(char* line) {
-    int len = strlen(line);
-
-    if (len < 1) return 0;
-    line[--len] = 0;
-
-    if (len < 50) return 0;
-    if (line[20] != 'x') return 0;
-
-    mapinfo* mi = static_cast<mapinfo*>(dlmalloc(sizeof(mapinfo) + (len - 47)));
-    if (mi == 0) return 0;
-
-    mi->start = strtoul(line, 0, 16);
-    mi->end = strtoul(line + 9, 0, 16);
-    /* To be filled in parse_elf_info if the mapped section starts with
-     * elf_header
-     */
-    mi->next = 0;
-    strcpy(mi->name, line + 49);
-
-    return mi;
-}
-
-__LIBC_HIDDEN__
-mapinfo *init_mapinfo(int pid) {
-    struct mapinfo *milist = NULL;
-    char data[1024]; // Used to read lines as well as to construct the filename.
-    snprintf(data, sizeof(data), "/proc/%d/maps", pid);
-    FILE *fp = fopen(data, "r");
-    if (fp) {
-        while (fgets(data, sizeof(data), fp)) {
-            mapinfo *mi = parse_maps_line(data);
-            if (mi) {
-                mi->next = milist;
-                milist = mi;
-            }
-        }
-        fclose(fp);
-    }
-
-    return milist;
-}
-
-__LIBC_HIDDEN__
-void deinit_mapinfo(mapinfo *mi) {
-    mapinfo *del;
-    while (mi) {
-        del = mi;
-        mi = mi->next;
-        dlfree(del);
-    }
-}
-
-/* Map a pc address to the name of the containing ELF file */
-__LIBC_HIDDEN__
-const char *map_to_name(mapinfo *mi, unsigned pc, const char* def) {
-    while (mi) {
-        if ((pc >= mi->start) && (pc < mi->end)) {
-            return mi->name;
-        }
-        mi = mi->next;
-    }
-    return def;
-}
-
-/* Find the containing map info for the pc */
-__LIBC_HIDDEN__
-const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc) {
-    *rel_pc = pc;
-    while (mi) {
-        if ((pc >= mi->start) && (pc < mi->end)) {
-            // Only calculate the relative offset for shared libraries
-            if (strstr(mi->name, ".so")) {
-                *rel_pc -= mi->start;
-            }
-            return mi;
-        }
-        mi = mi->next;
-    }
-    return NULL;
-}
diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp
index 624a40e..bba0472 100644
--- a/libc/bionic/malloc_debug_common.cpp
+++ b/libc/bionic/malloc_debug_common.cpp
@@ -294,8 +294,8 @@
 unsigned int malloc_double_free_backlog;
 
 static void InitMalloc(MallocDebug* table, int debug_level, const char* prefix) {
-  __libc_android_log_print(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n",
-                           __progname, debug_level, prefix);
+  __libc_format_log(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n",
+                    __progname, debug_level, prefix);
 
   char symbol[128];
 
@@ -429,7 +429,7 @@
         dlclose(libc_malloc_impl_handle);
         return;
     }
-    if (malloc_debug_initialize()) {
+    if (malloc_debug_initialize() == -1) {
         dlclose(libc_malloc_impl_handle);
         return;
     }
@@ -487,11 +487,19 @@
 }
 
 static void malloc_fini_impl() {
-    if (libc_malloc_impl_handle) {
+    // Our BSD stdio implementation doesn't close the standard streams, it only flushes them.
+    // And it doesn't do that until its atexit handler (_cleanup) is run, and we run first!
+    // It's great that other unclosed FILE*s show up as malloc leaks, but we need to manually
+    // clean up the standard streams ourselves.
+    fclose(stdin);
+    fclose(stdout);
+    fclose(stderr);
+
+    if (libc_malloc_impl_handle != NULL) {
         MallocDebugFini malloc_debug_finalize =
             reinterpret_cast<MallocDebugFini>(dlsym(libc_malloc_impl_handle,
                                                     "malloc_debug_finalize"));
-        if (malloc_debug_finalize) {
+        if (malloc_debug_finalize != NULL) {
             malloc_debug_finalize();
         }
     }
diff --git a/libc/bionic/malloc_debug_common.h b/libc/bionic/malloc_debug_common.h
index 78ad5e5..3d12f87 100644
--- a/libc/bionic/malloc_debug_common.h
+++ b/libc/bionic/malloc_debug_common.h
@@ -35,6 +35,8 @@
 
 #include <stdlib.h>
 
+#include <private/debug_format.h>
+
 #define HASHTABLE_SIZE      1543
 #define BACKTRACE_SIZE      32
 /* flag definitions, currently sharing storage with "size" */
@@ -97,10 +99,10 @@
 // =============================================================================
 
 #define debug_log(format, ...)  \
-    __libc_android_log_print(ANDROID_LOG_DEBUG, "malloc_leak_check", (format), ##__VA_ARGS__ )
+    __libc_format_log(ANDROID_LOG_DEBUG, "malloc_leak_check", (format), ##__VA_ARGS__ )
 #define error_log(format, ...)  \
-    __libc_android_log_print(ANDROID_LOG_ERROR, "malloc_leak_check", (format), ##__VA_ARGS__ )
+    __libc_format_log(ANDROID_LOG_ERROR, "malloc_leak_check", (format), ##__VA_ARGS__ )
 #define info_log(format, ...)  \
-    __libc_android_log_print(ANDROID_LOG_INFO, "malloc_leak_check", (format), ##__VA_ARGS__ )
+    __libc_format_log(ANDROID_LOG_INFO, "malloc_leak_check", (format), ##__VA_ARGS__ )
 
 #endif  // MALLOC_DEBUG_COMMON_H
diff --git a/libc/bionic/malloc_debug_leak.cpp b/libc/bionic/malloc_debug_leak.cpp
index 090a981..68b6ae2 100644
--- a/libc/bionic/malloc_debug_leak.cpp
+++ b/libc/bionic/malloc_debug_leak.cpp
@@ -45,6 +45,7 @@
 #include <unistd.h>
 #include <unwind.h>
 
+#include "debug_stacktrace.h"
 #include "dlmalloc.h"
 #include "logd.h"
 #include "malloc_debug_common.h"
@@ -255,8 +256,6 @@
 
 static void* MEMALIGN_GUARD = reinterpret_cast<void*>(0xA1A41520);
 
-extern __LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries);
-
 extern "C" void* leak_malloc(size_t bytes) {
     // allocate enough space infront of the allocation to store the pointer for
     // the alloc structure. This will making free'ing the structer really fast!
diff --git a/libc/bionic/malloc_debug_qemu.cpp b/libc/bionic/malloc_debug_qemu.cpp
index e586b1b..812a451 100644
--- a/libc/bionic/malloc_debug_qemu.cpp
+++ b/libc/bionic/malloc_debug_qemu.cpp
@@ -257,8 +257,8 @@
                              INFO_TRACING_ENABLED)
 
 /* Prints a string to the emulator's stdout.
- * In early stages of system loading, logging mesages via
- * __libc_android_log_print API is not available, because ADB API has not been
+ * In early stages of system loading, logging messages to logcat
+ * is not available, because ADB API has not been
  * hooked up yet. So, in order to see such messages we need to print them to
  * the emulator's stdout.
  * Parameters passed to this macro are the same as parameters for printf
@@ -289,8 +289,7 @@
  */
 #define qemu_debug_log(format, ...)                                         \
     do {                                                                    \
-        __libc_android_log_print(ANDROID_LOG_DEBUG, "memcheck",             \
-                                 (format), ##__VA_ARGS__);                  \
+        __libc_format_log(ANDROID_LOG_DEBUG, "memcheck", (format), ##__VA_ARGS__); \
         if (tracing_flags & DEBUG_TRACING_ENABLED) {                        \
             qemu_log(ANDROID_LOG_DEBUG, (format), ##__VA_ARGS__);           \
         }                                                                   \
@@ -298,8 +297,7 @@
 
 #define qemu_error_log(format, ...)                                         \
     do {                                                                    \
-        __libc_android_log_print(ANDROID_LOG_ERROR, "memcheck",             \
-                                 (format), ##__VA_ARGS__);                  \
+        __libc_format_log(ANDROID_LOG_ERROR, "memcheck", (format), ##__VA_ARGS__); \
         if (tracing_flags & ERROR_TRACING_ENABLED) {                        \
             qemu_log(ANDROID_LOG_ERROR, (format), ##__VA_ARGS__);           \
         }                                                                   \
@@ -307,8 +305,7 @@
 
 #define qemu_info_log(format, ...)                                          \
     do {                                                                    \
-        __libc_android_log_print(ANDROID_LOG_INFO, "memcheck",              \
-                                 (format), ##__VA_ARGS__);                  \
+        __libc_format_log(ANDROID_LOG_INFO, "memcheck", (format), ##__VA_ARGS__); \
         if (tracing_flags & INFO_TRACING_ENABLED) {                         \
             qemu_log(ANDROID_LOG_INFO, (format), ##__VA_ARGS__);            \
         }                                                                   \
@@ -318,20 +315,19 @@
  * Param:
  *  type - Message type: debug, error, or info
  *  desc - MallocDesc instance to dump.
- *  frmt + rest - Formats message preceding dumped descriptor.
+ *  fmt + rest - Formats message preceding dumped descriptor.
 */
-#define log_mdesc(type, desc, frmt, ...)                                    \
+#define log_mdesc(type, desc, fmt, ...)                                    \
     do {                                                                    \
         if (tracing_enabled(type)) {                                        \
             char log_str[4096];                                             \
-            size_t str_len;                                                 \
-            snprintf(log_str, sizeof(log_str), frmt, ##__VA_ARGS__);        \
+            __libc_format_buffer(log_str, sizeof(log_str), fmt, ##__VA_ARGS__); \
             log_str[sizeof(log_str) - 1] = '\0';                            \
-            str_len = strlen(log_str);                                      \
+            size_t str_len = strlen(log_str);                               \
             dump_malloc_descriptor(log_str + str_len,                       \
                                    sizeof(log_str) - str_len,               \
                                    (desc));                                 \
-            type##_log(log_str);                                            \
+            type##_log("%s", log_str);                                      \
         }                                                                   \
     } while (0)
 
diff --git a/libc/bionic/malloc_debug_stacktrace.cpp b/libc/bionic/malloc_debug_stacktrace.cpp
deleted file mode 100644
index 32b8ac0..0000000
--- a/libc/bionic/malloc_debug_stacktrace.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <unwind.h>
-#include <sys/types.h>
-
-// =============================================================================
-// stack trace functions
-// =============================================================================
-
-struct stack_crawl_state_t {
-    size_t count;
-    intptr_t* addrs;
-};
-
-
-/* depends how the system includes define this */
-#ifdef HAVE_UNWIND_CONTEXT_STRUCT
-typedef struct _Unwind_Context __unwind_context;
-#else
-typedef _Unwind_Context __unwind_context;
-#endif
-
-static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg) {
-    stack_crawl_state_t* state = static_cast<stack_crawl_state_t*>(arg);
-    if (state->count) {
-        intptr_t ip = (intptr_t)_Unwind_GetIP(context);
-        if (ip) {
-            state->addrs[0] = ip;
-            state->addrs++;
-            state->count--;
-            return _URC_NO_REASON;
-        }
-    }
-    /*
-     * If we run out of space to record the address or 0 has been seen, stop
-     * unwinding the stack.
-     */
-    return _URC_END_OF_STACK;
-}
-
-__LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries) {
-    stack_crawl_state_t state;
-    state.count = max_entries;
-    state.addrs = addrs;
-    _Unwind_Backtrace(trace_function, &state);
-    return max_entries - state.count;
-}
diff --git a/libc/bionic/memccpy.c b/libc/bionic/memccpy.c
deleted file mode 100644
index 789fde6..0000000
--- a/libc/bionic/memccpy.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <stddef.h>
-#include <string.h>
-
-void *memccpy(void *dst, const void *src, int c, size_t n)
-{
-    char*        q     = dst;
-    const char*  p     = src;
-    const char*  p_end = p + n;
-    char         ch    = ~(char)c;  /* ensure ch != c */
-
-    for (;;) {
-        if (ch == c || p >= p_end) break;
-        *q++ = ch = *p++;
-    }
-
-    if (p >= p_end && ch != c)
-        return NULL;
-
-    return q;
-}
diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c
index f294723..f2a7ebe 100644
--- a/libc/bionic/pthread.c
+++ b/libc/bionic/pthread.c
@@ -50,6 +50,7 @@
 #include "bionic_pthread.h"
 #include "bionic_ssp.h"
 #include "bionic_tls.h"
+#include "debug_format.h"
 #include "pthread_internal.h"
 #include "thread_private.h"
 
@@ -229,7 +230,7 @@
             // For backwards compatibility reasons, we just warn about failures here.
             // error = errno;
             const char* msg = "pthread_create sched_setscheduler call failed: %s\n";
-            __libc_android_log_print(ANDROID_LOG_WARN, "libc", msg, strerror(errno));
+            __libc_format_log(ANDROID_LOG_WARN, "libc", msg, strerror(errno));
         }
     }
 
diff --git a/libc/bionic/pthread_debug.c b/libc/bionic/pthread_debug.cpp
similarity index 75%
rename from libc/bionic/pthread_debug.c
rename to libc/bionic/pthread_debug.cpp
index 7ee208c..7d98d10 100644
--- a/libc/bionic/pthread_debug.c
+++ b/libc/bionic/pthread_debug.cpp
@@ -31,9 +31,7 @@
 #include <sys/system_properties.h>
 #include <sys/mman.h>
 
-#if HAVE_DLADDR
-#include <dlfcn.h>
-#endif
+//#include <dlfcn.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -42,8 +40,12 @@
 #include <unwind.h>
 #include <unistd.h>
 
-#include "logd.h"
 #include "bionic_tls.h"
+#include "debug_mapinfo.h"
+#include "debug_stacktrace.h"
+#include "logd.h"
+
+#include <private/debug_format.h>
 
 /*
  * ===========================================================================
@@ -97,20 +99,16 @@
 // =============================================================================
 
 #define LOGD(format, ...)  \
-    __libc_android_log_print(ANDROID_LOG_DEBUG, \
-            "pthread_debug", (format), ##__VA_ARGS__ )
+    __libc_format_log(ANDROID_LOG_DEBUG, "pthread_debug", (format), ##__VA_ARGS__ )
 
 #define LOGW(format, ...)  \
-    __libc_android_log_print(ANDROID_LOG_WARN, \
-            "pthread_debug", (format), ##__VA_ARGS__ )
+    __libc_format_log(ANDROID_LOG_WARN, "pthread_debug", (format), ##__VA_ARGS__ )
 
 #define LOGE(format, ...)  \
-    __libc_android_log_print(ANDROID_LOG_ERROR, \
-            "pthread_debug", (format), ##__VA_ARGS__ )
+    __libc_format_log(ANDROID_LOG_ERROR, "pthread_debug", (format), ##__VA_ARGS__ )
 
 #define LOGI(format, ...)  \
-    __libc_android_log_print(ANDROID_LOG_INFO, \
-            "pthread_debug", (format), ##__VA_ARGS__ )
+    __libc_format_log(ANDROID_LOG_INFO, "pthread_debug", (format), ##__VA_ARGS__ )
 
 static const char* const kStartBanner =
         "===============================================================";
@@ -120,185 +118,9 @@
 
 extern char* __progname;
 
-// =============================================================================
-// map info functions
-// =============================================================================
-
-typedef struct mapinfo {
-    struct mapinfo *next;
-    unsigned start;
-    unsigned end;
-    char name[];
-} mapinfo;
-
-static mapinfo* sMapInfo = NULL;
-
-static mapinfo *parse_maps_line(char *line)
-{
-    mapinfo *mi;
-    int len = strlen(line);
-
-    if(len < 1) return 0;
-    line[--len] = 0;
-
-    if(len < 50) return 0;
-    if(line[20] != 'x') return 0;
-
-    mi = malloc(sizeof(mapinfo) + (len - 47));
-    if(mi == 0) return 0;
-
-    mi->start = strtoul(line, 0, 16);
-    mi->end = strtoul(line + 9, 0, 16);
-    /* To be filled in parse_elf_info if the mapped section starts with
-     * elf_header
-     */
-    mi->next = 0;
-    strcpy(mi->name, line + 49);
-
-    return mi;
-}
-
-static mapinfo *init_mapinfo(int pid)
-{
-    struct mapinfo *milist = NULL;
-    char data[1024];
-    sprintf(data, "/proc/%d/maps", pid);
-    FILE *fp = fopen(data, "r");
-    if(fp) {
-        while(fgets(data, sizeof(data), fp)) {
-            mapinfo *mi = parse_maps_line(data);
-            if(mi) {
-                mi->next = milist;
-                milist = mi;
-            }
-        }
-        fclose(fp);
-    }
-
-    return milist;
-}
-
-static void deinit_mapinfo(mapinfo *mi)
-{
-   mapinfo *del;
-   while(mi) {
-       del = mi;
-       mi = mi->next;
-       free(del);
-   }
-}
-
-/* Find the containing map info for the pc */
-static const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc)
-{
-    *rel_pc = pc;
-    while(mi) {
-        if((pc >= mi->start) && (pc < mi->end)){
-            // Only calculate the relative offset for shared libraries
-            if (strstr(mi->name, ".so")) {
-                *rel_pc -= mi->start;
-            }
-            return mi;
-        }
-        mi = mi->next;
-    }
-    return NULL;
-}
-
-// =============================================================================
-// stack trace functions
-// =============================================================================
-
 #define STACK_TRACE_DEPTH 16
 
-typedef struct
-{
-    size_t count;
-    intptr_t* addrs;
-} stack_crawl_state_t;
-
-/* depends how the system includes define this */
-#ifdef HAVE_UNWIND_CONTEXT_STRUCT
-typedef struct _Unwind_Context __unwind_context;
-#else
-typedef _Unwind_Context __unwind_context;
-#endif
-
-static _Unwind_Reason_Code trace_function(__unwind_context *context, void *arg)
-{
-    stack_crawl_state_t* state = (stack_crawl_state_t*)arg;
-    if (state->count) {
-        intptr_t ip = (intptr_t)_Unwind_GetIP(context);
-        if (ip) {
-            state->addrs[0] = ip;
-            state->addrs++;
-            state->count--;
-            return _URC_NO_REASON;
-        }
-    }
-    /*
-     * If we run out of space to record the address or 0 has been seen, stop
-     * unwinding the stack.
-     */
-    return _URC_END_OF_STACK;
-}
-
-static inline
-int get_backtrace(intptr_t* addrs, size_t max_entries)
-{
-    stack_crawl_state_t state;
-    state.count = max_entries;
-    state.addrs = (intptr_t*)addrs;
-    _Unwind_Backtrace(trace_function, (void*)&state);
-    return max_entries - state.count;
-}
-
-static void log_backtrace(intptr_t* addrs, size_t c)
-{
-    int index = 0;
-    size_t i;
-    for (i=0 ; i<c; i++) {
-        unsigned int relpc;
-        void* offset = 0;
-        const char* symbol = NULL;
-
-#if HAVE_DLADDR
-        Dl_info info;
-        if (dladdr((void*)addrs[i], &info)) {
-            offset = info.dli_saddr;
-            symbol = info.dli_sname;
-        }
-#endif
-
-        if (symbol || index>0 || !HAVE_DLADDR) {
-            /*
-             * this test is a bit sketchy, but it allows us to skip the
-             * stack trace entries due to this debugging code. it works
-             * because those don't have a symbol (they're not exported)
-             */
-            mapinfo const* mi = pc_to_mapinfo(sMapInfo, addrs[i], &relpc);
-            char const* soname = mi ? mi->name : NULL;
-#if HAVE_DLADDR
-            if (!soname)
-                soname = info.dli_fname;
-#endif
-            if (!soname)
-                soname = "unknown";
-
-            if (symbol) {
-                LOGW("          "
-                     "#%02d  pc %08lx  %s (%s+0x%x)",
-                     index, relpc, soname, symbol,
-                     addrs[i] - (intptr_t)offset);
-            } else {
-                LOGW("          "
-                     "#%02d  pc %08lx  %s",
-                     index, relpc, soname);
-            }
-            index++;
-        }
-    }
-}
+static mapinfo_t* gMapInfo;
 
 /****************************************************************************/
 
@@ -322,18 +144,21 @@
 static size_t sDbgAllocOffset = DBG_ALLOC_BLOCK_SIZE;
 static char* sDbgAllocPtr = NULL;
 
-static void* DbgAllocLocked(size_t size) {
+template <typename T>
+static T* DbgAllocLocked(size_t count = 1) {
+    size_t size = sizeof(T) * count;
     if ((sDbgAllocOffset + size) > DBG_ALLOC_BLOCK_SIZE) {
         sDbgAllocOffset = 0;
-        sDbgAllocPtr = mmap(NULL, DBG_ALLOC_BLOCK_SIZE, PROT_READ|PROT_WRITE,
-                MAP_ANON | MAP_PRIVATE, 0, 0);
+        sDbgAllocPtr = reinterpret_cast<char*>(mmap(NULL, DBG_ALLOC_BLOCK_SIZE,
+                                                    PROT_READ|PROT_WRITE,
+                                                    MAP_ANON | MAP_PRIVATE, 0, 0));
         if (sDbgAllocPtr == MAP_FAILED) {
             return NULL;
         }
     }
     void* addr = sDbgAllocPtr + sDbgAllocOffset;
     sDbgAllocOffset += size;
-    return addr;
+    return reinterpret_cast<T*>(addr);
 }
 
 static void* debug_realloc(void *ptr, size_t size, size_t old_size) {
@@ -447,8 +272,8 @@
 
 /****************************************************************************/
 
-extern int pthread_mutex_lock_impl(pthread_mutex_t *mutex);
-extern int pthread_mutex_unlock_impl(pthread_mutex_t *mutex);
+extern "C" int pthread_mutex_lock_impl(pthread_mutex_t *mutex);
+extern "C" int pthread_mutex_unlock_impl(pthread_mutex_t *mutex);
 
 static int pthread_mutex_lock_unchecked(pthread_mutex_t *mutex) {
     return pthread_mutex_lock_impl(mutex);
@@ -460,9 +285,9 @@
 
 /****************************************************************************/
 
-static void dup_backtrace(CallStack* stack, int count, intptr_t const* addrs) {
+static void dup_backtrace(CallStack* stack, size_t count, intptr_t const* addrs) {
     stack->depth = count;
-    stack->addrs = DbgAllocLocked(count * sizeof(intptr_t));
+    stack->addrs = DbgAllocLocked<intptr_t>(count);
     memcpy(stack->addrs, addrs, count * sizeof(intptr_t));
 }
 
@@ -545,9 +370,9 @@
         /* Turn off prediction temporarily in this thread while logging */
         sPthreadDebugDisabledThread = gettid();
 
-        if (sMapInfo == NULL) {
-            // note: we're protected by sDbgLock
-            sMapInfo = init_mapinfo(getpid());
+        if (gMapInfo == NULL) {
+            // note: we're protected by sDbgLock.
+            gMapInfo = mapinfo_create(getpid());
         }
 
         LOGW("%s\n", kStartBanner);
@@ -555,7 +380,7 @@
         LOGW("Illegal lock attempt:\n");
         LOGW("--- pthread_mutex_t at %p\n", obj->mutex);
         stackDepth = get_backtrace(addrs, STACK_TRACE_DEPTH);
-        log_backtrace(addrs, stackDepth);
+        log_backtrace(gMapInfo, addrs, stackDepth);
 
         LOGW("+++ Currently held locks in this thread (in reverse order):");
         MutexInfo* cur = obj;
@@ -566,7 +391,7 @@
             if (parent->owner == ourtid) {
                 LOGW("--- pthread_mutex_t at %p\n", parent->mutex);
                 if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) {
-                    log_backtrace(parent->stackTrace, parent->stackDepth);
+                    log_backtrace(gMapInfo, parent->stackTrace, parent->stackDepth);
                 }
                 cur = parent;
                 break;
@@ -589,13 +414,13 @@
             if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) {
                 int index = historyListHas(&obj->parents, objParent);
                 if ((size_t)index < (size_t)obj->stacks.count) {
-                    log_backtrace(
-                            obj->stacks.stack[index].addrs,
-                            obj->stacks.stack[index].depth);
+                    log_backtrace(gMapInfo,
+                                  obj->stacks.stack[index].addrs,
+                                  obj->stacks.stack[index].depth);
                 } else {
-                    log_backtrace(
-                            obj->stackTrace,
-                            obj->stackDepth);
+                    log_backtrace(gMapInfo,
+                                  obj->stackTrace,
+                                  obj->stackDepth);
                 }
             }
             result = 0;
@@ -640,8 +465,8 @@
 
     linkParentToChild(mrl, object);
     if (!traverseTree(object, mrl)) {
-        deinit_mapinfo(sMapInfo);
-        sMapInfo = NULL;
+        mapinfo_destroy(gMapInfo);
+        gMapInfo = NULL;
         LOGW("%s\n", kEndBanner);
         unlinkParentFromChild(mrl, object);
         // reenable pthread debugging for this thread
@@ -758,7 +583,7 @@
 
     if (entry == NULL) {
         // create a new entry
-        entry = (HashEntry*)DbgAllocLocked(sizeof(HashEntry));
+        entry = DbgAllocLocked<HashEntry>();
         entry->data = NULL;
         entry->slot = slot;
         entry->prev = NULL;
@@ -785,8 +610,9 @@
             &mutex, sizeof(mutex),
             &MutexInfo_equals);
     if (entry->data == NULL) {
-        entry->data = (MutexInfo*)DbgAllocLocked(sizeof(MutexInfo));
-        initMutexInfo(entry->data, mutex);
+        MutexInfo* mutex_info = DbgAllocLocked<MutexInfo>();
+        entry->data = mutex_info;
+        initMutexInfo(mutex_info, mutex);
     }
 
     pthread_mutex_unlock_unchecked(&sDbgLock);
@@ -808,8 +634,9 @@
             &pid, sizeof(pid),
             &ThreadInfo_equals);
     if (entry->data == NULL) {
-        entry->data = (ThreadInfo*)DbgAllocLocked(sizeof(ThreadInfo));
-        initThreadInfo(entry->data, pid);
+        ThreadInfo* thread_info = DbgAllocLocked<ThreadInfo>();
+        entry->data = thread_info;
+        initThreadInfo(thread_info, pid);
     }
 
     pthread_mutex_unlock_unchecked(&sDbgLock);
@@ -848,8 +675,7 @@
  * after system properties have been initialized
  */
 
-__LIBC_HIDDEN__
-void pthread_debug_init(void) {
+extern "C" __LIBC_HIDDEN__ void pthread_debug_init() {
     char env[PROP_VALUE_MAX];
     if (__system_property_get("debug.libc.pthread", env)) {
         int level = atoi(env);
@@ -872,8 +698,7 @@
  * the checks before the lock is held.)
  */
 
-__LIBC_HIDDEN__
-void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex)
+extern "C" __LIBC_HIDDEN__ void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex)
 {
     if (sPthreadDebugLevel == 0) return;
     // prediction disabled for this thread
@@ -890,8 +715,7 @@
  * still held (ie: before calling the real unlock)
  */
 
-__LIBC_HIDDEN__
-void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex)
+extern "C" __LIBC_HIDDEN__ void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex)
 {
     if (sPthreadDebugLevel == 0) return;
     // prediction disabled for this thread
diff --git a/libc/bionic/ssp.cpp b/libc/bionic/ssp.cpp
index fdf8832..08c36c5 100644
--- a/libc/bionic/ssp.cpp
+++ b/libc/bionic/ssp.cpp
@@ -63,8 +63,8 @@
     path[count] = '\0';
   }
 
-  // Do a best effort at logging. This ends up calling writev(2).
-  __libc_android_log_print(ANDROID_LOG_FATAL, path, "stack corruption detected: aborted");
+  // Do a best effort at logging.
+  __libc_android_log_write(ANDROID_LOG_FATAL, path, "stack corruption detected: aborted");
 
   // Make sure there is no default action for SIGABRT.
   struct sigaction sa;
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index 48281b4..3f24d1b 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -32,6 +32,7 @@
 #include <mntent.h>
 #include <netdb.h>
 #include <private/android_filesystem_config.h>
+#include <private/debug_format.h>
 #include <private/logd.h>
 #include <pthread.h>
 #include <pwd.h>
@@ -435,7 +436,7 @@
 
 static void unimplemented_stub(const char* function) {
   const char* fmt = "%s(3) is not implemented on Android\n";
-  __libc_android_log_print(ANDROID_LOG_WARN, "libc", fmt, function);
+  __libc_format_log(ANDROID_LOG_WARN, "libc", fmt, function);
   fprintf(stderr, fmt, function);
 }
 
diff --git a/libc/private/bionic_auxv.h b/libc/private/bionic_auxv.h
index d3b0038..69d15b6 100644
--- a/libc/private/bionic_auxv.h
+++ b/libc/private/bionic_auxv.h
@@ -25,8 +25,8 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#ifndef _SYS_AUXV_H_
-#define _SYS_AUXV_H_
+#ifndef _PRIVATE_BIONIC_AUXV_H_
+#define _PRIVATE_BIONIC_AUXV_H_
 
 #include <elf.h>
 
@@ -36,4 +36,4 @@
 
 __END_DECLS
 
-#endif /* _SYS_AUXV_H_ */
+#endif /* _PRIVATE_BIONIC_AUXV_H_ */
diff --git a/linker/linker_format.h b/libc/private/debug_format.h
similarity index 65%
rename from linker/linker_format.h
rename to libc/private/debug_format.h
index 862e439..0bc1148 100644
--- a/linker/linker_format.h
+++ b/libc/private/debug_format.h
@@ -26,17 +26,30 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LINKER_FORMAT_H
-#define _LINKER_FORMAT_H
+#ifndef _DEBUG_FORMAT_H
+#define _DEBUG_FORMAT_H
 
+#include <sys/cdefs.h>
 #include <stdarg.h>
 #include <stddef.h>
 
-// Formatting routines for the dynamic linker's debug traces
-// We want to avoid dragging the whole C library fprintf()
-// implementation into the dynamic linker since this creates
-// issues (it uses malloc()/free()) and increases code size.
-int format_buffer(char* buffer, size_t buffer_size, const char* format, ...)
+__BEGIN_DECLS
+
+// Formatting routines for the C library's internal debugging.
+// Unlike the usual alternatives, these don't allocate.
+
+__LIBC_HIDDEN__ int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...)
     __attribute__((__format__(printf, 3, 4)));
 
-#endif /* _LINKER_FORMAT_H */
+__LIBC_HIDDEN__ int __libc_format_fd(int fd, const char* format, ...)
+    __attribute__((__format__(printf, 2, 3)));
+
+__LIBC_HIDDEN__ int __libc_format_log(int priority, const char* tag, const char* format, ...)
+    __attribute__((__format__(printf, 3, 4)));
+
+__LIBC_HIDDEN__ int __libc_format_log_va_list(int priority, const char* tag, const char* format,
+                                              va_list ap);
+
+__END_DECLS
+
+#endif /* _DEBUG_FORMAT_H */
diff --git a/libc/upstream-netbsd/libc/string/memccpy.c b/libc/upstream-netbsd/libc/string/memccpy.c
new file mode 100644
index 0000000..c086241
--- /dev/null
+++ b/libc/upstream-netbsd/libc/string/memccpy.c
@@ -0,0 +1,61 @@
+/*	$NetBSD: memccpy.c,v 1.13 2012/06/25 22:32:46 abs Exp $	*/
+
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)memccpy.c	8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: memccpy.c,v 1.13 2012/06/25 22:32:46 abs Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <assert.h>
+#include <string.h>
+
+void *
+memccpy(void *t, const void *f, int c, size_t n)
+{
+
+	_DIAGASSERT(t != 0);
+	_DIAGASSERT(f != 0);
+
+	if (n) {
+		unsigned char *tp = t;
+		const unsigned char *fp = f;
+		unsigned char uc = c;
+		do {
+			if ((*tp++ = *fp++) == uc)
+				return (tp);
+		} while (--n != 0);
+	}
+	return (0);
+}
diff --git a/libc/upstream-netbsd/libc/string/strcoll.c b/libc/upstream-netbsd/libc/string/strcoll.c
new file mode 100644
index 0000000..77a0942
--- /dev/null
+++ b/libc/upstream-netbsd/libc/string/strcoll.c
@@ -0,0 +1,59 @@
+/*	$NetBSD: strcoll.c,v 1.10 2012/06/25 22:32:46 abs Exp $	*/
+
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)strcoll.c	8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: strcoll.c,v 1.10 2012/06/25 22:32:46 abs Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <assert.h>
+#include <string.h>
+
+/*
+ * Compare strings according to LC_COLLATE category of current locale.
+ */
+int
+strcoll(const char *s1, const char *s2)
+{
+
+	_DIAGASSERT(s1 != NULL);
+	_DIAGASSERT(s2 != NULL);
+
+	/* LC_COLLATE is unimplemented, hence always "C" */
+	return (strcmp(s1, s2));
+}
diff --git a/linker/Android.mk b/linker/Android.mk
index c85b09e..9718d90 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -13,7 +13,6 @@
     dlfcn.cpp \
     linker.cpp \
     linker_environ.cpp \
-    linker_format.cpp \
     linker_phdr.cpp \
     rt.cpp
 
diff --git a/linker/debugger.cpp b/linker/debugger.cpp
index 5fd5cb7..492ca4b 100644
--- a/linker/debugger.cpp
+++ b/linker/debugger.cpp
@@ -27,7 +27,6 @@
  */
 
 #include "linker.h"
-#include "linker_format.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -38,6 +37,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
+#include <private/debug_format.h>
 #include <private/logd.h>
 
 extern "C" int tgkill(int tgid, int tid, int sig);
@@ -109,43 +109,40 @@
  * could allocate memory or hold a lock.
  */
 static void logSignalSummary(int signum, const siginfo_t* info) {
-    const char* signame;
+    const char* signal_name;
     switch (signum) {
-        case SIGILL:    signame = "SIGILL";     break;
-        case SIGABRT:   signame = "SIGABRT";    break;
-        case SIGBUS:    signame = "SIGBUS";     break;
-        case SIGFPE:    signame = "SIGFPE";     break;
-        case SIGSEGV:   signame = "SIGSEGV";    break;
+        case SIGILL:    signal_name = "SIGILL";     break;
+        case SIGABRT:   signal_name = "SIGABRT";    break;
+        case SIGBUS:    signal_name = "SIGBUS";     break;
+        case SIGFPE:    signal_name = "SIGFPE";     break;
+        case SIGSEGV:   signal_name = "SIGSEGV";    break;
 #if defined(SIGSTKFLT)
-        case SIGSTKFLT: signame = "SIGSTKFLT";  break;
+        case SIGSTKFLT: signal_name = "SIGSTKFLT";  break;
 #endif
-        case SIGPIPE:   signame = "SIGPIPE";    break;
-        default:        signame = "???";        break;
+        case SIGPIPE:   signal_name = "SIGPIPE";    break;
+        default:        signal_name = "???";        break;
     }
 
-    char threadname[MAX_TASK_NAME_LEN + 1]; // one more for termination
-    if (prctl(PR_GET_NAME, (unsigned long)threadname, 0, 0, 0) != 0) {
-        strcpy(threadname, "<name unknown>");
+    char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination
+    if (prctl(PR_GET_NAME, (unsigned long)thread_name, 0, 0, 0) != 0) {
+        strcpy(thread_name, "<name unknown>");
     } else {
-        // short names are null terminated by prctl, but the manpage
+        // short names are null terminated by prctl, but the man page
         // implies that 16 byte names are not.
-        threadname[MAX_TASK_NAME_LEN] = 0;
+        thread_name[MAX_TASK_NAME_LEN] = 0;
     }
 
-    char buffer[128];
     // "info" will be NULL if the siginfo_t information was not available.
     if (info != NULL) {
-        format_buffer(buffer, sizeof(buffer),
-                      "Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)",
-                      signum, signame, reinterpret_cast<uintptr_t>(info->si_addr),
-                      info->si_code, gettid(), threadname);
+        __libc_format_log(ANDROID_LOG_FATAL, "libc",
+                          "Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)",
+                          signum, signal_name, reinterpret_cast<uintptr_t>(info->si_addr),
+                          info->si_code, gettid(), thread_name);
     } else {
-        format_buffer(buffer, sizeof(buffer),
-            "Fatal signal %d (%s), thread %d (%s)",
-            signum, signame, gettid(), threadname);
+        __libc_format_log(ANDROID_LOG_FATAL, "libc",
+                          "Fatal signal %d (%s), thread %d (%s)",
+                          signum, signal_name, gettid(), thread_name);
     }
-
-    __libc_android_log_write(ANDROID_LOG_FATAL, "libc", buffer);
 }
 
 /*
@@ -178,8 +175,6 @@
  * we crash.
  */
 void debugger_signal_handler(int n, siginfo_t* info, void*) {
-    char msgbuf[128];
-
     /*
      * It's possible somebody cleared the SA_SIGINFO flag, which would mean
      * our "info" arg holds an undefined value.
@@ -215,17 +210,15 @@
 
         if (ret < 0) {
             /* read or write failed -- broken connection? */
-            format_buffer(msgbuf, sizeof(msgbuf),
-                "Failed while talking to debuggerd: %s", strerror(errno));
-            __libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf);
+            __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s",
+                              strerror(errno));
         }
 
         close(s);
     } else {
         /* socket failed; maybe process ran out of fds */
-        format_buffer(msgbuf, sizeof(msgbuf),
-            "Unable to open connection to debuggerd: %s", strerror(errno));
-        __libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf);
+        __libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s",
+                          strerror(errno));
     }
 
     /* remove our net so we fault for real when we return */
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 0a89b72..c8a2a84 100755
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -41,13 +41,13 @@
 
 // Private C library headers.
 #include <private/bionic_tls.h>
+#include <private/debug_format.h>
 #include <private/logd.h>
 #include <private/ScopedPthreadMutexLocker.h>
 
 #include "linker.h"
 #include "linker_debug.h"
 #include "linker_environ.h"
-#include "linker_format.h"
 #include "linker_phdr.h"
 
 /* Assume average path length of 64 and max 8 paths */
@@ -159,7 +159,7 @@
 static char __linker_dl_err_buf[768];
 #define DL_ERR(fmt, x...) \
     do { \
-        format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf), fmt, ##x); \
+        __libc_format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf), fmt, ##x); \
         /* If LD_DEBUG is set high enough, send every dlerror(3) message to the log. */ \
         DEBUG(fmt "\n", ##x); \
     } while(0)
@@ -674,7 +674,7 @@
 static int open_library_on_path(const char* name, const char* const paths[]) {
   char buf[512];
   for (size_t i = 0; paths[i] != NULL; ++i) {
-    int n = format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name);
+    int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name);
     if (n < 0 || n >= static_cast<int>(sizeof(buf))) {
       PRINT("Warning: ignoring very long library path: %s/%s\n", paths[i], name);
       continue;
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 0a3710b..b326d00 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -52,19 +52,17 @@
 
 /*********************************************************************/
 
-#include "linker_format.h"
+#include <private/debug_format.h>
 
 #if LINKER_DEBUG_TO_LOG
-extern int format_log(int, const char*, const char*, ...) __attribute__((__format__(printf, 3, 4)));
 #define _PRINTVF(v,x...)                                        \
     do {                                                          \
-        if (debug_verbosity > (v)) format_log(5-(v),"linker",x);  \
+        if (debug_verbosity > (v)) __libc_format_log(5-(v),"linker",x);  \
     } while (0)
 #else /* !LINKER_DEBUG_TO_LOG */
-extern int format_fd(int, const char *, ...) __attribute__((__format__(printf, 2, 3)));
 #define _PRINTVF(v,x...)                           \
     do {                                             \
-        if (debug_verbosity > (v)) format_fd(1, x);  \
+        if (debug_verbosity > (v)) __libc_format_fd(1, x);  \
     } while (0)
 #endif /* !LINKER_DEBUG_TO_LOG */