resolved conflicts for merge of e1dd3c28 to jb-dev-plus-aosp

Change-Id: I58b9c13d20771aa39b703ec05cbff8aeaad38fe8
diff --git a/libc/Android.mk b/libc/Android.mk
index 6c535dc..f55f9fe 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -731,7 +731,10 @@
 LOCAL_C_INCLUDES := $(libc_common_c_includes)
 
 LOCAL_SRC_FILES := \
-	bionic/malloc_debug_leak.c
+	bionic/malloc_debug_leak.c \
+	bionic/malloc_debug_check.c \
+	bionic/malloc_debug_check_mapinfo.c \
+	bionic/malloc_debug_stacktrace.c
 
 LOCAL_MODULE:= libc_malloc_debug_leak
 
diff --git a/libc/bionic/libc_init_common.c b/libc/bionic/libc_init_common.c
index 7fb1246..4ce4db6 100644
--- a/libc/bionic/libc_init_common.c
+++ b/libc/bionic/libc_init_common.c
@@ -138,4 +138,12 @@
 
         func();
     }
+
+#ifndef LIBC_STATIC
+    {
+        extern void __libc_postfini(void) __attribute__((weak));
+        if (__libc_postfini)
+            __libc_postfini();
+    }
+#endif
 }
diff --git a/libc/bionic/libc_init_dynamic.c b/libc/bionic/libc_init_dynamic.c
index 1c8480c..3a7e8e2 100644
--- a/libc/bionic/libc_init_dynamic.c
+++ b/libc/bionic/libc_init_dynamic.c
@@ -89,6 +89,12 @@
     malloc_debug_init();
 }
 
