summaryrefslogtreecommitdiffstats
path: root/libc
diff options
context:
space:
mode:
authorVladimir Chtchetkine <vchtchetkine@google.com>2009-11-19 11:28:22 -0800
committerAndroid Git Automerger <android-git-automerger@android.com>2009-11-19 11:28:22 -0800
commitfdfa16776ca8f33f671cbac5dd9fa8bd761e16a8 (patch)
tree3a740d8b093b0e05eba02871aa9a7290a37067dd /libc
parentebf3ea006e5367fff93d2491eec24c4b1a633805 (diff)
parent362b2aabee2dd04e04a3ad9c09f0ad0212569be4 (diff)
downloadbionic-fdfa16776ca8f33f671cbac5dd9fa8bd761e16a8.zip
bionic-fdfa16776ca8f33f671cbac5dd9fa8bd761e16a8.tar.gz
bionic-fdfa16776ca8f33f671cbac5dd9fa8bd761e16a8.tar.bz2
am 362b2aab: Merge change Ib4550a04 into eclair-mr2
Merge commit '362b2aabee2dd04e04a3ad9c09f0ad0212569be4' into eclair-mr2-plus-aosp * commit '362b2aabee2dd04e04a3ad9c09f0ad0212569be4': Split libc_debug.so into two .so modules loaded on demand from libc.so
Diffstat (limited to 'libc')
-rw-r--r--libc/Android.mk70
-rw-r--r--libc/bionic/dlmalloc.c16
-rw-r--r--libc/bionic/dlmalloc.h8
-rw-r--r--libc/bionic/libc_init_dynamic.c9
-rw-r--r--libc/bionic/libc_init_static.c6
-rw-r--r--libc/bionic/malloc_debug_common.c432
-rw-r--r--libc/bionic/malloc_debug_common.h84
-rw-r--r--libc/bionic/malloc_debug_leak.c (renamed from libc/bionic/malloc_leak.c)362
-rw-r--r--libc/bionic/malloc_debug_qemu.c81
9 files changed, 693 insertions, 375 deletions
diff --git a/libc/Android.mk b/libc/Android.mk
index bafc118..7f50390 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -521,17 +521,12 @@ include $(CLEAR_VARS)
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 :=
@@ -550,7 +545,7 @@ LOCAL_C_INCLUDES := $(libc_common_c_includes)
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
@@ -570,8 +565,16 @@ LOCAL_SYSTEM_SHARED_LIBRARIES :=
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)
@@ -582,30 +585,49 @@ LOCAL_CFLAGS := \
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 := 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
-LOCAL_SHARED_LIBRARIES := libdl
+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
+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 @@ MALLINFO_FIELD_TYPE default: size_t
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 @@ extern "C" {
/* ------------------- 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 @@ static void* sys_alloc(mstate m, size_t nb) {
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 @@ static int sys_trim(mstate m, size_t pad) {
}
/* 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 @@ static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
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 @@ History:
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 @@ extern "C" {
#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 @@ void __libc_prenit(void)
__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 @@ __noreturn void __libc_init(uintptr_t *elfdata,
/* 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
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
-// =============================================================================
-
-#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];
-};
+// 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
-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__ )
-
-// =============================================================================
-// 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);
-
- // 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 );
-}
+ __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__ )
+static int gTrapOnError = 1;
-/*
- * 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 @@ static _Unwind_Reason_Code trace_function(__unwind_context *context, void *arg)
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 @@ int get_backtrace(intptr_t* addrs, size_t max_entries)
}
// =============================================================================
-// 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 @@ static void assert_log_message(const char* format, ...)
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 @@ static void assert_log_message(const char* format, ...)
if (gTrapOnError) {
__builtin_trap();
}
- gMallocDispatch = &gMallocEngineTable[INDEX_MALLOC_CHECK];
+ __libc_malloc_dispatch = current_dispatch;
+ }
pthread_mutex_unlock(&gAllocationsMutex);
}
@@ -574,7 +339,7 @@ static int chk_mem_check(void* mem,
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 @@ static int chk_mem_check(void* mem,
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 @@ void* leak_malloc(size_t bytes)
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 @@ void leak_free(void* mem)
// 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 @@ void leak_free(void* mem)
header = (AllocationEntry*)mem - 1;
}
}
-
+
if (header->guard == GUARD || is_valid_entry(header->entry)) {
// decrement the allocations
HashEntry* entry = header->entry;
@@ -842,7 +607,7 @@ void* leak_memalign(size_t alignment, size_t bytes)
// 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 @@ void* leak_memalign(size_t alignment, size_t bytes)
// 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 @@ void* leak_memalign(size_t alignment, size_t bytes)
}
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);
+}