Split libc_debug.so into two .so modules loaded on demand from libc.so

This change is intended to eliminate need to replace libc.so with libc_debug.so in order to enablememory allocation debugging.
This is also the first step towards implementing extended memoryallocation debugging using emulator's capabilities in monitoring memory access.
diff --git a/libc/Android.mk b/libc/Android.mk
index 5718d18..98b2809 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -488,17 +488,12 @@
 LOCAL_SRC_FILES := \
 	$(libc_arch_static_src_files) \
 	bionic/dlmalloc.c \
+	bionic/malloc_debug_common.c \
 	bionic/libc_init_static.c
 
-LOCAL_CFLAGS := $(libc_common_cflags)
-
-ifeq ($(WITH_MALLOC_CHECK_LIBC_A),true)
-  LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
-  LOCAL_SRC_FILES += bionic/malloc_leak.c.arm
-endif
-
+LOCAL_CFLAGS := $(libc_common_cflags) \
+                -DLIBC_STATIC
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
-
 LOCAL_MODULE := libc
 LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
@@ -517,7 +512,7 @@
 LOCAL_SRC_FILES := \
 	$(libc_arch_dynamic_src_files) \
 	bionic/dlmalloc.c \
-	bionic/malloc_leak.c.arm \
+	bionic/malloc_debug_common.c \
 	bionic/libc_init_dynamic.c
 
 LOCAL_MODULE:= libc
@@ -537,8 +532,16 @@
 include $(BUILD_SHARED_LIBRARY)
 
 
+# For all builds, except for the -user build we will enable memory
+# allocation checking (including memory leaks, buffer overwrites, etc.)
+# Note that all these checks are also controlled by env. settings
+# that can enable, or disable specific checks. Note also that some of
+# the checks are available only in emulator and are implemeted in
+# libc_malloc_qemu_instrumented.so.
+ifneq ($(TARGET_BUILD_VARIANT),user)
+
 # ========================================================
-# libc_debug.so
+# libc_malloc_debug_leak.so
 # ========================================================
 include $(CLEAR_VARS)
 
@@ -549,30 +552,49 @@
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
 
 LOCAL_SRC_FILES := \
-	$(libc_arch_dynamic_src_files) \
-	bionic/dlmalloc.c \
-	bionic/malloc_leak.c.arm \
-	bionic/libc_init_dynamic.c
+	bionic/malloc_debug_leak.c
 
-LOCAL_MODULE:= libc_debug
+LOCAL_MODULE:= libc_malloc_debug_leak
 
-# WARNING: The only library libc.so should depend on is libdl.so!  If you add other libraries,
-# make sure to add -Wl,--exclude-libs=libgcc.a to the LOCAL_LDFLAGS for those libraries.  This
-# ensures that symbols that are pulled into those new libraries from libgcc.a are not declared
-# external; if that were the case, then libc would not pull those symbols from libgcc.a as it
-# should, instead relying on the external symbols from the dependent libraries.  That would
-# create an "cloaked" dependency on libgcc.a in libc though the libraries, which is not what
-# you wanted!
-
-LOCAL_SHARED_LIBRARIES := libdl
+LOCAL_SHARED_LIBRARIES := libc
 LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
 LOCAL_SYSTEM_SHARED_LIBRARIES :=
 # Don't prelink
 LOCAL_PRELINK_MODULE := false
 # Don't install on release build
-LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_TAGS := eng debug
 
 include $(BUILD_SHARED_LIBRARY)
 
+
+# ========================================================
+# libc_malloc_debug_qemu.so
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := \
+	$(libc_common_cflags) \
+	-DMALLOC_QEMU_INSTRUMENT
+
+LOCAL_C_INCLUDES := $(libc_common_c_includes)
+
+LOCAL_SRC_FILES := \
+	bionic/malloc_debug_qemu.c
+
+LOCAL_MODULE:= libc_malloc_debug_qemu
+
+LOCAL_SHARED_LIBRARIES := libc
+LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
+LOCAL_SYSTEM_SHARED_LIBRARIES :=
+# Don't prelink
+LOCAL_PRELINK_MODULE := false
+# Don't install on release build
+LOCAL_MODULE_TAGS := eng debug
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif	#!user
+
+
 # ========================================================
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libc/bionic/dlmalloc.c b/libc/bionic/dlmalloc.c
index f6f878e..19fbb75 100644
--- a/libc/bionic/dlmalloc.c
+++ b/libc/bionic/dlmalloc.c
@@ -390,9 +390,9 @@
   size_t. The value is used only if  HAVE_USR_INCLUDE_MALLOC_H is not set
 
 REALLOC_ZERO_BYTES_FREES    default: not defined
-  This should be set if a call to realloc with zero bytes should 
-  be the same as a call to free. Some people think it should. Otherwise, 
-  since this malloc returns a unique pointer for malloc(0), so does 
+  This should be set if a call to realloc with zero bytes should
+  be the same as a call to free. Some people think it should. Otherwise,
+  since this malloc returns a unique pointer for malloc(0), so does
   realloc(p, 0).
 
 LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H
@@ -671,7 +671,7 @@
 /* ------------------- Declarations of public routines ------------------- */
 
 /* Check an additional macro for the five primary functions */
-#if !defined(USE_DL_PREFIX) || !defined(MALLOC_LEAK_CHECK) 
+#ifndef USE_DL_PREFIX
 #define dlcalloc               calloc
 #define dlfree                 free
 #define dlmalloc               malloc
@@ -3627,7 +3627,7 @@
       m->seg.sflags = mmap_flag;
       m->magic = mparams.magic;
       init_bins(m);
-      if (is_global(m)) 
+      if (is_global(m))
         init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
       else {
         /* Offset top by embedded malloc_state */
@@ -3778,7 +3778,7 @@
     }
 
     /* Unmap any unused mmapped segments */