+void __libc_postfini(void)
+{
+    extern void malloc_debug_fini(void);
+    malloc_debug_fini();
+}
+
 /* This function is called from the executable's _start entry point
  * (see arch-$ARCH/bionic/crtbegin_dynamic.S), which is itself
  * called by the dynamic linker after it has loaded all shared
diff --git a/libc/bionic/malloc_debug_check.c b/libc/bionic/malloc_debug_check.c
new file mode 100644
index 0000000..4ae21fe
--- /dev/null
+++ b/libc/bionic/malloc_debug_check.c
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unwind.h>
+#include <dlfcn.h>
+#include <stdbool.h>
+
+#include <sys/types.h>
+#include <sys/system_properties.h>
+
+#include "dlmalloc.h"
+#include "logd.h"
+
+#include "malloc_debug_common.h"
+#include "malloc_debug_check_mapinfo.h"
+
+static mapinfo *milist;
+
+/* libc.debug.malloc.backlog */
+extern unsigned int malloc_double_free_backlog;
+
+#define MAX_BACKTRACE_DEPTH 15
+#define ALLOCATION_TAG      0x1ee7d00d
+#define BACKLOG_TAG         0xbabecafe
+#define FREE_POISON         0xa5
+#define BACKLOG_DEFAULT_LEN 100
+#define FRONT_GUARD         0xaa
+#define FRONT_GUARD_LEN     (1<<5)
+#define REAR_GUARD          0xbb
+#define REAR_GUARD_LEN      (1<<5)
+
+static void print_backtrace(const intptr_t *bt, unsigned int depth);
+
+static void log_message(const char* format, ...)
+{
+    extern pthread_mutex_t gAllocationsMutex;
+    extern const MallocDebug __libc_malloc_default_dispatch;
+    extern const MallocDebug* __libc_malloc_dispatch;
+
+    va_list  args;
+
+    pthread_mutex_lock(&gAllocationsMutex);
+    {
+        const MallocDebug* current_dispatch = __libc_malloc_dispatch;
+        __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
+        va_start(args, format);
+        __libc_android_log_vprint(ANDROID_LOG_ERROR, "libc",
+                                format, args);
+        va_end(args);
+        __libc_malloc_dispatch = current_dispatch;
+    }
+    pthread_mutex_unlock(&gAllocationsMutex);
+}
+
+struct hdr {
+    uint32_t tag;
+    struct hdr *prev;
+    struct hdr *next;
+    intptr_t bt[MAX_BACKTRACE_DEPTH];
+    int bt_depth;
+    intptr_t freed_bt[MAX_BACKTRACE_DEPTH];
+    int freed_bt_depth;
+    size_t size;
+    char front_guard[FRONT_GUARD_LEN];
+} __attribute__((packed));
+
+struct ftr {
+    char rear_guard[REAR_GUARD_LEN];
+} __attribute__((packed));
+
+static inline struct ftr * to_ftr(struct hdr *hdr)
+{
+    return (struct ftr *)(((char *)(hdr + 1)) + hdr->size);
+}
+
+static inline void *user(struct hdr *hdr)
+{
+    return hdr + 1;
+}
+
+static inline struct hdr *meta(void *user)
+{
+    return ((struct hdr *)user) - 1;
+}
+
+/* Call this on exit() to get leaked memory */
+void free_leaked_memory(void);
+
+static unsigned num;
+static struct hdr *tail;
+static struct hdr *head;
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+static unsigned backlog_num;
+static struct hdr *backlog_tail;
+static struct hdr *backlog_head;
+static pthread_mutex_t backlog_lock = PTHREAD_MUTEX_INITIALIZER;
+
+extern __LIBC_HIDDEN__
+int get_backtrace(intptr_t* addrs, size_t max_entries);
+
+static void print_backtrace(const intptr_t *bt, unsigned int depth)
+{
+    const mapinfo *mi;
+    unsigned int cnt;
+    unsigned int rel_pc;
+    intptr_t self_bt[MAX_BACKTRACE_DEPTH];
+
+    if (!bt) {
+        depth = get_backtrace(self_bt, MAX_BACKTRACE_DEPTH);
+        bt = self_bt;
+    }
+
+    log_message("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
+    for (cnt = 0; cnt < depth && cnt < MAX_BACKTRACE_DEPTH; cnt++) {
+        mi = pc_to_mapinfo(milist, bt[cnt], &rel_pc);
+        log_message("\t#%02d  pc %08x  %s\n", cnt,
+                   mi ? (intptr_t)rel_pc : bt[cnt],
+                   mi ? mi->name : "(unknown)");
+    }
+}
+
+static inline void init_front_guard(struct hdr *hdr)
+{
+    memset(hdr->front_guard, FRONT_GUARD, FRONT_GUARD_LEN);
+}
+
+static inline bool is_front_guard_valid(struct hdr *hdr)
+{
+    unsigned i;
+    for (i = 0; i < FRONT_GUARD_LEN; i++)
+        if (hdr->front_guard[i] != FRONT_GUARD)
+            return 0;
+    return 1;
+}
+
+static inline void init_rear_guard(struct hdr *hdr)
+{
+    struct ftr *ftr = to_ftr(hdr);
+    memset(ftr->rear_guard, REAR_GUARD, REAR_GUARD_LEN);
+}
+
+static inline bool is_rear_guard_valid(struct hdr *hdr)
+{
+    unsigned i;
+    int valid = 1;
+    int first_mismatch = -1;
+    struct ftr *ftr = to_ftr(hdr);
+    for (i = 0; i < REAR_GUARD_LEN; i++) {
+        if (ftr->rear_guard[i] != REAR_GUARD) {
+            if (first_mismatch < 0)
+                first_mismatch = i;
+            valid = 0;
+        }
+        else if (first_mismatch >= 0) {
+            log_message("+++ REAR GUARD MISMATCH [%d, %d)\n", first_mismatch, i);
+            first_mismatch = -1;
+        }
+    }
+
+    if (first_mismatch >= 0)
+        log_message("+++ REAR GUARD MISMATCH [%d, %d)\n", first_mismatch, i);
+    return valid;
+}
+
+static inline void add_locked(struct hdr *hdr, struct hdr **tail, struct hdr **head)
+{
+    hdr->prev = NULL;
+    hdr->next = *head;
+    if (*head)
+        (*head)->prev = hdr;
+    else
+        *tail = hdr;
+    *head = hdr;
+}
+
+static inline int del_locked(struct hdr *hdr, struct hdr **tail, struct hdr **head)
+{
+    if (hdr->prev)
+        hdr->prev->next = hdr->next;
+    else
+        *head = hdr->next;
+    if (hdr->next)
+        hdr->next->prev = hdr->prev;
+    else
+        *tail = hdr->prev;
+    return 0;
+}
+
+static inline void add(struct hdr *hdr, size_t size)
+{
+    pthread_mutex_lock(&lock);
+    hdr->tag = ALLOCATION_TAG;
+    hdr->size = size;
+    init_front_guard(hdr);
+    init_rear_guard(hdr);
+    num++;
+    add_locked(hdr, &tail, &head);
+    pthread_mutex_unlock(&lock);
+}
+
+static inline int del(struct hdr *hdr)
+{
+    if (hdr->tag != ALLOCATION_TAG)
+        return -1;
+
+    pthread_mutex_lock(&lock);
+    del_locked(hdr, &tail, &head);
+    num--;
+    pthread_mutex_unlock(&lock);
+    return 0;
+}
+
+static inline void poison(struct hdr *hdr)
+{
+    memset(user(hdr), FREE_POISON, hdr->size);
+}
+
+static int was_used_after_free(struct hdr *hdr)
+{
+    unsigned i;
+    const char *data = (const char *)user(hdr);
+    for (i = 0; i < hdr->size; i++)
+        if (data[i] != FREE_POISON)
+            return 1;
+    return 0;
+}
+
+/* returns 1 if valid, *safe == 1 if safe to dump stack */
+static inline int check_guards(struct hdr *hdr, int *safe)
+{
+    *safe = 1;
+    if (!is_front_guard_valid(hdr)) {
+        if (hdr->front_guard[0] == FRONT_GUARD) {
+            log_message("+++ ALLOCATION %p SIZE %d HAS A CORRUPTED FRONT GUARD\n",
+                       user(hdr), hdr->size);
+        } else {
+            log_message("+++ ALLOCATION %p HAS A CORRUPTED FRONT GUARD "\
+                      "(NOT DUMPING STACKTRACE)\n", user(hdr));
+            /* Allocation header is probably corrupt, do not print stack trace */
+            *safe = 0;
+        }
+        return 0;
+    }
+
+    if (!is_rear_guard_valid(hdr)) {
+        log_message("+++ ALLOCATION %p SIZE %d HAS A CORRUPTED REAR GUARD\n",
+                   user(hdr), hdr->size);
+        return 0;
+    }
+
+    return 1;
+}
+
+/* returns 1 if valid, *safe == 1 if safe to dump stack */
+static inline int check_allocation_locked(struct hdr *hdr, int *safe)
+{
+    int valid = 1;
+    *safe = 1;
+
+    if (hdr->tag != ALLOCATION_TAG && hdr->tag != BACKLOG_TAG) {
+        log_message("+++ ALLOCATION %p HAS INVALID TAG %08x (NOT DUMPING STACKTRACE)\n",
+                   user(hdr), hdr->tag);
+	/* Allocation header is probably corrupt, do not dequeue or dump stack
+         * trace.
+         */
+        *safe = 0;
+        return 0;
+    }
+
+    if (hdr->tag == BACKLOG_TAG && was_used_after_free(hdr)) {
+        log_message("+++ ALLOCATION %p SIZE %d WAS USED AFTER BEING FREED\n",
+                   user(hdr), hdr->size);
+        valid = 0;
+	/* check the guards to see if it's safe to dump a stack trace */
+        (void)check_guards(hdr, safe);
+    }
+    else
+        valid = check_guards(hdr, safe);
+
+    if (!valid && *safe) {
+        log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
+                        user(hdr), hdr->size);
+        print_backtrace(hdr->bt, hdr->bt_depth);
+        if (hdr->tag == BACKLOG_TAG) {
+            log_message("+++ ALLOCATION %p SIZE %d FREED HERE:\n",
+                       user(hdr), hdr->size);
+            print_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
+        }
+    }
+
+    return valid;
+}
+
+static inline int del_and_check_locked(struct hdr *hdr,
+                                   struct hdr **tail, struct hdr **head, unsigned *cnt,
+                                   int *safe)
+{
+    int valid;
+    valid = check_allocation_locked(hdr, safe);
+    if (safe) {
+        (*cnt)--;
+        del_locked(hdr, tail, head);
+    }
+    return valid;
+}
+
+static inline void del_from_backlog_locked(struct hdr *hdr)
+{
+        int safe;
+        (void)del_and_check_locked(hdr,
+                              &backlog_tail, &backlog_head, &backlog_num,
+                              &safe);
+        hdr->tag = 0; /* clear the tag */
+}
+
+static inline void del_from_backlog(struct hdr *hdr)
+{
+    pthread_mutex_lock(&backlog_lock);
+    del_from_backlog_locked(hdr);
+    pthread_mutex_unlock(&backlog_lock);
+}
+
+static inline int del_leak(struct hdr *hdr, int *safe)
+{
+    int valid;
+    pthread_mutex_lock(&lock);
+    valid = del_and_check_locked(hdr,
+                            &tail, &head, &num,
+                            safe);
+    pthread_mutex_unlock(&lock);
+    return valid;
+}
+
+static inline void add_to_backlog(struct hdr *hdr)
+{
+    pthread_mutex_lock(&backlog_lock);
+    hdr->tag = BACKLOG_TAG;
+    backlog_num++;
+    add_locked(hdr, &backlog_tail, &backlog_head);
+    poison(hdr);
+    /* If we've exceeded the maximum backlog, clear it up */
+    while (backlog_num > malloc_double_free_backlog) {
+        struct hdr *gone = backlog_tail;
+        del_from_backlog_locked(gone);
+        dlfree(gone);
+    }
+    pthread_mutex_unlock(&backlog_lock);
+}
+
+void* chk_malloc(size_t size)
+{
+    struct hdr *hdr;
+
+//  log_message("%s: %s\n", __FILE__, __FUNCTION__);
+
+    hdr = dlmalloc(sizeof(struct hdr) + size + sizeof(struct ftr));
+    if (hdr) {
+        hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
+        add(hdr, size);
+        return user(hdr);
+    }
+    return NULL;
+}
+
+void* chk_memalign(size_t alignment, size_t bytes)
+{
+//  log_message("%s: %s\n", __FILE__, __FUNCTION__);
+    // XXX: it's better to use malloc, than being wrong
+    return chk_malloc(bytes);
+}
+
+void chk_free(void *ptr)
+{
+    struct hdr *hdr;
+
+//  log_message("%s: %s\n", __FILE__, __FUNCTION__);
+
+    if (!ptr) /* ignore free(NULL) */
+        return;
+
+    hdr = meta(ptr);
+
+    if (del(hdr) < 0) {
+        intptr_t bt[MAX_BACKTRACE_DEPTH];
+        int depth;
+        depth = get_backtrace(bt, MAX_BACKTRACE_DEPTH);
+        if (hdr->tag == BACKLOG_TAG) {
+            log_message("+++ ALLOCATION %p SIZE %d BYTES MULTIPLY FREED!\n",
+                       user(hdr), hdr->size);
+            log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
+                       user(hdr), hdr->size);
+            print_backtrace(hdr->bt, hdr->bt_depth);
+            /* hdr->freed_bt_depth should be nonzero here */
+            log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n",
+                       user(hdr), hdr->size);
+            print_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
+            log_message("+++ ALLOCATION %p SIZE %d NOW BEING FREED HERE:\n",
+                       user(hdr), hdr->size);
+            print_backtrace(bt, depth);
+        }
+        else {
+            log_message("+++ ALLOCATION %p IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
+                       user(hdr));
+            print_backtrace(bt, depth);
+            /* Leak here so that we do not crash */
+            //dlfree(user(hdr));
+        }
+    }
+    else {
+        hdr->freed_bt_depth = get_backtrace(hdr->freed_bt,
+                                      MAX_BACKTRACE_DEPTH);
+        add_to_backlog(hdr);
+    }
+}
+
+void *chk_realloc(void *ptr, size_t size)
+{
+    struct hdr *hdr;
+
+//  log_message("%s: %s\n", __FILE__, __FUNCTION__);
+
+    if (!size) {
+        chk_free(ptr);
+        return NULL;
+    }
+
+    if (!ptr)
+        return chk_malloc(size);
+
+    hdr = meta(ptr);
+
+    if (del(hdr) < 0) {
+        intptr_t bt[MAX_BACKTRACE_DEPTH];
+        int depth;
+        depth = get_backtrace(bt, MAX_BACKTRACE_DEPTH);
+        if (hdr->tag == BACKLOG_TAG) {
+            log_message("+++ REALLOCATION %p SIZE %d OF FREED MEMORY!\n",
+                       user(hdr), size, hdr->size);
+            log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
+                       user(hdr), hdr->size);
+            print_backtrace(hdr->bt, hdr->bt_depth);
+            /* hdr->freed_bt_depth should be nonzero here */
+            log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n",
+                       user(hdr), hdr->size);
+            print_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
+            log_message("+++ ALLOCATION %p SIZE %d NOW BEING REALLOCATED HERE:\n",
+                       user(hdr), hdr->size);
+            print_backtrace(bt, depth);
+
+             /* We take the memory out of the backlog and fall through so the
+             * reallocation below succeeds.  Since we didn't really free it, we
+             * can default to this behavior.
+             */
+            del_from_backlog(hdr);
+        }
+        else {
+            log_message("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
+                       user(hdr), size);
+            print_backtrace(bt, depth);
+            // just get a whole new allocation and leak the old one
+            return dlrealloc(0, size);
+            // return dlrealloc(user(hdr), size); // assuming it was allocated externally
+        }
+    }
+
+    hdr = dlrealloc(hdr, sizeof(struct hdr) + size + sizeof(struct ftr));
+    if (hdr) {
+        hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
+        add(hdr, size);
+        return user(hdr);
+    }
+
+    return NULL;
+}
+
+void *chk_calloc(int nmemb, size_t size)
+{
+//  log_message("%s: %s\n", __FILE__, __FUNCTION__);
+    struct hdr *hdr;
+    size_t total_size = nmemb * size;
+    hdr = dlcalloc(1, sizeof(struct hdr) + total_size + sizeof(struct ftr));
+    if (hdr) {
+        hdr->bt_depth = get_backtrace(
+                            hdr->bt, MAX_BACKTRACE_DEPTH);
+        add(hdr, total_size);
+        return user(hdr);
+    }
+    return NULL;
+}
+
+static void heaptracker_free_leaked_memory(void)
+{
+    struct hdr *del; int cnt;
+
+    if (num)
+        log_message("+++ THERE ARE %d LEAKED ALLOCATIONS\n", num);
+
+    while (head) {
+        int safe;
+        del = head;
+        log_message("+++ DELETING %d BYTES OF LEAKED MEMORY AT %p (%d REMAINING)\n",
+                del->size, user(del), num);
+        if (del_leak(del, &safe)) {
+            /* safe == 1, because the allocation is valid */
+            log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
+                        user(del), del->size);
+            print_backtrace(del->bt, del->bt_depth);
+        }
+        dlfree(del);
+    }
+
+//  log_message("+++ DELETING %d BACKLOGGED ALLOCATIONS\n", backlog_num);
+    while (backlog_head) {
+	del = backlog_tail;
+        del_from_backlog(del);
+        dlfree(del);
+    }
+}
+
+/* Initializes malloc debugging framework.
+ * See comments on MallocDebugInit in malloc_debug_common.h
+ */
+int malloc_debug_initialize(void)
+{
+    if (!malloc_double_free_backlog)
+        malloc_double_free_backlog = BACKLOG_DEFAULT_LEN;
+    milist = init_mapinfo(getpid());
+    return 0;
+}
+
+void malloc_debug_finalize(void)
+{
+    heaptracker_free_leaked_memory();
+    deinit_mapinfo(milist);
+}
diff --git a/libc/bionic/malloc_debug_check_mapinfo.c b/libc/bionic/malloc_debug_check_mapinfo.c
new file mode 100644
index 0000000..044fc65
--- /dev/null
+++ b/libc/bionic/malloc_debug_check_mapinfo.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "dlmalloc.h"
+#include "malloc_debug_check_mapinfo.h"
+
+// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so
+// 012345678901234567890123456789012345678901234567890123456789
+// 0         1         2         3         4         5
+
+static mapinfo *parse_maps_line(char *line)
+{
+    mapinfo *mi;
+    int len = strlen(line);
+
+    if(len < 1) return 0;
+    line[--len] = 0;
+
+    if(len < 50) return 0;
+    if(line[20] != 'x') return 0;
+
+    mi = dlmalloc(sizeof(mapinfo) + (len - 47));
+    if(mi == 0) return 0;
+
+    mi->start = strtoul(line, 0, 16);
+    mi->end = strtoul(line + 9, 0, 16);
+    /* To be filled in parse_elf_info if the mapped section starts with
+     * elf_header
+     */
+    mi->next = 0;
+    strcpy(mi->name, line + 49);
+
+    return mi;
+}
+
+__LIBC_HIDDEN__
+mapinfo *init_mapinfo(int pid)
+{
+    struct mapinfo *milist = NULL;
+    char data[1024];
+    sprintf(data, "/proc/%d/maps", pid);
+    FILE *fp = fopen(data, "r");
+    if(fp) {
+        while(fgets(data, sizeof(data), fp)) {
+            mapinfo *mi = parse_maps_line(data);
+            if(mi) {
+                mi->next = milist;
+                milist = mi;
+            }
+        }
+        fclose(fp);
+    }
+
+    return milist;
+}
+
+__LIBC_HIDDEN__
+void deinit_mapinfo(mapinfo *mi)
+{
+   mapinfo *del;
+   while(mi) {
+       del = mi;
+       mi = mi->next;
+       dlfree(del);
+   }
+}
+
+/* Map a pc address to the name of the containing ELF file */
+__LIBC_HIDDEN__
+const char *map_to_name(mapinfo *mi, unsigned pc, const char* def)
+{
+    while(mi) {
+        if((pc >= mi->start) && (pc < mi->end)){
+            return mi->name;
+        }
+        mi = mi->next;
+    }
+    return def;
+}
+
+/* Find the containing map info for the pc */
+__LIBC_HIDDEN__
+const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc)
+{
+    *rel_pc = pc;
+    while(mi) {
+        if((pc >= mi->start) && (pc < mi->end)){
+            // Only calculate the relative offset for shared libraries
+            if (strstr(mi->name, ".so")) {
+                *rel_pc -= mi->start;
+            }
+            return mi;
+        }
+        mi = mi->next;
+    }
+    return NULL;
+}
diff --git a/libc/bionic/malloc_debug_check_mapinfo.h b/libc/bionic/malloc_debug_check_mapinfo.h
new file mode 100644
index 0000000..8a01cd3
--- /dev/null
+++ b/libc/bionic/malloc_debug_check_mapinfo.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef MALLOC_DEBUG_CHECK_MAPINFO_H
+#define MALLOC_DEBUG_CHECK_MAPINFO_H
+
+#include <sys/cdefs.h>
+
+typedef struct mapinfo {
+    struct mapinfo *next;
+    unsigned start;
+    unsigned end;
+    char name[];
+} mapinfo;
+
+__LIBC_HIDDEN__ mapinfo *init_mapinfo(int pid);
+__LIBC_HIDDEN__ void deinit_mapinfo(mapinfo *mi);
+__LIBC_HIDDEN__ const char *map_to_name(mapinfo *mi, unsigned pc, const char* def);
+__LIBC_HIDDEN__ const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc);
+
+#endif/*MALLOC_DEBUG_CHECK_MAPINFO_H*/
diff --git a/libc/bionic/malloc_debug_common.c b/libc/bionic/malloc_debug_common.c
index 6837e39..4105ab8 100644
--- a/libc/bionic/malloc_debug_common.c
+++ b/libc/bionic/malloc_debug_common.c
@@ -240,17 +240,6 @@
 #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
