Sfoglia il codice sorgente

Improve malloc debugging support.

Miles Bader 21 anni fa
parent
commit
4d952dfe77

+ 11 - 0
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

+ 12 - 2
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
-

+ 17 - 8
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

+ 15 - 10
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);

+ 19 - 12
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);
 }

+ 34 - 11
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).  */

+ 85 - 0
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));
+    }
+}

+ 4 - 3
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;
 }