Merge "Use libunwindbacktrace for debug malloc code."
diff --git a/libc/Android.mk b/libc/Android.mk
index 15a68b9..9554e18 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -980,8 +980,6 @@
     $(libc_arch_dynamic_src_files) \
     $(libc_static_common_src_files) \
     bionic/malloc_debug_common.cpp \
-    bionic/debug_mapinfo.cpp \
-    bionic/debug_stacktrace.cpp \
     bionic/libc_init_dynamic.cpp \
     bionic/NetdClient.cpp \
 
@@ -1047,7 +1045,10 @@
 LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
 
-LOCAL_C_INCLUDES := $(libc_common_c_includes)
+# Make sure that unwind.h comes from libunwind.
+LOCAL_C_INCLUDES := \
+    external/libunwind/include \
+    $(libc_common_c_includes) \
 
 LOCAL_SRC_FILES := \
     bionic/debug_mapinfo.cpp \
@@ -1062,6 +1063,7 @@
 
 LOCAL_SHARED_LIBRARIES := libc libdl
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
+LOCAL_WHOLE_STATIC_LIBRARIES := libunwindbacktrace
 LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
 
 # Don't install on release build
diff --git a/libc/bionic/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp
index 17276ce..d83799a 100644
--- a/libc/bionic/debug_mapinfo.cpp
+++ b/libc/bionic/debug_mapinfo.cpp
@@ -26,39 +26,48 @@
  * SUCH DAMAGE.
  */
 
+#include <ctype.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <sys/mman.h>
 
 #include "debug_mapinfo.h"
+#include "malloc_debug_disable.h"
 
-// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so
-// 012345678901234567890123456789012345678901234567890123456789
-// 0         1         2         3         4         5
-
+// Format of /proc/<PID>/maps:
+//   6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so
 static mapinfo_t* parse_maps_line(char* line) {
-  int len = strlen(line);
+  uintptr_t start;
+  uintptr_t end;
+  int name_pos;
+  if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d%n", &start,
+             &end, &name_pos) < 2) {
+    return NULL;
+  }
 
-  if (len < 1) return 0;
-  line[--len] = 0;
+  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;
+  }
 
-  if (len < 50) return 0;
-  if (line[20] != 'x') return 0;
-
-  mapinfo_t* mi = static_cast<mapinfo_t*>(
-      mmap(NULL, sizeof(mapinfo_t) + (len - 47), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0));
-  if (mi == MAP_FAILED) return 0;
-
-  mi->start = strtoul(line, 0, 16);
-  mi->end = strtoul(line + 9, 0, 16);
-  mi->next = 0;
-  strcpy(mi->name, line + 49);
-
+  mapinfo_t* mi = reinterpret_cast<mapinfo_t*>(calloc(1, sizeof(mapinfo_t) + name_len + 1));
+  if (mi) {
+    mi->start = start;
+    mi->end = end;
+    memcpy(mi->name, name, name_len);
+    mi->name[name_len] = '\0';
+  }
   return mi;
 }
 
 __LIBC_HIDDEN__ mapinfo_t* mapinfo_create(pid_t pid) {
+  ScopedDisableDebugCalls disable;
+
   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);
@@ -77,10 +86,12 @@
 }
 
 __LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi) {
+  ScopedDisableDebugCalls disable;
+
   while (mi != NULL) {
     mapinfo_t* del = mi;
     mi = mi->next;
-    munmap(del, sizeof(mapinfo_t) + strlen(del->name) + 2);
+    free(del);
   }
 }
 
diff --git a/libc/bionic/debug_mapinfo.h b/libc/bionic/debug_mapinfo.h
index cccd2e3..926b377 100644
--- a/libc/bionic/debug_mapinfo.h
+++ b/libc/bionic/debug_mapinfo.h
@@ -33,8 +33,8 @@
 
 struct mapinfo_t {
   struct mapinfo_t* next;
-  unsigned start;
-  unsigned end;
+  uintptr_t start;
+  uintptr_t end;
   char name[];
 };
 
diff --git a/libc/bionic/debug_stacktrace.cpp b/libc/bionic/debug_stacktrace.cpp
index 713e761..b86e2af 100644
--- a/libc/bionic/debug_stacktrace.cpp
+++ b/libc/bionic/debug_stacktrace.cpp
@@ -35,6 +35,7 @@
 #include <sys/types.h>
 
 #include "debug_mapinfo.h"