@@ -288,6 +277,14 @@
 #define MALLOC_ALIGNMENT ((size_t)8U)
 #endif  /* MALLOC_ALIGNMENT */
 
+/* This variable is set to the value of property libc.debug.malloc.backlog,
+ * when the value of libc.debug.malloc = 10.  It determines the size of the
+ * backlog we use to detect multiple frees.  If the property is not set, the
+ * backlog length defaults to an internal constant defined in
+ * malloc_debug_check.c
+ */
+unsigned int malloc_double_free_backlog;
+
 /* Initializes memory allocation framework once per process. */
 static void malloc_init_impl(void)
 {
@@ -339,9 +336,17 @@
     switch (debug_level) {
         case 1:
         case 5:
-        case 10:
+        case 10: {
+            char debug_backlog[PROP_VALUE_MAX];
+            if (__system_property_get("libc.debug.malloc.backlog", debug_backlog)) {
+                malloc_double_free_backlog = atoi(debug_backlog);
+                info_log("%s: setting backlog length to %d\n",
+                         __progname, malloc_double_free_backlog);
+            }
+
             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) {
@@ -485,7 +490,19 @@
     }
 }
 
+static void malloc_fini_impl(void)
+{
+    if (libc_malloc_impl_handle) {
+        MallocDebugFini malloc_debug_finalize = NULL;
+        malloc_debug_finalize =
+                dlsym(libc_malloc_impl_handle, "malloc_debug_finalize");
+        if (malloc_debug_finalize)
+            malloc_debug_finalize();
+    }
+}
+
 static pthread_once_t  malloc_init_once_ctl = PTHREAD_ONCE_INIT;
+static pthread_once_t  malloc_fini_once_ctl = PTHREAD_ONCE_INIT;
 
 #endif  // !LIBC_STATIC
 #endif  // USE_DL_PREFIX
@@ -504,3 +521,14 @@
     }
 #endif  // USE_DL_PREFIX && !LIBC_STATIC
 }
