summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extra/Configs/Config.in11
-rw-r--r--libc/stdlib/malloc/Makefile14
-rw-r--r--libc/stdlib/malloc/free.c25
-rw-r--r--libc/stdlib/malloc/heap_debug.c25
-rw-r--r--libc/stdlib/malloc/malloc.c31
-rw-r--r--libc/stdlib/malloc/malloc.h45
-rw-r--r--libc/stdlib/malloc/malloc_debug.c85
-rw-r--r--libc/stdlib/malloc/realloc.c7
8 files changed, 197 insertions, 46 deletions
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index 3b5fcf1f5..089c1b40b 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -367,4 +367,15 @@ config SUPPORT_LD_DEBUG_EARLY
to debug the uClibc shared library loader early initialization,
answer Y. Mere mortals answer N.
+config UCLIBC_MALLOC_DEBUGGING
+ bool "Build malloc with debugging support"
+ depends MALLOC
+ default n
+ help
+ Answer Y here to compile extra debugging support code into malloc.
+ Malloc debugging output may then be enabled at runtime using
+ the MALLOC_DEBUG environment variable. Because this increases
+ the size of malloc appreciably (due to strings etc), you
+ should say N unless you need to debug a malloc problem.
+
endmenu
diff --git a/libc/stdlib/malloc/Makefile b/libc/stdlib/malloc/Makefile
index 97527621b..d722d1dc3 100644
--- a/libc/stdlib/malloc/Makefile
+++ b/libc/stdlib/malloc/Makefile
@@ -27,6 +27,16 @@ include $(TOPDIR)Rules.mak
# calloc.c can be found at uClibc/libc/stdlib/calloc.c
CSRC = malloc.c free.c realloc.c memalign.c \
heap_alloc.c heap_alloc_at.c heap_free.c
+
+# Turn on malloc debugging if requested
+ifeq ($(UCLIBC_MALLOC_DEBUGGING),y)
+CSRC += malloc_debug.c heap_debug.c
+CFLAGS += -DMALLOC_DEBUGGING -DHEAP_DEBUGGING
+ifeq ($(UCLIBC_UCLINUX_BROKEN_MUNMAP),y)
+CFLAGS += -DMALLOC_MMB_DEBUGGING
+endif
+endif
+
COBJS=$(patsubst %.c,%.o, $(CSRC))
OBJS=$(COBJS)
@@ -37,10 +47,10 @@ $(LIBC): ar-target
ar-target: $(OBJS)
$(AR) $(ARFLAGS) $(LIBC) $(OBJS)
-$(COBJS): %.o : %.c
+# Depend on uClinux_config.h to cache changes in __UCLIBC_MALLOC_DEBUGGING__
+$(COBJS): %.o : %.c ../../../include/bits/uClibc_config.h
$(CC) $(CFLAGS) -c $< -o $@
$(STRIPTOOL) -x -R .note -R .comment $*.o
clean:
rm -f *.[oa] *~ core
-
diff --git a/libc/stdlib/malloc/free.c b/libc/stdlib/malloc/free.c
index a00f996d9..3b2ec651e 100644
--- a/libc/stdlib/malloc/free.c
+++ b/libc/stdlib/malloc/free.c
@@ -31,7 +31,7 @@ free_to_heap (void *mem, struct heap *heap)
/* Normal free. */
- MALLOC_DEBUG ("free: 0x%lx (base = 0x%lx, total_size = %d)\n",
+ MALLOC_DEBUG (1, "free: 0x%lx (base = 0x%lx, total_size = %d)",
(long)mem, (long)MALLOC_BASE (mem), MALLOC_SIZE (mem));
size = MALLOC_SIZE (mem);
@@ -76,7 +76,7 @@ free_to_heap (void *mem, struct heap *heap)
reasonably cheap. */
if ((void *)end != sbrk (0))
{
- MALLOC_DEBUG (" not unmapping: 0x%lx - 0x%lx (%ld bytes)\n",
+ MALLOC_DEBUG (-1, "not unmapping: 0x%lx - 0x%lx (%ld bytes)",
start, end, end - start);
__malloc_unlock_sbrk ();
__heap_unlock (heap);
@@ -84,7 +84,7 @@ free_to_heap (void *mem, struct heap *heap)
}
#endif
- MALLOC_DEBUG (" unmapping: 0x%lx - 0x%lx (%ld bytes)\n",
+ MALLOC_DEBUG (0, "unmapping: 0x%lx - 0x%lx (%ld bytes)",
start, end, end - start);
/* Remove FA from the heap. */
@@ -119,7 +119,8 @@ free_to_heap (void *mem, struct heap *heap)
exactly as we got them from mmap, so scan through our list of
mmapped blocks, and return them in order. */
- MALLOC_MMB_DEBUG (" walking mmb list for region 0x%x[%d]...\n", start, end - start);
+ MALLOC_MMB_DEBUG (1, "walking mmb list for region 0x%x[%d]...",
+ start, end - start);
prev_mmb = 0;
mmb = __malloc_mmapped_blocks;
@@ -127,7 +128,7 @@ free_to_heap (void *mem, struct heap *heap)
&& ((mmb_end = (mmb_start = (unsigned long)mmb->mem) + mmb->size)
<= end))
{
- MALLOC_MMB_DEBUG (" considering mmb at 0x%x: 0x%x[%d]\n",
+ MALLOC_MMB_DEBUG (1, "considering mmb at 0x%x: 0x%x[%d]",
(unsigned)mmb, mmb_start, mmb_end - mmb_start);
if (mmb_start >= start
@@ -143,18 +144,20 @@ free_to_heap (void *mem, struct heap *heap)
this block, so give up. */
break;
- MALLOC_MMB_DEBUG (" unmapping mmb at 0x%x: 0x%x[%d]\n",
+ MALLOC_MMB_DEBUG (1, "unmapping mmb at 0x%x: 0x%x[%d]",
(unsigned)mmb, mmb_start, mmb_end - mmb_start);
if (mmb_start != start)
/* We're going to unmap a part of the heap that begins after
start, so put the intervening region back into the heap. */
{
- MALLOC_MMB_DEBUG (" putting intervening region back into heap: 0x%x[%d]\n",
+ MALLOC_MMB_DEBUG (0, "putting intervening region back into heap: 0x%x[%d]",
start, mmb_start - start);
__heap_free (heap, (void *)start, mmb_start - start);
}
+ MALLOC_MMB_DEBUG_INDENT (-1);
+
/* Unlink MMB from the list. */
if (prev_mmb)
prev_mmb->next = next_mmb;
@@ -194,17 +197,21 @@ free_to_heap (void *mem, struct heap *heap)
prev_mmb = mmb;
mmb = mmb->next;
}
+
+ MALLOC_MMB_DEBUG_INDENT (-1);
}
if (start != end)
/* Hmm, well there's something we couldn't unmap, so put it back
into the heap. */
{
- MALLOC_MMB_DEBUG (" putting tail region back into heap: 0x%x[%d]\n",
+ MALLOC_MMB_DEBUG (0, "putting tail region back into heap: 0x%x[%d]",
start, end - start);
__heap_free (heap, (void *)start, end - start);
}
+ MALLOC_MMB_DEBUG_INDENT (-1);
+
# else /* !__UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
/* MEM/LEN may not be page-aligned, so we have to page-align them,
@@ -241,6 +248,8 @@ free_to_heap (void *mem, struct heap *heap)
#endif /* MALLOC_USE_SBRK */
}
+
+ MALLOC_DEBUG_INDENT (-1);
}
void
diff --git a/libc/stdlib/malloc/heap_debug.c b/libc/stdlib/malloc/heap_debug.c
index 85ed15609..c1a127317 100644
--- a/libc/stdlib/malloc/heap_debug.c
+++ b/libc/stdlib/malloc/heap_debug.c
@@ -16,6 +16,7 @@
#include <stdarg.h>
#include <string.h>
+#include "malloc.h"
#include "heap.h"
@@ -29,14 +30,14 @@ __heap_dump_freelist (struct heap *heap)
{
struct heap_free_area *fa;
for (fa = heap->free_areas; fa; fa = fa->next)
- fprintf (stderr,
- " 0x%lx: 0x%lx - 0x%lx (%d)\tP=0x%lx, N=0x%lx\n",
- (long)fa,
- (long)HEAP_FREE_AREA_START (fa),
- (long)HEAP_FREE_AREA_END (fa),
- fa->size,
- (long)fa->prev,
- (long)fa->next);
+ __malloc_debug_printf (0,
+ "0x%lx: 0x%lx - 0x%lx (%d)\tP=0x%lx, N=0x%lx",
+ (long)fa,
+ (long)HEAP_FREE_AREA_START (fa),
+ (long)HEAP_FREE_AREA_END (fa),
+ fa->size,
+ (long)fa->prev,
+ (long)fa->next);
}
/* Output a text representation of HEAP to stderr, labelling it with STR. */
@@ -51,8 +52,9 @@ __heap_dump (struct heap *heap, const char *str)
recursed = 1;
- fprintf (stderr, " %s: heap @0x%lx:\n", str, (long)heap);
+ __malloc_debug_printf (1, "%s: heap @0x%lx:", str, (long)heap);
__heap_dump_freelist (heap);
+ __malloc_debug_indent (-1);
recursed = 0;
}
@@ -76,7 +78,10 @@ __heap_check_failure (struct heap *heap, struct heap_free_area *fa,
vfprintf (stderr, fmt, val);
va_end (val);
- fprintf (stderr, "\nheap dump:\n");
+ putc ('\n', stderr);
+
+ __malloc_debug_set_indent (0);
+ __malloc_debug_printf (1, "heap dump:");
__heap_dump_freelist (heap);
exit (22);
diff --git a/libc/stdlib/malloc/malloc.c b/libc/stdlib/malloc/malloc.c
index b23d566b1..4466367ed 100644
--- a/libc/stdlib/malloc/malloc.c
+++ b/libc/stdlib/malloc/malloc.c
@@ -29,10 +29,6 @@ struct heap __malloc_heap = HEAP_INIT_WITH_FA (initial_fa);
malloc_mutex_t __malloc_sbrk_lock;
#endif /* MALLOC_USE_LOCKING && MALLOC_USE_SBRK */
-#ifdef MALLOC_DEBUGGING
-int __malloc_debug = 0;
-#endif
-
#ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__
/* A list of all malloc_mmb structures describing blocsk that
@@ -44,10 +40,6 @@ struct malloc_mmb *__malloc_mmapped_blocks = 0;
annoying ways. */
HEAP_DECLARE_STATIC_FREE_AREA (initial_mmb_fa, 48); /* enough for 3 mmbs */
struct heap __malloc_mmb_heap = HEAP_INIT_WITH_FA (initial_mmb_fa);
-
-# ifdef MALLOC_MMB_DEBUGGING
-int __malloc_mmb_debug = 0;
-# endif
#endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
@@ -56,7 +48,7 @@ malloc_from_heap (size_t size, struct heap *heap)
{
void *mem;
- MALLOC_DEBUG ("malloc: %d bytes\n", size);
+ MALLOC_DEBUG (1, "malloc: %d bytes", size);
/* Include extra space to record the size of the allocated block. */
size += MALLOC_HEADER_SIZE;
@@ -121,7 +113,7 @@ malloc_from_heap (size_t size, struct heap *heap)
struct malloc_mmb *mmb, *prev_mmb, *new_mmb;
#endif
- MALLOC_DEBUG (" adding memory: 0x%lx - 0x%lx (%d bytes)\n",
+ MALLOC_DEBUG (1, "adding system memroy to heap: 0x%lx - 0x%lx (%d bytes)",
(long)block, (long)block + block_size, block_size);
/* Get back the heap lock. */
@@ -130,6 +122,8 @@ malloc_from_heap (size_t size, struct heap *heap)
/* Put BLOCK into the heap. */
__heap_free (heap, block, block_size);
+ MALLOC_DEBUG_INDENT (-1);
+
/* Try again to allocate. */
mem = __heap_alloc (heap, &size);
@@ -155,7 +149,7 @@ malloc_from_heap (size_t size, struct heap *heap)
else
__malloc_mmapped_blocks = new_mmb;
- MALLOC_MMB_DEBUG (" new mmb at 0x%x: 0x%x[%d]\n",
+ MALLOC_MMB_DEBUG (0, "new mmb at 0x%x: 0x%x[%d]",
(unsigned)new_mmb,
(unsigned)new_mmb->mem, block_size);
#endif /* !MALLOC_USE_SBRK && __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
@@ -167,9 +161,11 @@ malloc_from_heap (size_t size, struct heap *heap)
{
mem = MALLOC_SETUP (mem, size);
- MALLOC_DEBUG (" malloc: returning 0x%lx (base:0x%lx, total_size:%d)\n",
+ MALLOC_DEBUG (-1, "malloc: returning 0x%lx (base:0x%lx, total_size:%ld)",
(long)mem, (long)MALLOC_BASE(mem), (long)MALLOC_SIZE(mem));
}
+ else
+ MALLOC_DEBUG (-1, "malloc: returning 0");
return mem;
}
@@ -177,5 +173,16 @@ malloc_from_heap (size_t size, struct heap *heap)
void *
malloc (size_t size)
{
+#ifdef MALLOC_DEBUGGING
+ static int debugging_initialized = 0;
+ if (! debugging_initialized)
+ {
+ debugging_initialized = 1;
+ __malloc_debug_init ();
+ }
+ if (__malloc_check)
+ __heap_check (&__malloc_heap, "malloc");
+#endif
+
return malloc_from_heap (size, &__malloc_heap);
}
diff --git a/libc/stdlib/malloc/malloc.h b/libc/stdlib/malloc/malloc.h
index db0fb9bd7..7fe8b6016 100644
--- a/libc/stdlib/malloc/malloc.h
+++ b/libc/stdlib/malloc/malloc.h
@@ -78,12 +78,18 @@ extern struct heap __malloc_mmb_heap;
about mmap block allocation/freeing by the `uclinux broken munmap' code
to stderr, when the variable __malloc_mmb_debug is set to true. */
#ifdef MALLOC_MMB_DEBUGGING
-#include <stdio.h>
+# include <stdio.h>
extern int __malloc_mmb_debug;
-#define MALLOC_MMB_DEBUG(fmt, args...) \
- (__malloc_mmb_debug ? fprintf (stderr, fmt , ##args) : 0)
+# define MALLOC_MMB_DEBUG(indent, fmt, args...) \
+ (__malloc_mmb_debug ? __malloc_debug_printf (indent, fmt , ##args) : 0)
+# define MALLOC_MMB_DEBUG_INDENT(indent) \
+ (__malloc_mmb_debug ? __malloc_debug_indent (indent) : 0)
+# ifndef MALLOC_DEBUGGING
+# define MALLOC_DEBUGGING
+# endif
#else /* !MALLOC_MMB_DEBUGGING */
-#define MALLOC_MMB_DEBUG(fmt, args...) (void)0
+# define MALLOC_MMB_DEBUG(fmt, args...) (void)0
+# define MALLOC_MMB_DEBUG_INDENT(indent) (void)0
#endif /* MALLOC_MMB_DEBUGGING */
#endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
@@ -158,13 +164,30 @@ extern malloc_mutex_t __malloc_sbrk_lock;
/* Define MALLOC_DEBUGGING to cause malloc to emit debugging info to stderr
when the variable __malloc_debug is set to true. */
#ifdef MALLOC_DEBUGGING
-#include <stdio.h>
-extern int __malloc_debug;
-#define MALLOC_DEBUG(fmt, args...) \
- (__malloc_debug ? fprintf (stderr, fmt , ##args) : 0)
-#else
-#define MALLOC_DEBUG(fmt, args...) (void)0
-#endif
+
+extern int __malloc_debug, __malloc_check;
+
+# define MALLOC_DEBUG(indent, fmt, args...) \
+ (__malloc_debug ? __malloc_debug_printf (indent, fmt , ##args) : 0)
+# define MALLOC_DEBUG_INDENT(indent) \
+ (__malloc_debug ? __malloc_debug_indent (indent) : 0)
+
+extern int __malloc_debug_cur_indent;
+
+/* Print FMT and args indented at the current debug print level, followed
+ by a newline, and change the level by INDENT. */
+extern void __malloc_debug_printf (int indent, const char *fmt, ...);
+
+/* Change the current debug print level by INDENT. */
+#define __malloc_debug_indent(indent) (__malloc_debug_cur_indent += indent)
+
+/* Set the current debug print level to LEVEL. */
+#define __malloc_debug_set_indent(level) (__malloc_debug_cur_indent = level)
+
+#else /* !MALLOC_DEBUGGING */
+# define MALLOC_DEBUG(fmt, args...) (void)0
+# define MALLOC_DEBUG_INDENT(indent) (void)0
+#endif /* MALLOC_DEBUGGING */
/* Return SZ rounded down to POWER_OF_2_SIZE (which must be power of 2). */
diff --git a/libc/stdlib/malloc/malloc_debug.c b/libc/stdlib/malloc/malloc_debug.c
new file mode 100644
index 000000000..20a37f2f0
--- /dev/null
+++ b/libc/stdlib/malloc/malloc_debug.c
@@ -0,0 +1,85 @@
+/*
+ * libc/stdlib/malloc/malloc_debug.c -- malloc debugging support
+ *
+ * Copyright (C) 2002 NEC Corporation
+ * Copyright (C) 2002 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License. See the file COPYING.LIB in the main
+ * directory of this archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "malloc.h"
+#include "heap.h"
+
+#ifdef MALLOC_DEBUGGING
+int __malloc_debug = 0, __malloc_check = 0;
+#endif
+
+#ifdef MALLOC_MMB_DEBUGGING
+int __malloc_mmb_debug = 0;
+#endif
+
+/* Debugging output is indented this may levels. */
+int __malloc_debug_cur_indent = 0;
+
+
+/* Print FMT and args indented at the current debug print level, followed
+ by a newline, and change the level by INDENT. */
+void
+__malloc_debug_printf (int indent, const char *fmt, ...)
+{
+ int i;
+ va_list val;
+
+ for (i = 0; i < __malloc_debug_cur_indent; i++)
+ fputs (" ", stderr);
+
+ va_start (val, fmt);
+ vfprintf (stderr, fmt, val);
+ va_end (val);
+
+ putc ('\n', stderr);
+
+ __malloc_debug_indent (indent);
+}
+
+void
+__malloc_debug_init (void)
+{
+ char *ev = getenv ("MALLOC_DEBUG");
+ if (ev)
+ {
+ int val = atoi (ev);
+ if (val & 1)
+ __malloc_check = 1;
+
+#ifdef MALLOC_DEBUGGING
+ if (val & 2)
+ __malloc_debug = 1;
+#endif
+#ifdef MALLOC_MMB_DEBUGGING
+ if (val & 4)
+ __malloc_mmb_debug = 1;
+#endif
+
+#ifdef HEAP_DEBUGGING
+ if (val & 8)
+ __heap_debug = 1;
+#endif
+
+ if (val)
+ __malloc_debug_printf
+ (0, "malloc_debug: initialized to %d (check = %d, dump = %d, dump_mmb = %d, dump_heap = %d)",
+ val,
+ !!(val & 1), !!(val & 2),
+ !!(val & 4), !!(val & 8));
+ }
+}
diff --git a/libc/stdlib/malloc/realloc.c b/libc/stdlib/malloc/realloc.c
index 9bfe95198..d4e0d9cb4 100644
--- a/libc/stdlib/malloc/realloc.c
+++ b/libc/stdlib/malloc/realloc.c
@@ -43,7 +43,7 @@ realloc (void *mem, size_t new_size)
allocation unit (SIZE is already guaranteed to be so).*/
new_size = HEAP_ADJUST_SIZE (new_size + MALLOC_HEADER_SIZE);
- MALLOC_DEBUG ("realloc: 0x%lx, %d (base = 0x%lx, total_size = %d)\n",
+ MALLOC_DEBUG (1, "realloc: 0x%lx, %d (base = 0x%lx, total_size = %d)",
(long)mem, new_size, (long)base_mem, size);
if (new_size > size)
@@ -81,9 +81,10 @@ realloc (void *mem, size_t new_size)
}
if (mem)
- MALLOC_DEBUG (" realloc: returning 0x%lx"
- " (base:0x%lx, total_size:%d)\n",
+ MALLOC_DEBUG (-1, "realloc: returning 0x%lx (base:0x%lx, total_size:%d)",
(long)mem, (long)MALLOC_BASE(mem), (long)MALLOC_SIZE(mem));
+ else
+ MALLOC_DEBUG (-1, "realloc: returning 0");
return mem;
}