+#include "malloc_debug_disable.h"
 #include "private/libc_logging.h"
 
 #if defined(__LP64__)
@@ -56,6 +57,8 @@
 static DemanglerFn g_demangler_fn = NULL;
 
 __LIBC_HIDDEN__ void backtrace_startup() {
+  ScopedDisableDebugCalls disable;
+
   g_map_info = mapinfo_create(getpid());
   g_demangler = dlopen("libgccdemangle.so", RTLD_NOW);
   if (g_demangler != NULL) {
@@ -65,6 +68,8 @@
 }
 
 __LIBC_HIDDEN__ void backtrace_shutdown() {
+  ScopedDisableDebugCalls disable;
+
   mapinfo_destroy(g_map_info);
   dlclose(g_demangler);
 }
@@ -98,7 +103,7 @@
     return _URC_NO_REASON;
   }
 
-#ifdef __arm__
+#if defined(__arm__)
   /*
    * The instruction pointer is pointing at the instruction after the bl(x), and
    * the _Unwind_Backtrace routine already masks the Thumb mode indicator (LSB
@@ -121,12 +126,16 @@
 }
 
 __LIBC_HIDDEN__ int get_backtrace(uintptr_t* frames, size_t max_depth) {
+  ScopedDisableDebugCalls disable;
+
   stack_crawl_state_t state(frames, max_depth);
   _Unwind_Backtrace(trace_function, &state);
   return state.frame_count;
 }
 
 __LIBC_HIDDEN__ void log_backtrace(uintptr_t* frames, size_t frame_count) {
+  ScopedDisableDebugCalls disable;
+
   uintptr_t self_bt[16];
   if (frames == NULL) {
     frame_count = get_backtrace(self_bt, 16);
@@ -146,7 +155,7 @@
       symbol = info.dli_sname;
     }
 
-    uintptr_t rel_pc;
+    uintptr_t rel_pc = offset;
     const mapinfo_t* mi = (g_map_info != NULL) ? mapinfo_find(g_map_info, frames[i], &rel_pc) : NULL;
     const char* soname = (mi != NULL) ? mi->name : info.dli_fname;
     if (soname == NULL) {
diff --git a/libc/bionic/malloc_debug_check.cpp b/libc/bionic/malloc_debug_check.cpp
index 1c63d4d..94ba6f5 100644
--- a/libc/bionic/malloc_debug_check.cpp
+++ b/libc/bionic/malloc_debug_check.cpp
@@ -49,6 +49,7 @@
 #include "debug_mapinfo.h"
 #include "debug_stacktrace.h"
 #include "malloc_debug_common.h"
+#include "malloc_debug_disable.h"
 #include "private/bionic_macros.h"
 #include "private/libc_logging.h"
 #include "private/ScopedPthreadMutexLocker.h"
@@ -331,6 +332,9 @@
 
 extern "C" void* chk_malloc(size_t bytes) {
 //  log_message("%s: %s\n", __FILE__, __FUNCTION__);
+    if (DebugCallsDisabled()) {
+        return g_malloc_dispatch->malloc(bytes);
+    }
 
     size_t size = sizeof(hdr_t) + bytes + sizeof(ftr_t);
     if (size < bytes) { // Overflow
@@ -348,6 +352,10 @@
 }
 
 extern "C" void* chk_memalign(size_t alignment, size_t bytes) {
+    if (DebugCallsDisabled()) {
+        return g_malloc_dispatch->memalign(alignment, bytes);
+    }
+
     if (alignment <= MALLOC_ALIGNMENT) {
         return chk_malloc(bytes);
     }
@@ -386,6 +394,9 @@
 
 extern "C" void chk_free(void* ptr) {
 //  log_message("%s: %s\n", __FILE__, __FUNCTION__);
+    if (DebugCallsDisabled()) {
+        return g_malloc_dispatch->free(ptr);
+    }
 
     if (!ptr) /* ignore free(NULL) */
         return;