+
+void malloc_debug_fini(void)
+{
+    /* We need to finalize malloc iff we implement 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_fini_once_ctl, malloc_fini_impl)) {
+        error_log("Unable to finalize 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
index 87600d6..c78846b 100644
--- a/libc/bionic/malloc_debug_common.h
+++ b/libc/bionic/malloc_debug_common.h
@@ -82,15 +82,31 @@
     void* (*memalign)(size_t alignment, size_t bytes);
 };
 
-/* Malloc debugging initialization routine.
- * This routine must be implemented in .so modules that implement malloc
- * debugging. This routine is called once per process from malloc_init_impl
- * routine implemented in bionic/libc/bionic/malloc_debug_common.c when malloc
+/* Malloc debugging initialization and finalization routines.
+ *
+ * These routines must be implemented in .so modules that implement malloc
+ * debugging. The are is called once per process from malloc_init_impl and
+ * malloc_fini_impl respectively.
+ *
+ * They are implemented in bionic/libc/bionic/malloc_debug_common.c when malloc
  * debugging gets initialized for the process.
- * Return:
- *  0 on success, -1 on failure.
+ *
+ * MallocDebugInit returns:
+ *    0 on success, -1 on failure.
  */
 typedef int (*MallocDebugInit)(void);
+typedef void (*MallocDebugFini)(void);
+
+// =============================================================================
+// log functions
+// =============================================================================
+
+#define debug_log(format, ...)  \
+    __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__ )
 
 #ifdef __cplusplus
 };  /* end of extern "C" */
