Use libunwindbacktrace for debug malloc code.

Create a method of disabling the debug allocation code paths so that
it's possible to use the libunwindbacktrace library without any
modifications.

Use this path to create and destroy the maps for the process. It's not
stricly necessary in the init code since the symbols are not modified
until after the initialize calls.

Also, remove the debug_XXX source files that doesn't need to be in libc.so.

Fix the maps reading code since it was completely broken for 64 bit.

Bug: 16408686

(cherry picked from commit 861c0ef37bcfcae56d88572cb01c18bcfe1faded)

Change-Id: I04445f0cf9a1e85172b64d57df92eb7939ce2332
diff --git a/libc/Android.mk b/libc/Android.mk
index 1fb5e84..8326dbb 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -982,8 +982,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 \
 
@@ -1049,7 +1047,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 \
@@ -1064,6 +1065,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