@@ -421,6 +432,9 @@
 
 extern "C" void* chk_realloc(void* ptr, size_t bytes) {
 //  log_message("%s: %s\n", __FILE__, __FUNCTION__);
+    if (DebugCallsDisabled()) {
+        return g_malloc_dispatch->realloc(ptr, bytes);
+    }
 
     if (!ptr) {
         return chk_malloc(bytes);
@@ -496,6 +510,10 @@
 
 extern "C" void* chk_calloc(size_t nmemb, size_t bytes) {
 //  log_message("%s: %s\n", __FILE__, __FUNCTION__);
+    if (DebugCallsDisabled()) {
+        return g_malloc_dispatch->calloc(nmemb, bytes);
+    }
+
     size_t total_bytes = nmemb * bytes;
     size_t size = sizeof(hdr_t) + total_bytes + sizeof(ftr_t);
     if (size < total_bytes || (nmemb && SIZE_MAX / nmemb < bytes)) { // Overflow
@@ -513,6 +531,10 @@
 }
 
 extern "C" size_t chk_malloc_usable_size(const void* ptr) {
+    if (DebugCallsDisabled()) {
+        return g_malloc_dispatch->malloc_usable_size(ptr);
+    }
+
     // malloc_usable_size returns 0 for NULL and unknown blocks.
     if (ptr == NULL)
         return 0;
@@ -529,6 +551,10 @@
 }
 
 extern "C" int chk_posix_memalign(void** memptr, size_t alignment, size_t size) {
+  if (DebugCallsDisabled()) {
+    return g_malloc_dispatch->posix_memalign(memptr, alignment, size);
+  }
+
   if (!powerof2(alignment)) {
     return EINVAL;
   }
@@ -538,7 +564,12 @@
   return (*memptr != NULL) ? 0 : ENOMEM;
 }
 
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
 extern "C" void* chk_pvalloc(size_t bytes) {
+  if (DebugCallsDisabled()) {
+    return g_malloc_dispatch->pvalloc(bytes);
+  }
+
   size_t pagesize = getpagesize();
   size_t size = BIONIC_ALIGN(bytes, pagesize);
   if (size < bytes) { // Overflow
@@ -548,10 +579,16 @@
 }
 
 extern "C" void* chk_valloc(size_t size) {
+  if (DebugCallsDisabled()) {
+    return g_malloc_dispatch->valloc(size);
+  }
   return chk_memalign(getpagesize(), size);
 }
+#endif
 
 static void ReportMemoryLeaks() {
+  ScopedDisableDebugCalls disable;
+
   // Use /proc/self/exe link to obtain the program name for logging
   // purposes. If it's not available, we set it to "<unknown>".
   char exe[PATH_MAX];
@@ -585,10 +622,14 @@
   }
 }
 
+pthread_key_t g_debug_calls_disabled;
+
 extern "C" bool malloc_debug_initialize(HashTable* hash_table, const MallocDebug* malloc_dispatch) {
   g_hash_table = hash_table;
   g_malloc_dispatch = malloc_dispatch;
 
+  pthread_key_create(&g_debug_calls_disabled, NULL);
+
   char debug_backlog[PROP_VALUE_MAX];
   if (__system_property_get("libc.debug.malloc.backlog", debug_backlog)) {
     g_malloc_debug_backlog = atoi(debug_backlog);
@@ -605,4 +646,6 @@
     ReportMemoryLeaks();
   }
   backtrace_shutdown();
+
+  pthread_setspecific(g_debug_calls_disabled, NULL);
 }
diff --git a/libc/bionic/malloc_debug_disable.h b/libc/bionic/malloc_debug_disable.h
new file mode 100644
index 0000000..9503128
--- /dev/null
+++ b/libc/bionic/malloc_debug_disable.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef MALLOC_DEBUG_DISABLE_H
+#define MALLOC_DEBUG_DISABLE_H
+
+#include <pthread.h>
+
+#include "private/bionic_macros.h"
+
+// =============================================================================
+// Used to disable the debug allocation calls.
+// =============================================================================
+extern pthread_key_t g_debug_calls_disabled;
+
+static inline bool DebugCallsDisabled() {
+  return pthread_getspecific(g_debug_calls_disabled) != NULL;
+}
+
+class ScopedDisableDebugCalls {
+ public:
+  ScopedDisableDebugCalls() : disabled_(DebugCallsDisabled()) {
+    if (!disabled_) {
+      pthread_setspecific(g_debug_calls_disabled, reinterpret_cast<const void*>(1));
+    }
+  }
+  ~ScopedDisableDebugCalls() {
+    if (!disabled_) {
+      pthread_setspecific(g_debug_calls_disabled, NULL);
+    }
+  }
+
+ private:
+  bool disabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedDisableDebugCalls);
+};
+
+#endif  // MALLOC_DEBUG_DISABLE_H
diff --git a/libc/bionic/malloc_debug_leak.cpp b/libc/bionic/malloc_debug_leak.cpp
index d9824f0..7926a1f 100644
--- a/libc/bionic/malloc_debug_leak.cpp
+++ b/libc/bionic/malloc_debug_leak.cpp
@@ -48,6 +48,7 @@
 
 #include "debug_stacktrace.h"
 #include "malloc_debug_common.h"
+#include "malloc_debug_disable.h"
 
 #include "private/bionic_macros.h"
 #include "private/libc_logging.h"
@@ -267,6 +268,7 @@
   return (*memptr != NULL) ? 0 : ENOMEM;
 }
 
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
 extern "C" void* fill_pvalloc(size_t bytes) {
   size_t pagesize = getpagesize();
   size_t size = BIONIC_ALIGN(bytes, pagesize);
@@ -279,6 +281,7 @@
 extern "C" void* fill_valloc(size_t size) {
   return fill_memalign(getpagesize(), size);
 }
+#endif
 
 // =============================================================================
 // malloc leak functions
@@ -287,6 +290,10 @@
 static uint32_t MEMALIGN_GUARD      = 0xA1A41520;
 
 extern "C" void* leak_malloc(size_t bytes) {
+    if (DebugCallsDisabled()) {
+        return g_malloc_dispatch->malloc(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!
 
@@ -319,6 +326,10 @@
 }
 
 extern "C" void leak_free(void* mem) {
+  if (DebugCallsDisabled()) {
+    return g_malloc_dispatch->free(mem);
+  }
+
   if (mem == NULL) {
     return;
   }
@@ -355,6 +366,10 @@
 }
 
 extern "C" void* leak_calloc(size_t n_elements, size_t elem_size) {
+    if (DebugCallsDisabled()) {
+        return g_malloc_dispatch->calloc(n_elements, elem_size);
+    }
+
     // Fail on overflow - just to be safe even though this code runs only
     // within the debugging C library, not the production one.
     if (n_elements && SIZE_MAX / n_elements < elem_size) {
@@ -370,6 +385,10 @@
 }
 
 extern "C" void* leak_realloc(void* oldMem, size_t bytes) {
+    if (DebugCallsDisabled()) {
+        return g_malloc_dispatch->realloc(oldMem, bytes);
+    }
+
     if (oldMem == NULL) {
         return leak_malloc(bytes);
     }
@@ -398,6 +417,10 @@
 }
 
 extern "C" void* leak_memalign(size_t alignment, size_t bytes) {
+    if (DebugCallsDisabled()) {
+        return g_malloc_dispatch->memalign(alignment, bytes);
+    }
+
     // we can just use malloc
     if (alignment <= MALLOC_ALIGNMENT) {
         return leak_malloc(bytes);
@@ -439,6 +462,10 @@
 }
 
 extern "C" size_t leak_malloc_usable_size(const void* mem) {
+    if (DebugCallsDisabled()) {
+        return g_malloc_dispatch->malloc_usable_size(mem);
+    }
+
     if (mem != NULL) {
         // Check the guard to make sure it is valid.
         const AllocationEntry* header = const_to_header((void*)mem);
@@ -467,6 +494,10 @@
 }
 
 extern "C" int leak_posix_memalign(void** memptr, size_t alignment, size_t size) {
+  if (DebugCallsDisabled()) {
+    return g_malloc_dispatch->posix_memalign(memptr, alignment, size);
+  }
+
   if (!powerof2(alignment)) {
     return EINVAL;
   }
@@ -476,7 +507,12 @@
   return (*memptr != NULL) ? 0 : ENOMEM;
 }
 
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
 extern "C" void* leak_pvalloc(size_t bytes) {
+  if (DebugCallsDisabled()) {
+    return g_malloc_dispatch->pvalloc(bytes);
+  }
+
   size_t pagesize = getpagesize();
   size_t size = BIONIC_ALIGN(bytes, pagesize);
   if (size < bytes) { // Overflow
@@ -486,5 +522,10 @@
 }
 
 extern "C" void* leak_valloc(size_t size) {
+  if (DebugCallsDisabled()) {
+    return g_malloc_dispatch->valloc(size);
+  }
+
   return leak_memalign(getpagesize(), size);
 }
+#endif