diff --git a/libc/bionic/malloc_debug_leak.c b/libc/bionic/malloc_debug_leak.c
index e584502..316d5fe 100644
--- a/libc/bionic/malloc_debug_leak.c
+++ b/libc/bionic/malloc_debug_leak.c
@@ -61,22 +61,11 @@
 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
+// stack trace functions
 // =============================================================================
 
-#define debug_log(format, ...)  \
-    __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;
-
 #define MALLOC_ALIGNMENT    8
 #define GUARD               0x48151642
 #define DEBUG               0
@@ -210,250 +199,12 @@
     gHashTable.count--;
 }
 
-
 // =============================================================================
-// stack trace functions
-// =============================================================================
-
-typedef struct
-{
-    size_t count;
-    intptr_t* addrs;
-} stack_crawl_state_t;
-
-
-/* depends how the system includes define this */
-#ifdef HAVE_UNWIND_CONTEXT_STRUCT
-typedef struct _Unwind_Context __unwind_context;
-#else
-typedef _Unwind_Context __unwind_context;
-#endif
-
-static _Unwind_Reason_Code trace_function(__unwind_context *context, void *arg)
-{
-    stack_crawl_state_t* state = (stack_crawl_state_t*)arg;
-    if (state->count) {
-        intptr_t ip = (intptr_t)_Unwind_GetIP(context);
-        if (ip) {
-            state->addrs[0] = ip;
-            state->addrs++;
-            state->count--;
-            return _URC_NO_REASON;
-        }
-    }
-    /*
-     * If we run out of space to record the address or 0 has been seen, stop
-     * unwinding the stack.
-     */
-    return _URC_END_OF_STACK;
-}
-
-static inline
-int get_backtrace(intptr_t* addrs, size_t max_entries)
-{
-    stack_crawl_state_t state;
-    state.count = max_entries;
-    state.addrs = (intptr_t*)addrs;
-    _Unwind_Backtrace(trace_function, (void*)&state);
-    return max_entries - state.count;
-}
-
-// =============================================================================
-// malloc check functions
+// malloc fill functions
 // =============================================================================
 
 #define CHK_FILL_FREE           0xef
 #define CHK_SENTINEL_VALUE      (char)0xeb