-    if (HAVE_MMAP) 
+    if (HAVE_MMAP)
       released += release_unused_segments(m);
 
     /* On failure, disable autotrim to avoid repeated failed future calls */
@@ -3986,7 +3986,7 @@
     while (a < alignment) a <<= 1;
     alignment = a;
   }
-  
+
   if (bytes >= MAX_REQUEST - alignment) {
     if (m != 0)  { /* Test isn't needed but avoids compiler warning */
       MALLOC_FAILURE_ACTION;
@@ -5446,5 +5446,5 @@
     Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
       * Based loosely on libg++-1.2X malloc. (It retains some of the overall
          structure of old version,  but most details differ.)
- 
+
 */
diff --git a/libc/bionic/dlmalloc.h b/libc/bionic/dlmalloc.h
index e5f7d4a..1b642d2 100644
--- a/libc/bionic/dlmalloc.h
+++ b/libc/bionic/dlmalloc.h
@@ -1,14 +1,14 @@
 /*
   Default header file for malloc-2.8.x, written by Doug Lea
   and released to the public domain, as explained at
-  http://creativecommons.org/licenses/publicdomain. 
- 
+  http://creativecommons.org/licenses/publicdomain.
+
   last update: Mon Aug 15 08:55:52 2005  Doug Lea  (dl at gee)
 
   This header is for ANSI C/C++ only.  You can set any of
   the following #defines before including:
 
-  * If USE_DL_PREFIX is defined, it is assumed that malloc.c 
+  * If USE_DL_PREFIX is defined, it is assumed that malloc.c
     was also compiled with this option, so all routines
     have names starting with "dl".
 
@@ -34,7 +34,7 @@
 #if !ONLY_MSPACES
 
 /* Check an additional macro for the five primary functions */
-#if !defined(USE_DL_PREFIX) || !defined(MALLOC_LEAK_CHECK) 
+#if !defined(USE_DL_PREFIX)
 #define dlcalloc               calloc
 #define dlfree                 free
 #define dlmalloc               malloc
diff --git a/libc/bionic/libc_init_dynamic.c b/libc/bionic/libc_init_dynamic.c
index b479b27..682ebcf 100644
--- a/libc/bionic/libc_init_dynamic.c
+++ b/libc/bionic/libc_init_dynamic.c
@@ -52,8 +52,6 @@
 #include "libc_init_common.h"
 #include <bionic_tls.h>
 
-extern void malloc_debug_init();
-
 /* We flag the __libc_preinit function as a constructor to ensure
  * that its address is listed in libc.so's .init_array section.
  * This ensures that the function is called by the dynamic linker
@@ -78,12 +76,11 @@
 
     __libc_init_common(elfdata);
 
-#ifdef MALLOC_LEAK_CHECK
-    /* setup malloc leak checker, requires system properties */
+    /* Setup malloc routines accordingly to the environment.
+     * Requires system properties
+     */
     extern void malloc_debug_init(void);
     malloc_debug_init();
-#endif
-
 }
 
 __noreturn void __libc_init(uintptr_t *elfdata,
diff --git a/libc/bionic/libc_init_static.c b/libc/bionic/libc_init_static.c
index e6264bb..d097b6b 100644
--- a/libc/bionic/libc_init_static.c
+++ b/libc/bionic/libc_init_static.c
@@ -68,12 +68,6 @@
     /* Initialize the C runtime environment */
     __libc_init_common(elfdata);
 
-#ifdef MALLOC_LEAK_CHECK
-    /* setup malloc leak checker, requires system properties */
-    extern void malloc_debug_init(void);
-    malloc_debug_init();
-#endif
-
     /* Several Linux ABIs don't pass the onexit pointer, and the ones that
      * do never use it.  Therefore, we ignore it.
      */
diff --git a/libc/bionic/malloc_debug_common.c b/libc/bionic/malloc_debug_common.c
new file mode 100644
index 0000000..4210915
--- /dev/null
+++ b/libc/bionic/malloc_debug_common.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+/*
+ * Contains definition of global variables and implementation of routines
+ * that are used by malloc leak detection code and other components in
+ * the system. The trick is that some components expect these data and
+ * routines to be defined / implemented in libc.so library, regardless
+ * whether or not MALLOC_LEAK_CHECK macro is defined. To make things even
+ * more tricky, malloc leak detection code, implemented in
+ * libc_malloc_debug.so also requires access to these variables and routines
+ * (to fill allocation entry hash table, for example). So, all relevant
+ * variables and routines are defined / implemented here and exported
+ * to all, leak detection code and other components via dynamic (libc.so),
+ * or static (libc.a) linking.
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "dlmalloc.h"
+#include "malloc_debug_common.h"
+
+/*
+ * In a VM process, this is set to 1 after fork()ing out of zygote.
+ */
+int gMallocLeakZygoteChild = 0;
+
+pthread_mutex_t gAllocationsMutex = PTHREAD_MUTEX_INITIALIZER;
+HashTable gHashTable;
+
+// =============================================================================
+// output functions
+// =============================================================================
+
+static int hash_entry_compare(const void* arg1, const void* arg2)
+{
+    HashEntry* e1 = *(HashEntry**)arg1;
+    HashEntry* e2 = *(HashEntry**)arg2;
+
+    size_t nbAlloc1 = e1->allocations;
+    size_t nbAlloc2 = e2->allocations;
+    size_t size1 = e1->size & ~SIZE_FLAG_MASK;
+    size_t size2 = e2->size & ~SIZE_FLAG_MASK;
+    size_t alloc1 = nbAlloc1 * size1;
+    size_t alloc2 = nbAlloc2 * size2;
+
+    // sort in descending order by:
+    // 1) total size
+    // 2) number of allocations
+    //
+    // This is used for sorting, not determination of equality, so we don't
+    // need to compare the bit flags.
+    int result;
+    if (alloc1 > alloc2) {
+        result = -1;
+    } else if (alloc1 < alloc2) {
+        result = 1;
+    } else {
+        if (nbAlloc1 > nbAlloc2) {
+            result = -1;
+        } else if (nbAlloc1 < nbAlloc2) {
+            result = 1;
+        } else {
+            result = 0;
+        }
+    }
+    return result;
+}
+
+/*
+ * Retrieve native heap information.
+ *
+ * "*info" is set to a buffer we allocate
+ * "*overallSize" is set to the size of the "info" buffer
+ * "*infoSize" is set to the size of a single entry
+ * "*totalMemory" is set to the sum of all allocations we're tracking; does
+ *   not include heap overhead
+ * "*backtraceSize" is set to the maximum number of entries in the back trace
+ */
+void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
+        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize)
+{
+    // don't do anything if we have invalid arguments
+    if (info == NULL || overallSize == NULL || infoSize == NULL ||
+            totalMemory == NULL || backtraceSize == NULL) {
+        return;
+    }
+
+    pthread_mutex_lock(&gAllocationsMutex);
+
+    if (gHashTable.count == 0) {
+        *info = NULL;
+        *overallSize = 0;
+        *infoSize = 0;
+        *totalMemory = 0;
+        *backtraceSize = 0;
+        goto done;
+    }
+
+    void** list = (void**)dlmalloc(sizeof(void*) * gHashTable.count);
+
+    // get the entries into an array to be sorted
+    int index = 0;
+    int i;
+    for (i = 0 ; i < HASHTABLE_SIZE ; i++) {
+        HashEntry* entry = gHashTable.slots[i];
+        while (entry != NULL) {
+            list[index] = entry;
+            *totalMemory = *totalMemory +
+                ((entry->size & ~SIZE_FLAG_MASK) * entry->allocations);
+            index++;
+            entry = entry->next;
+        }
+    }
+
+    // XXX: the protocol doesn't allow variable size for the stack trace (yet)
+    *infoSize = (sizeof(size_t) * 2) + (sizeof(intptr_t) * BACKTRACE_SIZE);
+    *overallSize = *infoSize * gHashTable.count;
+    *backtraceSize = BACKTRACE_SIZE;
+
+    // now get A byte array big enough for this
+    *info = (uint8_t*)dlmalloc(*overallSize);
+
+    if (*info == NULL) {
+        *overallSize = 0;
+        goto done;
+    }
+
+    qsort((void*)list, gHashTable.count, sizeof(void*), hash_entry_compare);
+
+    uint8_t* head = *info;
+    const int count = gHashTable.count;
+    for (i = 0 ; i < count ; i++) {
+        HashEntry* entry = list[i];
+        size_t entrySize = (sizeof(size_t) * 2) + (sizeof(intptr_t) * entry->numEntries);
+        if (entrySize < *infoSize) {
+            /* we're writing less than a full entry, clear out the rest */
+            /* TODO: only clear out the part we're not overwriting? */
+            memset(head, 0, *infoSize);
+        } else {
+            /* make sure the amount we're copying doesn't exceed the limit */
+            entrySize = *infoSize;
+        }
+        memcpy(head, &(entry->size), entrySize);
+        head += *infoSize;
+    }
+
+    dlfree(list);
+
+done:
+    pthread_mutex_unlock(&gAllocationsMutex);
+}
+
+void free_malloc_leak_info(uint8_t* info)
+{
+    dlfree(info);
+}
+
+struct mallinfo mallinfo()
+{
+    return dlmallinfo();
+}
+
+void* valloc(size_t bytes) {
+    /* assume page size of 4096 bytes */
+    return memalign( getpagesize(), bytes );
+}
+
+/* Support for malloc debugging.
+ * Note that if USE_DL_PREFIX is not defined, it's assumed that memory
+ * allocation routines are implemented somewhere else, so all our custom
+ * malloc routines should not be compiled at all.
+ */
+#ifdef USE_DL_PREFIX
+
+/* Table for dispatching malloc calls, initialized with default dispatchers. */
+const MallocDebug __libc_malloc_default_dispatch __attribute__((aligned(32))) =
+{
+    dlmalloc, dlfree, dlcalloc, dlrealloc, dlmemalign
+};
+
+/* Selector of dispatch table to use for dispatching malloc calls. */
+const MallocDebug* __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
+
+void* malloc(size_t bytes) {
+    return __libc_malloc_dispatch->malloc(bytes);
+}
+void free(void* mem) {
+    __libc_malloc_dispatch->free(mem);
+}
+void* calloc(size_t n_elements, size_t elem_size) {
+    return __libc_malloc_dispatch->calloc(n_elements, elem_size);
+}
+void* realloc(void* oldMem, size_t bytes) {
+    return __libc_malloc_dispatch->realloc(oldMem, bytes);
+}
+void* memalign(size_t alignment, size_t bytes) {
+    return __libc_malloc_dispatch->memalign(alignment, bytes);
+}
+
+/* We implement malloc debugging only in libc.so, so code bellow
+ * must be excluded if we compile this file for static libc.a
+ */
+#ifndef LIBC_STATIC
+#include <sys/system_properties.h>
+#include <dlfcn.h>
+#include "logd.h"
+
+// =============================================================================
+// log functions
+// =============================================================================
+
+#define debug_log(format, ...)  \
+    __libc_android_log_print(ANDROID_LOG_DEBUG, "libc", (format), ##__VA_ARGS__ )
+#define error_log(format, ...)  \
+    __libc_android_log_print(ANDROID_LOG_ERROR, "libc", (format), ##__VA_ARGS__ )
+#define info_log(format, ...)  \
+    __libc_android_log_print(ANDROID_LOG_INFO, "libc", (format), ##__VA_ARGS__ )
+
+/* Table for dispatching malloc calls, depending on environment. */
+static MallocDebug gMallocUse __attribute__((aligned(32))) = {
+    dlmalloc, dlfree, dlcalloc, dlrealloc, dlmemalign
+};
+
+extern char*  __progname;
+
+/* Handle to shared library where actual memory allocation is implemented.
+ * This library is loaded and memory allocation calls are redirected there
+ * when libc.debug.malloc environment variable contains value other than
+ * zero:
+ * 1  - For memory leak detections.
+ * 5  - For filling allocated / freed memory with patterns defined by
+ *      CHK_SENTINEL_VALUE, and CHK_FILL_FREE macros.
+ * 10 - For adding pre-, and post- allocation stubs in order to detect
+ *      buffer overruns.
+ * 20 - For enabling emulator memory allocation instrumentation detecting
+ *      memory leaks and buffer overruns.
+ * Actual functionality for debug levels 1-10 is implemented in
+ * libc_malloc_debug_leak.so, while functionality for debug level 20 is
+ * implemented in libc_malloc_debug_qemu.so and can be run inside the
+ * emulator only.
+ */
+static void* libc_malloc_impl_handle = NULL;
+
+/* Initializes memory allocation framework once per process. */
+static void malloc_init_impl(void)
+{
+    const char* so_name = NULL;
+    unsigned int debug_level = 0;
+    unsigned int qemu_running = 0;
+    int len;
+    char env[PROP_VALUE_MAX];
+
+    // Get custom malloc debug level.
+    len = __system_property_get("libc.debug.malloc", env);
+    if (len) {
+        debug_level = atoi(env);
+    }
+
+    /* Debug level 0 means that we should use dlxxx allocation
+     * routines (default).
+     */
+    if (!debug_level) {
+        return;
+    }
+
+    // Get emulator running status.
+    len = __system_property_get("ro.kernel.qemu", env);
+    if (len) {
+        qemu_running = atoi(env);
+    }
+
+    // Lets see which .so must be loaded for the requested debug level
+    switch (debug_level) {
+        case 1:
+        case 5:
+        case 10:
+            so_name = "/system/lib/libc_malloc_debug_leak.so";
+            break;
+        case 20:
+            // Quick check: debug level 20 can only be handled in emulator
+            if (!qemu_running) {
+                info_log("%s: Debug level %d can only be set in emulator\n",
+                         __progname, debug_level);
+                return;
+            }
+            so_name = "/system/lib/libc_malloc_debug_qemu.so";
+            break;
+        default:
+            info_log("%s: Debug level %d is unknown\n",
+                     __progname, debug_level);
+            return;
+    }
+
+    // Load .so that implements the required malloc debugging functionality.
+    libc_malloc_impl_handle = dlopen(so_name, RTLD_LAZY);
+    if (libc_malloc_impl_handle == NULL) {
+        error_log("%s: Missing module %s required for malloc debug level %d\n",
+                 __progname, so_name, debug_level);
+        return;
+    }
+
+    // Initialize malloc dispatch table with appropriate routines.
+    switch (debug_level) {
+        case 1:
+            __libc_android_log_print(ANDROID_LOG_INFO, "libc",
+                    "%s using MALLOC_DEBUG = %d (leak checker)\n",
+                    __progname, debug_level);
+            gMallocUse.malloc =
+                dlsym(libc_malloc_impl_handle, "leak_malloc");
+            gMallocUse.free =
+                dlsym(libc_malloc_impl_handle, "leak_free");
+            gMallocUse.calloc =
+                dlsym(libc_malloc_impl_handle, "leak_calloc");
+            gMallocUse.realloc =
+                dlsym(libc_malloc_impl_handle, "leak_realloc");
+            gMallocUse.memalign =
+                dlsym(libc_malloc_impl_handle, "leak_memalign");
+            break;
+        case 5:
+            __libc_android_log_print(ANDROID_LOG_INFO, "libc",
+                    "%s using MALLOC_DEBUG = %d (fill)\n",
+                    __progname, debug_level);
+            gMallocUse.malloc =
+                dlsym(libc_malloc_impl_handle, "fill_malloc");
+            gMallocUse.free =
+                dlsym(libc_malloc_impl_handle, "fill_free");
+            gMallocUse.calloc = dlcalloc;
+            gMallocUse.realloc =
+                dlsym(libc_malloc_impl_handle, "fill_realloc");
+            gMallocUse.memalign =
+                dlsym(libc_malloc_impl_handle, "fill_memalign");
+            break;
+        case 10:
+            __libc_android_log_print(ANDROID_LOG_INFO, "libc",
+                    "%s using MALLOC_DEBUG = %d (sentinels, fill)\n",
+                    __progname, debug_level);
+            gMallocUse.malloc =
+                dlsym(libc_malloc_impl_handle, "chk_malloc");
+            gMallocUse.free =
+                dlsym(libc_malloc_impl_handle, "chk_free");
+            gMallocUse.calloc =
+                dlsym(libc_malloc_impl_handle, "chk_calloc");
+            gMallocUse.realloc =
+                dlsym(libc_malloc_impl_handle, "chk_realloc");
+            gMallocUse.memalign =
+                dlsym(libc_malloc_impl_handle, "chk_memalign");
+            break;
+        case 20:
+            __libc_android_log_print(ANDROID_LOG_INFO, "libc",
+                    "%s using MALLOC_DEBUG = %d (instrumented for emulator)\n",
+                    __progname, debug_level);
+            gMallocUse.malloc =
+                dlsym(libc_malloc_impl_handle, "qemu_instrumented_malloc");
+            gMallocUse.free =
+                dlsym(libc_malloc_impl_handle, "qemu_instrumented_free");
+            gMallocUse.calloc =
+                dlsym(libc_malloc_impl_handle, "qemu_instrumented_calloc");
+            gMallocUse.realloc =
+                dlsym(libc_malloc_impl_handle, "qemu_instrumented_realloc");
+            gMallocUse.memalign =
+                dlsym(libc_malloc_impl_handle, "qemu_instrumented_memalign");
+            break;
+        default:
+            break;
+    }
+
+    // Make sure dispatch table is initialized
+    if ((gMallocUse.malloc == NULL) ||
+        (gMallocUse.free == NULL) ||
+        (gMallocUse.calloc == NULL) ||
+        (gMallocUse.realloc == NULL) ||
+        (gMallocUse.memalign == NULL)) {
+        error_log("%s: Cannot initialize malloc dispatch table for debug level"
+                  " %d: %p, %p, %p, %p, %p\n",
+                  __progname, debug_level,
+                  gMallocUse.malloc, gMallocUse.free,
+                  gMallocUse.calloc, gMallocUse.realloc,
+                  gMallocUse.memalign);
+        dlclose(libc_malloc_impl_handle);
+        libc_malloc_impl_handle = NULL;
+    } else {
+        __libc_malloc_dispatch = &gMallocUse;
+    }
+}
+
+static pthread_once_t  malloc_init_once_ctl = PTHREAD_ONCE_INIT;
+
+#endif  // !LIBC_STATIC
+#endif  // USE_DL_PREFIX
+
+/* Initializes memory allocation framework.
+ * This routine is called from __libc_init routines implemented
+ * in libc_init_static.c and libc_init_dynamic.c files.
+ */
+void malloc_debug_init(void)
+{
+    /* We need to initialize malloc iff we impelement here custom
+     * malloc routines (i.e. USE_DL_PREFIX is defined) for libc.so
+     */
+#if defined(USE_DL_PREFIX) && !defined(LIBC_STATIC)
+    if (pthread_once(&malloc_init_once_ctl, malloc_init_impl)) {
+        error_log("Unable to initialize malloc_debug component.");
+    }
+#endif  // USE_DL_PREFIX && !LIBC_STATIC
+}
diff --git a/libc/bionic/malloc_debug_common.h b/libc/bionic/malloc_debug_common.h
new file mode 100644
index 0000000..a6301b3
--- /dev/null
+++ b/libc/bionic/malloc_debug_common.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+/*
+ * Contains declarations of types and constants used by malloc leak
+ * detection code in both, libc and libc_malloc_debug libraries.
+ */
+#ifndef MALLOC_DEBUG_COMMON_H
+#define MALLOC_DEBUG_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define HASHTABLE_SIZE      1543
+#define BACKTRACE_SIZE      32
+/* flag definitions, currently sharing storage with "size" */
+#define SIZE_FLAG_ZYGOTE_CHILD  (1<<31)
+#define SIZE_FLAG_MASK          (SIZE_FLAG_ZYGOTE_CHILD)
+
+#define MAX_SIZE_T           (~(size_t)0)
+
+// =============================================================================
+// Structures
+// =============================================================================
+
+typedef struct HashEntry HashEntry;
+struct HashEntry {
+    size_t slot;
+    HashEntry* prev;
+    HashEntry* next;
+    size_t numEntries;
+    // fields above "size" are NOT sent to the host
+    size_t size;
+    size_t allocations;
+    intptr_t backtrace[0];
+};
+
+typedef struct HashTable HashTable;
+struct HashTable {
+    size_t count;
+    HashEntry* slots[HASHTABLE_SIZE];
+};
+
+/* Entry in malloc dispatch table. */
+typedef struct MallocDebug MallocDebug;
+struct MallocDebug {
+    void* (*malloc)(size_t bytes);
+    void  (*free)(void* mem);
+    void* (*calloc)(size_t n_elements, size_t elem_size);
+    void* (*realloc)(void* oldMem, size_t bytes);
+    void* (*memalign)(size_t alignment, size_t bytes);
+};
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+#endif  // MALLOC_DEBUG_COMMON_H
diff --git a/libc/bionic/malloc_leak.c b/libc/bionic/malloc_debug_leak.c
similarity index 63%
rename from libc/bionic/malloc_leak.c
rename to libc/bionic/malloc_debug_leak.c
index 305f954..7b8822c 100644
--- a/libc/bionic/malloc_leak.c
+++ b/libc/bionic/malloc_debug_leak.c
@@ -38,6 +38,7 @@
 #include <stdarg.h>
 #include <fcntl.h>
 #include <unwind.h>
+#include <dlfcn.h>
 
 #include <sys/socket.h>
 #include <sys/un.h>
@@ -47,212 +48,37 @@
 
 #include "dlmalloc.h"
 #include "logd.h"
+#include "malloc_debug_common.h"
 
-// =============================================================================
-// Utilities directly used by Dalvik
-// =============================================================================
+// This file should be included into the build only when
+// MALLOC_LEAK_CHECK, or MALLOC_QEMU_INSTRUMENT, or both
+// macros are defined.
+#ifndef MALLOC_LEAK_CHECK
+#error MALLOC_LEAK_CHECK is not defined.
+#endif  // !MALLOC_LEAK_CHECK
 
-#define HASHTABLE_SIZE      1543
-#define BACKTRACE_SIZE      32
-/* flag definitions, currently sharing storage with "size" */
-#define SIZE_FLAG_ZYGOTE_CHILD  (1<<31)
-#define SIZE_FLAG_MASK          (SIZE_FLAG_ZYGOTE_CHILD)
-
-#define MAX_SIZE_T           (~(size_t)0)
-
-/*
- * In a VM process, this is set to 1 after fork()ing out of zygote.
- */
-int gMallocLeakZygoteChild = 0;
-
-// =============================================================================
-// Structures
-// =============================================================================
-
-typedef struct HashEntry HashEntry;
-struct HashEntry {
-    size_t slot;
-    HashEntry* prev;
-    HashEntry* next;
-    size_t numEntries;
-    // fields above "size" are NOT sent to the host
-    size_t size;
-    size_t allocations;
-    intptr_t backtrace[0];
-};
-
-typedef struct HashTable HashTable;
-struct HashTable {
-    size_t count;
-    HashEntry* slots[HASHTABLE_SIZE];
-};
-
-static pthread_mutex_t gAllocationsMutex = PTHREAD_MUTEX_INITIALIZER;
-static HashTable gHashTable;
+// Global variables defined in malloc_debug_common.c
+extern int gMallocLeakZygoteChild;
+extern pthread_mutex_t gAllocationsMutex;
+extern HashTable gHashTable;
+extern const MallocDebug __libc_malloc_default_dispatch;
+extern const MallocDebug* __libc_malloc_dispatch;
 
 // =============================================================================
 // log functions
 // =============================================================================
 
 #define debug_log(format, ...)  \
-    __libc_android_log_print(ANDROID_LOG_DEBUG, "malloc_leak", (format), ##__VA_ARGS__ )
+    __libc_android_log_print(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__ )
+#define info_log(format, ...)  \
+    __libc_android_log_print(ANDROID_LOG_INFO, "malloc_leak_check", (format), ##__VA_ARGS__ )
 
-// =============================================================================
-// output functions
-// =============================================================================
+static int gTrapOnError = 1;
 
-static int hash_entry_compare(const void* arg1, const void* arg2)
-{
-    HashEntry* e1 = *(HashEntry**)arg1;
-    HashEntry* e2 = *(HashEntry**)arg2;
-
-    size_t nbAlloc1 = e1->allocations;
-    size_t nbAlloc2 = e2->allocations;
-    size_t size1 = e1->size & ~SIZE_FLAG_MASK;
-    size_t size2 = e2->size & ~SIZE_FLAG_MASK;
-    size_t alloc1 = nbAlloc1 * size1;
-    size_t alloc2 = nbAlloc2 * size2;
-
-    // sort in descending order by:
-    // 1) total size
-    // 2) number of allocations
-    //
-    // This is used for sorting, not determination of equality, so we don't
-    // need to compare the bit flags.
-    int result;
-    if (alloc1 > alloc2) {
-        result = -1;
-    } else if (alloc1 < alloc2) {
-        result = 1;
-    } else {
-        if (nbAlloc1 > nbAlloc2) {
-            result = -1;
-        } else if (nbAlloc1 < nbAlloc2) {
-            result = 1;
-        } else {
-            result = 0;
-        }
-    }
-    return result;
-}
-
-/*
- * Retrieve native heap information.
- *
- * "*info" is set to a buffer we allocate
- * "*overallSize" is set to the size of the "info" buffer
- * "*infoSize" is set to the size of a single entry
- * "*totalMemory" is set to the sum of all allocations we're tracking; does
- *   not include heap overhead
- * "*backtraceSize" is set to the maximum number of entries in the back trace
- */
-void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
-        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize)
-{
-    // don't do anything if we have invalid arguments
-    if (info == NULL || overallSize == NULL || infoSize == NULL ||
-            totalMemory == NULL || backtraceSize == NULL) {
-        return;
-    }
-
-    pthread_mutex_lock(&gAllocationsMutex);
-
-    if (gHashTable.count == 0) {
-        *info = NULL;
-        *overallSize = 0;
-        *infoSize = 0;
-        *totalMemory = 0;
-        *backtraceSize = 0;
-        goto done;
-    }
-    
-    void** list = (void**)dlmalloc(sizeof(void*) * gHashTable.count);
-
-    // debug_log("*****\ngHashTable.count = %d\n", gHashTable.count);
-    // debug_log("list = %p\n", list);
-
-    // get the entries into an array to be sorted
-    int index = 0;
-    int i;
-    for (i = 0 ; i < HASHTABLE_SIZE ; i++) {
-        HashEntry* entry = gHashTable.slots[i];
-        while (entry != NULL) {
-            list[index] = entry;
-            *totalMemory = *totalMemory +
-                ((entry->size & ~SIZE_FLAG_MASK) * entry->allocations);
-            index++;
-            entry = entry->next;
-        }
-    }
-
-    // debug_log("sorted list!\n");
-    // XXX: the protocol doesn't allow variable size for the stack trace (yet)
-    *infoSize = (sizeof(size_t) * 2) + (sizeof(intptr_t) * BACKTRACE_SIZE);
-    *overallSize = *infoSize * gHashTable.count;
-    *backtraceSize = BACKTRACE_SIZE;
-
-    // debug_log("infoSize = 0x%x overall = 0x%x\n", *infoSize, *overallSize);
-    // now get A byte array big enough for this
-    *info = (uint8_t*)dlmalloc(*overallSize);
-
-    // debug_log("info = %p\n", info);
-    if (*info == NULL) {
-        *overallSize = 0;
-        goto done;
-    }
-
-    // debug_log("sorting list...\n");
-    qsort((void*)list, gHashTable.count, sizeof(void*), hash_entry_compare);
-
-    uint8_t* head = *info;
-    const int count = gHashTable.count;
-    for (i = 0 ; i < count ; i++) {
-        HashEntry* entry = list[i];
-        size_t entrySize = (sizeof(size_t) * 2) + (sizeof(intptr_t) * entry->numEntries);
-        if (entrySize < *infoSize) {
-            /* we're writing less than a full entry, clear out the rest */
-            /* TODO: only clear out the part we're not overwriting? */
-            memset(head, 0, *infoSize);
-        } else {
-            /* make sure the amount we're copying doesn't exceed the limit */
-            entrySize = *infoSize;
-        }
-        memcpy(head, &(entry->size), entrySize);
-        head += *infoSize;
-    }
-
-    dlfree(list);
-
-done:
-    // debug_log("+++++ done!\n");
-    pthread_mutex_unlock(&gAllocationsMutex);
-}
-
-void free_malloc_leak_info(uint8_t* info)
-{
-    dlfree(info);
-}
-
-struct mallinfo mallinfo()
-{
-    return dlmallinfo();
-}
-
-void* valloc(size_t bytes) {
-    /* assume page size of 4096 bytes */
-    return memalign( getpagesize(), bytes );
-}
-
-
-/*
- * Code guarded by MALLOC_LEAK_CHECK is only needed when malloc check is
- * enabled. Currently we exclude them in libc.so, and only include them in
- * libc_debug.so.
- */
-#ifdef MALLOC_LEAK_CHECK
 #define MALLOC_ALIGNMENT    8
 #define GUARD               0x48151642
-
 #define DEBUG               0
 
 // =============================================================================
@@ -407,13 +233,13 @@
     if (state->count) {
         intptr_t ip = (intptr_t)_Unwind_GetIP(context);
         if (ip) {
-            state->addrs[0] = 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.
      */
@@ -431,70 +257,6 @@
 }
 
 // =============================================================================
-// malloc leak function dispatcher
-// =============================================================================
-
-static void* leak_malloc(size_t bytes);
-static void  leak_free(void* mem);
-static void* leak_calloc(size_t n_elements, size_t elem_size);
-static void* leak_realloc(void* oldMem, size_t bytes);
-static void* leak_memalign(size_t alignment, size_t bytes);
-
-static void* fill_malloc(size_t bytes);
-static void  fill_free(void* mem);
-static void* fill_realloc(void* oldMem, size_t bytes);
-static void* fill_memalign(size_t alignment, size_t bytes);
-
-static void* chk_malloc(size_t bytes);
-static void  chk_free(void* mem);
-static void* chk_calloc(size_t n_elements, size_t elem_size);
-static void* chk_realloc(void* oldMem, size_t bytes);
-static void* chk_memalign(size_t alignment, size_t bytes);
-
-typedef struct {
-    void* (*malloc)(size_t bytes);
-    void  (*free)(void* mem);
-    void* (*calloc)(size_t n_elements, size_t elem_size);
-    void* (*realloc)(void* oldMem, size_t bytes);
-    void* (*memalign)(size_t alignment, size_t bytes);
-} MallocDebug;
-
-static const MallocDebug gMallocEngineTable[] __attribute__((aligned(32))) =
-{
-    { dlmalloc,     dlfree,     dlcalloc,       dlrealloc,     dlmemalign },
-    { leak_malloc,  leak_free,  leak_calloc,    leak_realloc,  leak_memalign },
-    { fill_malloc,  fill_free,  dlcalloc,       fill_realloc,  fill_memalign },
-    { chk_malloc,   chk_free,   chk_calloc,     chk_realloc,   chk_memalign }
-};
-
-enum {
-    INDEX_NORMAL = 0,
-    INDEX_LEAK_CHECK,
-    INDEX_MALLOC_FILL,
-    INDEX_MALLOC_CHECK,
-};
-
-static MallocDebug const * gMallocDispatch = &gMallocEngineTable[INDEX_NORMAL];
-static int gMallocDebugLevel;
-static int gTrapOnError = 1;
-
-void* malloc(size_t bytes) {
-    return gMallocDispatch->malloc(bytes);
-}
-void free(void* mem) {
-    gMallocDispatch->free(mem);
-}
-void* calloc(size_t n_elements, size_t elem_size) {
-    return gMallocDispatch->calloc(n_elements, elem_size);
-}
-void* realloc(void* oldMem, size_t bytes) {
-    return gMallocDispatch->realloc(oldMem, bytes);
-}
-void* memalign(size_t alignment, size_t bytes) {
-    return gMallocDispatch->memalign(alignment, bytes);
-}
-
-// =============================================================================
 // malloc check functions
 // =============================================================================
 
@@ -532,7 +294,9 @@
     va_list  args;
 
     pthread_mutex_lock(&gAllocationsMutex);
-        gMallocDispatch = &gMallocEngineTable[INDEX_NORMAL];
+    {
+        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);
@@ -541,7 +305,8 @@
         if (gTrapOnError) {
             __builtin_trap();
         }
-        gMallocDispatch = &gMallocEngineTable[INDEX_MALLOC_CHECK];
+        __libc_malloc_dispatch = current_dispatch;
+    }
     pthread_mutex_unlock(&gAllocationsMutex);
 }
 
@@ -574,7 +339,7 @@
     buf = (char*)mem - CHK_SENTINEL_HEAD_SIZE;
     for (i=0 ; i<CHK_SENTINEL_HEAD_SIZE ; i++) {
         if (buf[i] != CHK_SENTINEL_VALUE) {
-            assert_log_message( 
+            assert_log_message(
                 "*** %s CHECK: buffer %p "
                 "corrupted %d bytes before allocation",
                 func, mem, CHK_SENTINEL_HEAD_SIZE-i);
@@ -590,7 +355,7 @@
     buf = (char*)mem + bytes;
     for (i=CHK_SENTINEL_TAIL_SIZE-1 ; i>=0 ; i--) {
         if (buf[i] != CHK_SENTINEL_VALUE) {
-            assert_log_message( 
+            assert_log_message(
                 "*** %s CHECK: buffer %p, size=%lu, "
                 "corrupted %d bytes after allocation",
                 func, buffer, bytes, i+1);
@@ -743,11 +508,11 @@
 
             intptr_t backtrace[BACKTRACE_SIZE];
             size_t numEntries = get_backtrace(backtrace, BACKTRACE_SIZE);
-    
+
             AllocationEntry* header = (AllocationEntry*)base;
             header->entry = record_backtrace(backtrace, numEntries, bytes);
             header->guard = GUARD;
-    
+
             // now increment base to point to after our header.
             // this should just work since our header is 8 bytes.
             base = (AllocationEntry*)base + 1;
@@ -765,7 +530,7 @@
 
         // check the guard to make sure it is valid
         AllocationEntry* header = (AllocationEntry*)mem - 1;
-        
+
         if (header->guard != GUARD) {
             // could be a memaligned block
             if (((void**)mem)[-1] == MEMALIGN_GUARD) {
@@ -773,7 +538,7 @@
                 header = (AllocationEntry*)mem - 1;
             }
         }
-        
+
         if (header->guard == GUARD || is_valid_entry(header->entry)) {
             // decrement the allocations
             HashEntry* entry = header->entry;
@@ -842,7 +607,7 @@
     // need to make sure it's a power of two
     if (alignment & (alignment-1))
         alignment = 1L << (31 - __builtin_clz(alignment));
-    
+
     // here, aligment is at least MALLOC_ALIGNMENT<<1 bytes
     // we will align by at least MALLOC_ALIGNMENT bytes
     // and at most alignment-MALLOC_ALIGNMENT bytes
@@ -855,7 +620,7 @@
 
         // align the pointer
         ptr += ((-ptr) % alignment);
-        
+
         // there is always enough space for the base pointer and the guard
         ((void**)ptr)[-1] = MEMALIGN_GUARD;
         ((void**)ptr)[-2] = base;
@@ -864,60 +629,3 @@
     }
     return base;
 }
-#endif /* MALLOC_LEAK_CHECK */
-
-// called from libc_init()
-extern char*  __progname;
-
-void malloc_debug_init()
-{
-    unsigned int level = 0;
-#ifdef MALLOC_LEAK_CHECK
-    // if MALLOC_LEAK_CHECK is enabled, use level=1 by default
-    level = 1;
-#endif
-    char env[PROP_VALUE_MAX];
-    int len = __system_property_get("libc.debug.malloc", env);
-
-    if (len) {
-        level = atoi(env);
-#ifndef MALLOC_LEAK_CHECK
-        /* Alert the user that libc_debug.so needs to be installed as libc.so
-         * when performing malloc checks.
-         */
-        if (level != 0) {
-            __libc_android_log_print(ANDROID_LOG_INFO, "libc",
-                 "Malloc checks need libc_debug.so pushed to the device!\n");
-
-        }
-#endif
-    }
-
-#ifdef MALLOC_LEAK_CHECK
-    gMallocDebugLevel = level;
-    switch (level) {
-    default:
-    case 0:
-        gMallocDispatch = &gMallocEngineTable[INDEX_NORMAL];
-        break;
-    case 1:
-        __libc_android_log_print(ANDROID_LOG_INFO, "libc",
-                "%s using MALLOC_DEBUG = %d (leak checker)\n",
-                __progname, level);
-        gMallocDispatch = &gMallocEngineTable[INDEX_LEAK_CHECK];
-        break;
-    case 5:
-        __libc_android_log_print(ANDROID_LOG_INFO, "libc",
-                "%s using MALLOC_DEBUG = %d (fill)\n", 
-                __progname, level);
-        gMallocDispatch = &gMallocEngineTable[INDEX_MALLOC_FILL];
-        break;
-    case 10:
-        __libc_android_log_print(ANDROID_LOG_INFO, "libc",
-                "%s using MALLOC_DEBUG = %d (sentinels, fill)\n", 
-                __progname, level);
-        gMallocDispatch = &gMallocEngineTable[INDEX_MALLOC_CHECK];
-        break;
-    }
-#endif
-}
diff --git a/libc/bionic/malloc_debug_qemu.c b/libc/bionic/malloc_debug_qemu.c
new file mode 100644
index 0000000..b63ddb4
--- /dev/null
+++ b/libc/bionic/malloc_debug_qemu.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+/*
+ * Contains implementation of memeory allocation routines instrumented for
+ * usage in the emulator to detect memory allocation violations, such as
+ * memory leaks, buffer overruns, etc.
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "dlmalloc.h"
+#include "logd.h"
+
+// This file should be included into the build only when
+// MALLOC_QEMU_INSTRUMENT macro is defined.
+#ifndef MALLOC_QEMU_INSTRUMENT
+#error MALLOC_QEMU_INSTRUMENT is not defined.
+#endif  // MALLOC_QEMU_INSTRUMENT
+
+// =============================================================================
+// log functions
+// =============================================================================
+
+#define debug_log(format, ...)  \
+    __libc_android_log_print(ANDROID_LOG_DEBUG, "malloc_qemu", (format), ##__VA_ARGS__ )
+#define error_log(format, ...)  \
+    __libc_android_log_print(ANDROID_LOG_ERROR, "malloc_qemu", (format), ##__VA_ARGS__ )
+#define info_log(format, ...)  \
+    __libc_android_log_print(ANDROID_LOG_INFO, "malloc_qemu", (format), ##__VA_ARGS__ )
+
+void* qemu_instrumented_malloc(size_t bytes)
+{
+    return dlmalloc(bytes);
+}
+
+void  qemu_instrumented_free(void* mem)
+{
+    dlfree(mem);
+}
+
+void* qemu_instrumented_calloc(size_t n_elements, size_t elem_size)
+{
+    return dlcalloc(n_elements, elem_size);
+}
+
+void* qemu_instrumented_realloc(void* mem, size_t bytes)
+{
+    return dlrealloc(mem, bytes);
+}
+
+void* qemu_instrumented_memalign(size_t alignment, size_t bytes)
+{
+    return dlmemalign(alignment, bytes);
+}