-#define CHK_SENTINEL_HEAD_SIZE  16
-#define CHK_SENTINEL_TAIL_SIZE  16
-#define CHK_OVERHEAD_SIZE       (   CHK_SENTINEL_HEAD_SIZE +    \
-                                    CHK_SENTINEL_TAIL_SIZE +    \
-                                    sizeof(size_t) )
-
-static void dump_stack_trace()
-{
-    intptr_t addrs[20];
-    int c = get_backtrace(addrs, 20);
-    char buf[16];
-    char tmp[16*20];
-    int i;
-
-    tmp[0] = 0; // Need to initialize tmp[0] for the first strcat
-    for (i=0 ; i<c; i++) {
-        snprintf(buf, sizeof buf, "%2d: %08x\n", i, addrs[i]);
-        strlcat(tmp, buf, sizeof tmp);
-    }
-    __libc_android_log_print(ANDROID_LOG_ERROR, "libc", "call stack:\n%s", tmp);
-}
-
-static int is_valid_malloc_pointer(void* addr)
-{
-    return 1;
-}
-
-static void assert_log_message(const char* format, ...)
-{
-    va_list  args;
-
-    pthread_mutex_lock(&gAllocationsMutex);
-    {
-        const MallocDebug* current_dispatch = __libc_malloc_dispatch;
-        __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
-        va_start(args, format);
-        __libc_android_log_vprint(ANDROID_LOG_ERROR, "libc",
-                                format, args);
-        va_end(args);
-        dump_stack_trace();
-        if (gTrapOnError) {
-            __builtin_trap();
-        }
-        __libc_malloc_dispatch = current_dispatch;
-    }
-    pthread_mutex_unlock(&gAllocationsMutex);
-}
-
-static void assert_valid_malloc_pointer(void* mem)
-{
-    if (mem && !is_valid_malloc_pointer(mem)) {
-        assert_log_message(
-            "*** MALLOC CHECK: buffer %p, is not a valid "
-            "malloc pointer (are you mixing up new/delete "
-            "and malloc/free?)", mem);
-    }
-}
-
-/* Check that a given address corresponds to a guarded block,
- * and returns its original allocation size in '*allocated'.
- * 'func' is the capitalized name of the caller function.
- * Returns 0 on success, or -1 on failure.
- * NOTE: Does not return if gTrapOnError is set.
- */
-static int chk_mem_check(void*       mem,
-                         size_t*     allocated,
-                         const char* func)
-{
-    char*  buffer;
-    size_t offset, bytes;
-    int    i;
-    char*  buf;
-
-    /* first check the bytes in the sentinel header */
-    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(
-                "*** %s CHECK: buffer %p "
-                "corrupted %d bytes before allocation",
-                func, mem, CHK_SENTINEL_HEAD_SIZE-i);
-            return -1;
-        }
-    }
-
-    /* then the ones in the sentinel trailer */
-    buffer = (char*)mem - CHK_SENTINEL_HEAD_SIZE;
-    offset = dlmalloc_usable_size(buffer) - sizeof(size_t);
-    bytes  = *(size_t *)(buffer + offset);
-
-    buf = (char*)mem + bytes;
-    for (i=CHK_SENTINEL_TAIL_SIZE-1 ; i>=0 ; i--) {
-        if (buf[i] != CHK_SENTINEL_VALUE) {
-            assert_log_message(
-                "*** %s CHECK: buffer %p, size=%lu, "
-                "corrupted %d bytes after allocation",
-                func, buffer, bytes, i+1);
-            return -1;
-        }
-    }
-
-    *allocated = bytes;
-    return 0;
-}
-
-
-void* chk_malloc(size_t bytes)
-{
-    size_t size = bytes + CHK_OVERHEAD_SIZE;
-    if (size < bytes) { // Overflow.
-        return NULL;
-    }
-    uint8_t* buffer = (uint8_t*) dlmalloc(size);
-    if (buffer) {
-        memset(buffer, CHK_SENTINEL_VALUE, bytes + CHK_OVERHEAD_SIZE);
-        size_t offset = dlmalloc_usable_size(buffer) - sizeof(size_t);
-        *(size_t *)(buffer + offset) = bytes;
-        buffer += CHK_SENTINEL_HEAD_SIZE;
-    }
-    return buffer;
-}
-
-void  chk_free(void* mem)
-{
-    assert_valid_malloc_pointer(mem);
-    if (mem) {
-        size_t  size;
-        char*   buffer;
-
-        if (chk_mem_check(mem, &size, "FREE") == 0) {
-            buffer = (char*)mem - CHK_SENTINEL_HEAD_SIZE;
-            memset(buffer, CHK_FILL_FREE, size + CHK_OVERHEAD_SIZE);
-            dlfree(buffer);
-        }
-    }
-}
-
-void* chk_calloc(size_t n_elements, size_t elem_size)
-{
-    size_t  size;
-    void*   ptr;
-
-    /* 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 && MAX_SIZE_T / n_elements < elem_size) {
-        return NULL;
-    }
-    size = n_elements * elem_size;
-    ptr  = chk_malloc(size);
-    if (ptr != NULL) {
-        memset(ptr, 0, size);
-    }
-    return ptr;
-}
-
-void* chk_realloc(void* mem, size_t bytes)
-{
-    char*   buffer;
-    int     ret;
-    size_t  old_bytes = 0;
-
-    assert_valid_malloc_pointer(mem);
-
-    if (mem != NULL && chk_mem_check(mem, &old_bytes, "REALLOC") < 0)
-        return NULL;
-
-    char* new_buffer = chk_malloc(bytes);
-    if (mem == NULL) {
-        return new_buffer;
-    }
-
-    if (new_buffer) {
-        if (bytes > old_bytes)
-            bytes = old_bytes;
-        memcpy(new_buffer, mem, bytes);
-        chk_free(mem);
-    }
-
-    return new_buffer;
-}
-
-void* chk_memalign(size_t alignment, size_t bytes)
-{
-    // XXX: it's better to use malloc, than being wrong
-    return chk_malloc(bytes);
-}
-
-// =============================================================================
-// malloc fill functions
-// =============================================================================
 
 void* fill_malloc(size_t bytes)
 {
@@ -501,6 +252,9 @@
 
 #define MEMALIGN_GUARD  ((void*)0xA1A41520)
 
+extern __LIBC_HIDDEN__
+int get_backtrace(intptr_t* addrs, size_t max_entries);
+
 void* leak_malloc(size_t bytes)
 {
     // allocate enough space infront of the allocation to store the pointer for
@@ -645,12 +399,3 @@
     }
     return base;
 }
-
-/* Initializes malloc debugging framework.
- * See comments on MallocDebugInit in malloc_debug_common.h
- */
-int malloc_debug_initialize(void)
-{
-    // We don't really have anything that requires initialization here.
-    return 0;
-}
diff --git a/libc/bionic/malloc_debug_qemu.c b/libc/bionic/malloc_debug_qemu.c
index 4b694e9..bcbf1e6 100644
--- a/libc/bionic/malloc_debug_qemu.c
+++ b/libc/bionic/malloc_debug_qemu.c
@@ -287,7 +287,7 @@
 /*
  * Logging helper macros.
  */
-#define debug_log(format, ...)                                              \
+#define qemu_debug_log(format, ...)                                         \
     do {                                                                    \
         __libc_android_log_print(ANDROID_LOG_DEBUG, "memcheck",             \
                                  (format), ##__VA_ARGS__ );                 \
@@ -296,7 +296,7 @@
         }                                                                   \
     } while (0)
 
-#define error_log(format, ...)                                              \
+#define qemu_error_log(format, ...)                                         \
     do {                                                                    \
         __libc_android_log_print(ANDROID_LOG_ERROR, "memcheck",             \
                                  (format), ##__VA_ARGS__ );                 \
@@ -305,7 +305,7 @@
         }                                                                   \
     } while (0)
 
-#define info_log(format, ...)                                               \
+#define qemu_info_log(format, ...)                                          \
     do {                                                                    \
         __libc_android_log_print(ANDROID_LOG_INFO, "memcheck",              \
                                  (format), ##__VA_ARGS__ );                 \
@@ -692,7 +692,7 @@
 
     notify_qemu_libc_initialized(malloc_pid);
 
-    debug_log("Instrumented for pid=%03u: malloc=%p, free=%p, calloc=%p, realloc=%p, memalign=%p",
+    qemu_debug_log("Instrumented for pid=%03u: malloc=%p, free=%p, calloc=%p, realloc=%p, memalign=%p",
               malloc_pid, qemu_instrumented_malloc, qemu_instrumented_free,
               qemu_instrumented_calloc, qemu_instrumented_realloc,
               qemu_instrumented_memalign);
@@ -717,7 +717,7 @@
     desc.suffix_size = DEFAULT_SUFFIX_SIZE;
     desc.ptr = dlmalloc(mallocdesc_alloc_size(&desc));
     if (desc.ptr == NULL) {
-        error_log("<libc_pid=%03u, pid=%03u> malloc(%u): dlmalloc(%u) failed.",
+        qemu_error_log("<libc_pid=%03u, pid=%03u> malloc(%u): dlmalloc(%u) failed.",
                   malloc_pid, getpid(), bytes, mallocdesc_alloc_size(&desc));
         return NULL;
     }
@@ -797,7 +797,7 @@
 
     if (n_elements == 0 || elem_size == 0) {
         // Just let go zero bytes allocation.
-        info_log("::: <libc_pid=%03u, pid=%03u>: Zero calloc redir to malloc",
+        qemu_info_log("::: <libc_pid=%03u, pid=%03u>: Zero calloc redir to malloc",
                  malloc_pid, getpid());
         return qemu_instrumented_malloc(0);
     }
@@ -874,14 +874,14 @@
 
     if (mem == NULL) {
         // Nothing to realloc. just do regular malloc.
-        info_log("::: <libc_pid=%03u, pid=%03u>: realloc(%p, %u) redir to malloc",
+        qemu_info_log("::: <libc_pid=%03u, pid=%03u>: realloc(%p, %u) redir to malloc",
                  malloc_pid, getpid(), mem, bytes);
         return qemu_instrumented_malloc(bytes);
     }
 
     if (bytes == 0) {
         // This is a "free" condition.
-        info_log("::: <libc_pid=%03u, pid=%03u>: realloc(%p, %u) redir to free and malloc",
+        qemu_info_log("::: <libc_pid=%03u, pid=%03u>: realloc(%p, %u) redir to free and malloc",
                  malloc_pid, getpid(), mem, bytes);
         qemu_instrumented_free(mem);
 
@@ -977,7 +977,7 @@
 
     if (bytes == 0) {
         // Just let go zero bytes allocation.
-        info_log("::: <libc_pid=%03u, pid=%03u>: memalign(%X, %u) redir to malloc",
+        qemu_info_log("::: <libc_pid=%03u, pid=%03u>: memalign(%X, %u) redir to malloc",
                  malloc_pid, getpid(), alignment, bytes);
         return qemu_instrumented_malloc(0);
     }
diff --git a/libc/bionic/malloc_debug_stacktrace.c b/libc/bionic/malloc_debug_stacktrace.c
new file mode 100644
index 0000000..c71b1c5
--- /dev/null
+++ b/libc/bionic/malloc_debug_stacktrace.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <unwind.h>
+#include <sys/types.h>
+
+// =============================================================================
+// stack trace functions
+// =============================================================================
+
+typedef struct
+{
+    size_t count;
+    intptr_t* addrs;
+} stack_crawl_state_t;
+
+
+/* depends how the system includes define this */
+#ifdef HAVE_UNWIND_CONTEXT_STRUCT
+typedef struct _Unwind_Context __unwind_context;
+#else
+typedef _Unwind_Context __unwind_context;
+#endif
+
+static _Unwind_Reason_Code trace_function(__unwind_context *context, void *arg)
+{
+    stack_crawl_state_t* state = (stack_crawl_state_t*)arg;
+    if (state->count) {
+        intptr_t ip = (intptr_t)_Unwind_GetIP(context);
+        if (ip) {
+            state->addrs[0] = ip;
+            state->addrs++;
+            state->count--;
+            return _URC_NO_REASON;
+        }
+    }
+    /*
+     * If we run out of space to record the address or 0 has been seen, stop
+     * unwinding the stack.
+     */
+    return _URC_END_OF_STACK;
+}
+
+__LIBC_HIDDEN__
+int get_backtrace(intptr_t* addrs, size_t max_entries)
+{
+    stack_crawl_state_t state;
+    state.count = max_entries;
+    state.addrs = (intptr_t*)addrs;
+    _Unwind_Backtrace(trace_function, (void*)&state);
+    return max_entries - state.count;
+}