summary refs log tree commit diff
path: root/malloc
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1997-09-27 00:21:42 +0000
committerUlrich Drepper <drepper@redhat.com>1997-09-27 00:21:42 +0000
commita2b08ee54130cf3a74655856e6ca6c29874a9df2 (patch)
tree71e7d867304f432bc57043e0c54a5cf101835651 /malloc
parent650425ceb40e840b2123b6c8cc65389589f41218 (diff)
downloadglibc-a2b08ee54130cf3a74655856e6ca6c29874a9df2.tar.gz
glibc-a2b08ee54130cf3a74655856e6ca6c29874a9df2.tar.xz
glibc-a2b08ee54130cf3a74655856e6ca6c29874a9df2.zip
1997-09-27 01:14  Ulrich Drepper  <drepper@cygnus.com>

	* Makeconfig (extra-objs): Depend in before-compile.

	* configure.in: Locate Perl and substitute with complete path.
	* config.make.in: Add PERL for substitution.
	* elf/Makefile (routines): Add dl-addr.
	* elf/dladdr.c: Move the real code into ...
	* elf/dl-addr.c: New file.
	* elf/link.h: Add prototype for _dl_addr.

	* elf/dladdr.c (dladdr): Change address argument to be const.
	* elf/dlfcn.h: Likewise.

	* locale/C_name.c: Add _nl_POSIX_name.
	* locale/localeinfo.h: Add declaration of _nl_POSIX_name.
	* locale/findlocale.c (_nl_find_locale): Use _nl_POSIX_name.
	(_nl_remove_locale): Free name of data set.
	* locale/setlocale.c (clever_copy): Remove.
	(new_composite_name): Use _nl_C_name and _nl_POSIX_name in compare.
	(setname): Only remove old name when it is for category LC_ALL.

	Change malloc, free, realloc, and memalign hooks for glibc to take
	another parameter indicating the location of the caller.
	* malloc/malloc.c: Change hook functions and variables.
	* malloc/malloc.h: Likewise.
	* malloc/mcheck.c: Likewise.  Make sure later hooked function also
	get the original caller address.
	* malloc/mtrace.c: Likewise.
	(tr_where): If no information in _mtrace_file is given use the
	information about the caller.
	* malloc/Makefile (distribute): Replace mtrace.awk by mtrace.pl.
	Add rules to install mtrace.pl after rewriting.
	* malloc/mtrace.pl: New file.  Based on the old AWK script but
	with extended functionality.
	* malloc/mtrace.awk: Removed.

	* po/fr.po: New version.

	* string/Makefile: Do use builtins for tester.c and inl-tester.c.
	* string/tester.c: Rewrite.  Split in many small functions to not
	exceed gcc's limits.

	* sysdeps/unix/sysv/linux/syscalls.list: Add prctl.

1997-09-25  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* string/bits/string2.h (__stpcpy_small): Don't use casts as
	lvalues.

1997-09-26  Andreas Jaeger  <aj@arthur.rhein-neckar.de>

	* manual/time.texi (Formatting Date and Time): Clarify
	explanation of strftime flags a bit.
	Suggested by Robert Bihlmeyer <robbe@orcus.priv.at>.

1997-09-25 00:13  David S. Miller  <davem@tanya.rutgers.edu>

	* sysdeps/libm-ieee754/s_exp2f.c: Protect _GNU_SOURCE definition.
	Fix typo, it is FLT_MANT_DIG.

1997-09-24 18:52  H.J. Lu  <hjl@gnu.ai.mit.edu>

	* math/atest-exp2.c: Include <stdlib/gmp.h> instead of <gmp.h>.

1997-08-27 08:10  H.J. Lu  <hjl@gnu.ai.mit.edu>

	* libio/libio.h, libio/libioP.h: Support libio in libstdc++.

	* libio/libio.h (_IO_peekc): Defined as _IO_peekc_unlocked if
	_IO_MTSAFE_IO is undefined.

1997-09-24 23:27  Richard Henderson  <rth@cygnus.com>

	* elf/dl-runtime.c (fixup): Don't go through elf_machine_relplt, but
	lookup the value of the target symbol ourselves and call the new
	elf_machine_fixup_plt.  This kills the ELF_FIXUP_RETURN_VALUE hack.
	(profile_fixup): Likewise, but don't fix up the plt.
	* elf/rtld.c (_dl_main): ELF_MACHINE_RELOC_NOPLT renamed _JMP_SLOT.
	* sysdeps/alpha/dl-machine.h (ELF_MACHINE_RELOC_NOPLT): Renamed.
	(elf_alpha_fix_plt): Renamed elf_machine_fixup_plt.
	* sysdeps/i386/dl-machine.h (elf_machine_relplt): Killed.
	(ELF_MACHINE_JMP_SLOT): Renamed.
	(elf_machine_fixup_plt): New function.
	* sysdeps/m68k/dl-machine.h: Likewise.
	* sysdeps/powerpc/dl-machine.h: Likewise.
	(elf_machine_rela): Moved JMP_SLOT fixup out to elf_machine_fixup_plt.
	* sysdeps/sparc/sparc32/dl-machine.h: Likewise.
	* sysdeps/sparc/sparc64/dl-machine.h: Likewise.
	* sysdeps/stub/dl-machine.h: Update, sorta.

	* sysdeps/alpha/dl-machine.h (elf_machine_runtime_setup): Do profiling.
	(TRAMPOLINE_TEMPLATE): From the carcas of _RUNTIME_TRAMPOLINE, do
	both normal and profile code.
	(elf_machine_rela): Handle r_addend for .got and .plt too.
Diffstat (limited to 'malloc')
-rw-r--r--malloc/Makefile21
-rw-r--r--malloc/malloc.c117
-rw-r--r--malloc/malloc.h21
-rw-r--r--malloc/mcheck.c41
-rw-r--r--malloc/mtrace.awk50
-rw-r--r--malloc/mtrace.c83
-rw-r--r--malloc/mtrace.pl192
7 files changed, 434 insertions, 91 deletions
diff --git a/malloc/Makefile b/malloc/Makefile
index b43ce136cd..addabf12f8 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -27,7 +27,7 @@ dist-headers := malloc.h
 headers := $(dist-headers) obstack.h
 tests := mallocbug
 
-distribute = thread-m.h mtrace.awk mcheck-init.c mcheck.h
+distribute = thread-m.h mtrace.pl mcheck-init.c mcheck.h
 
 # Things which get pasted together into gmalloc.c.
 gmalloc-routines := malloc morecore
@@ -41,6 +41,19 @@ non-lib.a := libmcheck.a
 # These should be removed by `make clean'.
 extra-objs = mcheck-init.o libmcheck.a
 
+# The AWK script to analyze the output of the mtrace functions.
+ifneq ($(PERL),no)
+install-bin = mtrace
+
+# The Perl script will print addresses and to do this nicely we must know
+# whether we are on a 32 or 64 bit machine.
+ifneq ($strip($(findstring wordsize-32,$(config-sysdirs))),)
+address-width=10
+else
+address-width=18
+endif
+endif
+
 include ../Rules
 
 $(objpfx)libmcheck.a: $(objpfx)mcheck-init.o
@@ -52,3 +65,9 @@ lib: $(objpfx)libmcheck.a
 
 # Uncomment this for test releases.  For public releases it is too expensive.
 #CPPFLAGS-malloc.o += -DMALLOC_DEBUG
+
+$(objpfx)mtrace: mtrace.pl
+	rm -fr %@.new
+	sed -e 's|@PERL@|$(PERL)|' -e 's|@XXX@|$(address-width)|' \
+	    -e 's|@VERSION@|$(version)|' $^ > $@.new \
+	&& rm -fr $@ && mv $@.new $@ && chmod +x $@
diff --git a/malloc/malloc.c b/malloc/malloc.c
index fb51483279..17350eb426 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1178,7 +1178,19 @@ static int       main_trim(size_t pad);
 #ifndef NO_THREADS
 static int       heap_trim(heap_info *heap, size_t pad);
 #endif
-#if defined(_LIBC) || defined(MALLOC_HOOKS)
+#ifdef _LIBC
+static Void_t*   malloc_check(size_t sz, const Void_t *caller);
+static void      free_check(Void_t* mem, const Void_t *caller);
+static Void_t*   realloc_check(Void_t* oldmem, size_t bytes,
+			       const Void_t *caller);
+static Void_t*   memalign_check(size_t alignment, size_t bytes,
+				const Void_t *caller);
+static Void_t*   malloc_starter(size_t sz, const Void_t *caller);
+static void      free_starter(Void_t* mem, const Void_t *caller);
+static Void_t*   malloc_atfork(size_t sz, const Void_t *caller);
+static void      free_atfork(Void_t* mem, const Void_t *caller);
+#else
+#ifdef MALLOC_HOOKS
 static Void_t*   malloc_check(size_t sz);
 static void      free_check(Void_t* mem);
 static Void_t*   realloc_check(Void_t* oldmem, size_t bytes);
@@ -1188,6 +1200,7 @@ static void      free_starter(Void_t* mem);
 static Void_t*   malloc_atfork(size_t sz);
 static void      free_atfork(Void_t* mem);
 #endif
+#endif
 
 #else
 
@@ -1520,11 +1533,19 @@ int __malloc_initialized = 0;
    temporarily, because the `atfork' handler mechanism may use
    malloc/free internally (e.g. in LinuxThreads). */
 
-#if defined(_LIBC) || defined(MALLOC_HOOKS)
+#ifdef _LIBC
+static __malloc_ptr_t (*save_malloc_hook) __MALLOC_P ((size_t __size,
+						       const __malloc_ptr_t));
+static void           (*save_free_hook) __MALLOC_P ((__malloc_ptr_t __ptr,
+						     const __malloc_ptr_t));
+static Void_t*        save_arena;
+#else
+#ifdef MALLOC_HOOKS
 static __malloc_ptr_t (*save_malloc_hook) __MALLOC_P ((size_t __size));
 static void           (*save_free_hook) __MALLOC_P ((__malloc_ptr_t __ptr));
 static Void_t*        save_arena;
 #endif
+#endif
 
 static void
 ptmalloc_lock_all __MALLOC_P((void))
@@ -1639,11 +1660,15 @@ thread_atfork_static(ptmalloc_lock_all, ptmalloc_unlock_all, \
    initialization routine, then do the normal work. */
 
 static Void_t*
+#ifdef _LIBC
+malloc_hook_ini(size_t sz, const __malloc_ptr_t caller)
+#else
 #if __STD_C
 malloc_hook_ini(size_t sz)
 #else
 malloc_hook_ini(sz) size_t sz;
 #endif
+#endif
 {
   __malloc_hook = NULL;
   __realloc_hook = NULL;
@@ -1653,11 +1678,15 @@ malloc_hook_ini(sz) size_t sz;
 }
 
 static Void_t*
+#ifdef _LIBC
+realloc_hook_ini(Void_t* ptr, size_t sz, const __malloc_ptr_t caller)
+#else
 #if __STD_C
 realloc_hook_ini(Void_t* ptr, size_t sz)
 #else
 realloc_hook_ini(ptr, sz) Void_t* ptr; size_t sz;
 #endif
+#endif
 {
   __malloc_hook = NULL;
   __realloc_hook = NULL;
@@ -1667,11 +1696,15 @@ realloc_hook_ini(ptr, sz) Void_t* ptr; size_t sz;
 }
 
 static Void_t*
+#ifdef _LIBC
+memalign_hook_ini(size_t sz, size_t alignment, const __malloc_ptr_t caller)
+#else
 #if __STD_C
 memalign_hook_ini(size_t sz, size_t alignment)
 #else
 memalign_hook_ini(sz, alignment) size_t sz; size_t alignment;
 #endif
+#endif
 {
   __malloc_hook = NULL;
   __realloc_hook = NULL;
@@ -1681,6 +1714,18 @@ memalign_hook_ini(sz, alignment) size_t sz; size_t alignment;
 }
 
 void weak_variable (*__malloc_initialize_hook) __MALLOC_P ((void)) = NULL;
+#ifdef _LIBC
+void weak_variable (*__free_hook) __MALLOC_P ((__malloc_ptr_t __ptr,
+					       const __malloc_ptr_t)) = NULL;
+__malloc_ptr_t weak_variable (*__malloc_hook)
+ __MALLOC_P ((size_t __size, const __malloc_ptr_t)) = malloc_hook_ini;
+__malloc_ptr_t weak_variable (*__realloc_hook)
+ __MALLOC_P ((__malloc_ptr_t __ptr, size_t __size, const __malloc_ptr_t))
+     = realloc_hook_ini;
+__malloc_ptr_t weak_variable (*__memalign_hook)
+ __MALLOC_P ((size_t __size, size_t __alignment, const __malloc_ptr_t))
+     = memalign_hook_ini;
+#else
 void weak_variable (*__free_hook) __MALLOC_P ((__malloc_ptr_t __ptr)) = NULL;
 __malloc_ptr_t weak_variable (*__malloc_hook)
  __MALLOC_P ((size_t __size)) = malloc_hook_ini;
@@ -1688,6 +1733,7 @@ __malloc_ptr_t weak_variable (*__realloc_hook)
  __MALLOC_P ((__malloc_ptr_t __ptr, size_t __size)) = realloc_hook_ini;
 __malloc_ptr_t weak_variable (*__memalign_hook)
  __MALLOC_P ((size_t __size, size_t __alignment)) = memalign_hook_ini;
+#endif
 void weak_variable (*__after_morecore_hook) __MALLOC_P ((void)) = NULL;
 
 /* Activate a standard set of debugging hooks. */
@@ -2489,7 +2535,11 @@ Void_t* mALLOc(bytes) size_t bytes;
   if (__malloc_hook != NULL) {
     Void_t* result;
 
+#ifdef _LIBC
+    result = (*__malloc_hook)(bytes, __builtin_return_address (0));
+#else
     result = (*__malloc_hook)(bytes);
+#endif
     return result;
   }
 #endif
@@ -2780,7 +2830,11 @@ void fREe(mem) Void_t* mem;
 
 #if defined(_LIBC) || defined(MALLOC_HOOKS)
   if (__free_hook != NULL) {
+#ifdef _LIBC
+    (*__free_hook)(mem, __builtin_return_address (0));
+#else
     (*__free_hook)(mem);
+#endif
     return;
   }
 #endif
@@ -2980,7 +3034,11 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
   if (__realloc_hook != NULL) {
     Void_t* result;
 
+#ifdef _LIBC
+    result = (*__realloc_hook)(oldmem, bytes, __builtin_return_address (0));
+#else
     result = (*__realloc_hook)(oldmem, bytes);
+#endif
     return result;
   }
 #endif
@@ -3242,7 +3300,12 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
   if (__memalign_hook != NULL) {
     Void_t* result;
 
+#ifdef _LIBC
+    result = (*__memalign_hook)(alignment, bytes,
+				__builtin_return_address (0));
+#else
     result = (*__memalign_hook)(alignment, bytes);
+#endif
     return result;
   }
 #endif
@@ -3413,10 +3476,14 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
 #if defined(_LIBC) || defined(MALLOC_HOOKS)
   if (__malloc_hook != NULL) {
     sz = n * elem_size;
+#ifdef _LIBC
+    mem = (*__malloc_hook)(sz, __builtin_return_address (0));
+#else
     mem = (*__malloc_hook)(sz);
+#endif
     if(mem == 0)
       return 0;
-#ifdef HAVE_MEMCPY
+#ifdef HAVE_MEMSET
     return memset(mem, 0, sz);
 #else
     while(sz > 0) ((char*)mem)[--sz] = 0; /* rather inefficient */
@@ -4106,11 +4173,15 @@ mem2chunk_check(mem) Void_t* mem;
 }
 
 static Void_t*
+#ifdef _LIBC
+malloc_check(size_t sz, const Void_t *caller)
+#else
 #if __STD_C
 malloc_check(size_t sz)
 #else
 malloc_check(sz) size_t sz;
 #endif
+#endif
 {
   mchunkptr victim;
   INTERNAL_SIZE_T nb = request2size(sz + 1);
@@ -4129,11 +4200,15 @@ malloc_check(sz) size_t sz;
 }
 
 static void
+#ifdef _LIBC
+free_check(Void_t* mem, const Void_t *caller)
+#else
 #if __STD_C
 free_check(Void_t* mem)
 #else
 free_check(mem) Void_t* mem;
 #endif
+#endif
 {
   mchunkptr p;
 
@@ -4166,16 +4241,24 @@ free_check(mem) Void_t* mem;
 }
 
 static Void_t*
+#ifdef _LIBC
+realloc_check(Void_t* oldmem, size_t bytes, const Void_t *caller)
+#else
 #if __STD_C
 realloc_check(Void_t* oldmem, size_t bytes)
 #else
 realloc_check(oldmem, bytes) Void_t* oldmem; size_t bytes;
 #endif
+#endif
 {
   mchunkptr oldp, newp;
   INTERNAL_SIZE_T nb, oldsize;
 
+#ifdef _LIBC
+  if (oldmem == 0) return malloc_check(bytes, NULL);
+#else
   if (oldmem == 0) return malloc_check(bytes);
+#endif
   (void)mutex_lock(&main_arena.mutex);
   oldp = mem2chunk_check(oldmem);
   if(!oldp) {
@@ -4187,7 +4270,11 @@ realloc_check(oldmem, bytes) Void_t* oldmem; size_t bytes;
     case 2:
       abort();
     }
+#ifdef _LIBC
+    return malloc_check(bytes, NULL);
+#else
     return malloc_check(bytes);
+#endif
   }
   oldsize = chunksize(oldp);
 
@@ -4240,16 +4327,24 @@ realloc_check(oldmem, bytes) Void_t* oldmem; size_t bytes;
 }
 
 static Void_t*
+#ifdef _LIBC
+memalign_check(size_t alignment, size_t bytes, const Void_t *caller)
+#else
 #if __STD_C
 memalign_check(size_t alignment, size_t bytes)
 #else
 memalign_check(alignment, bytes) size_t alignment; size_t bytes;
 #endif
+#endif
 {
   INTERNAL_SIZE_T nb;
   mchunkptr p;
 
+#ifdef _LIBC
+  if (alignment <= MALLOC_ALIGNMENT) return malloc_check(bytes, NULL);
+#else
   if (alignment <= MALLOC_ALIGNMENT) return malloc_check(bytes);
+#endif
   if (alignment <  MINSIZE) alignment = MINSIZE;
 
   nb = request2size(bytes+1);
@@ -4270,11 +4365,15 @@ memalign_check(alignment, bytes) size_t alignment; size_t bytes;
    ptmalloc_init() hasn't completed yet. */
 
 static Void_t*
+#ifdef _LIBC
+malloc_starter(size_t sz, const Void_t *caller)
+#else
 #if __STD_C
 malloc_starter(size_t sz)
 #else
 malloc_starter(sz) size_t sz;
 #endif
+#endif
 {
   mchunkptr victim = chunk_alloc(&main_arena, request2size(sz));
 
@@ -4282,11 +4381,15 @@ malloc_starter(sz) size_t sz;
 }
 
 static void
+#ifdef _LIBC
+free_starter(Void_t* mem, const Void_t *caller)
+#else
 #if __STD_C
 free_starter(Void_t* mem)
 #else
 free_starter(mem) Void_t* mem;
 #endif
+#endif
 {
   mchunkptr p;
 
@@ -4305,11 +4408,15 @@ free_starter(mem) Void_t* mem;
    is active. */
 
 static Void_t*
+#ifdef _LIBC
+malloc_atfork (size_t sz, const Void_t *caller)
+#else
 #if __STD_C
 malloc_atfork(size_t sz)
 #else
 malloc_atfork(sz) size_t sz;
 #endif
+#endif
 {
   Void_t *vptr = NULL;
 
@@ -4328,11 +4435,15 @@ malloc_atfork(sz) size_t sz;
 }
 
 static void
+#ifdef _LIBC
+free_atfork(Void_t* mem, const Void_t *caller)
+#else
 #if __STD_C
 free_atfork(Void_t* mem)
 #else
 free_atfork(mem) Void_t* mem;
 #endif
+#endif
 {
   Void_t *vptr = NULL;
   arena *ar_ptr;
diff --git a/malloc/malloc.h b/malloc/malloc.h
index a72102e607..65381705df 100644
--- a/malloc/malloc.h
+++ b/malloc/malloc.h
@@ -178,8 +178,25 @@ extern __malloc_ptr_t malloc_get_state __MALLOC_P ((void));
    malloc_get_state(). */
 extern int malloc_set_state __MALLOC_P ((__malloc_ptr_t __ptr));
 
-#if defined(__GLIBC__) || defined(MALLOC_HOOKS)
+#ifdef __GLIBC__
+/* Hooks for debugging versions. */
+extern void (*__malloc_initialize_hook) __MALLOC_P ((void));
+extern void (*__free_hook) __MALLOC_P ((__malloc_ptr_t __ptr,
+					__const __malloc_ptr_t));
+extern __malloc_ptr_t (*__malloc_hook) __MALLOC_P ((size_t __size,
+						    __const __malloc_ptr_t));
+extern __malloc_ptr_t (*__realloc_hook) __MALLOC_P ((__malloc_ptr_t __ptr,
+						     size_t __size,
+						     __const __malloc_ptr_t));
+extern __malloc_ptr_t (*__memalign_hook) __MALLOC_P ((size_t __size,
+						      size_t __alignment,
+						      __const __malloc_ptr_t));
+extern void (*__after_morecore_hook) __MALLOC_P ((void));
 
+/* Activate a standard set of debugging hooks. */
+extern void __malloc_check_init __MALLOC_P ((void));
+#else
+#ifdef MALLOC_HOOKS
 /* Hooks for debugging versions. */
 extern void (*__malloc_initialize_hook) __MALLOC_P ((void));
 extern void (*__free_hook) __MALLOC_P ((__malloc_ptr_t __ptr));
@@ -192,7 +209,7 @@ extern void (*__after_morecore_hook) __MALLOC_P ((void));
 
 /* Activate a standard set of debugging hooks. */
 extern void __malloc_check_init __MALLOC_P ((void));
-
+#endif
 #endif
 
 #ifdef __cplusplus
diff --git a/malloc/mcheck.c b/malloc/mcheck.c
index 1a80a56570..47d35f1f1f 100644
--- a/malloc/mcheck.c
+++ b/malloc/mcheck.c
@@ -28,9 +28,10 @@
 #endif
 
 /* Old hook values.  */
-static void (*old_free_hook) __P ((__ptr_t ptr));
-static __ptr_t (*old_malloc_hook) __P ((__malloc_size_t size));
-static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size));
+static void (*old_free_hook) __P ((__ptr_t ptr, __const __ptr_t));
+static __ptr_t (*old_malloc_hook) __P ((__malloc_size_t size, const __ptr_t));
+static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size,
+					 __const __ptr_t));
 
 /* Function to call when something awful happens.  */
 static void (*abortfunc) __P ((enum mcheck_status));
@@ -91,10 +92,11 @@ checkhdr (hdr)
   return status;
 }
 
-static void freehook __P ((__ptr_t));
+static void freehook __P ((__ptr_t, const __ptr_t));
 static void
-freehook (ptr)
+freehook (ptr, caller)
      __ptr_t ptr;
+     const __ptr_t caller;
 {
   if (ptr)
     {
@@ -105,19 +107,27 @@ freehook (ptr)
       ptr = (__ptr_t) hdr;
     }
   __free_hook = old_free_hook;
-  free (ptr);
+  if (old_free_hook != NULL)
+    (*old_free_hook) (ptr, caller);
+  else
+    free (ptr);
   __free_hook = freehook;
 }
 
-static __ptr_t mallochook __P ((__malloc_size_t));
+static __ptr_t mallochook __P ((__malloc_size_t, const __ptr_t));
 static __ptr_t
-mallochook (size)
+mallochook (size, caller)
      __malloc_size_t size;
+     const __ptr_t caller;
 {
   struct hdr *hdr;
 
   __malloc_hook = old_malloc_hook;
-  hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
+  if (old_malloc_hook != NULL)
+    hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1,
+					     caller);
+  else
+    hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
   __malloc_hook = mallochook;
   if (hdr == NULL)
     return NULL;
@@ -129,11 +139,12 @@ mallochook (size)
   return (__ptr_t) (hdr + 1);
 }
 
-static __ptr_t reallochook __P ((__ptr_t, __malloc_size_t));
+static __ptr_t reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
 static __ptr_t
-reallochook (ptr, size)
+reallochook (ptr, size, caller)
      __ptr_t ptr;
      __malloc_size_t size;
+     const __ptr_t caller;
 {
   struct hdr *hdr;
   __malloc_size_t osize;
@@ -155,7 +166,13 @@ reallochook (ptr, size)
   __free_hook = old_free_hook;
   __malloc_hook = old_malloc_hook;
   __realloc_hook = old_realloc_hook;
-  hdr = (struct hdr *) realloc ((__ptr_t) hdr, sizeof (struct hdr) + size + 1);
+  if (old_realloc_hook != NULL)
+    hdr = (struct hdr *) (*old_realloc_hook) ((__ptr_t) hdr,
+					      sizeof (struct hdr) + size + 1,
+					      caller);
+  else
+    hdr = (struct hdr *) realloc ((__ptr_t) hdr,
+				  sizeof (struct hdr) + size + 1);
   __free_hook = freehook;
   __malloc_hook = mallochook;
   __realloc_hook = reallochook;
diff --git a/malloc/mtrace.awk b/malloc/mtrace.awk
deleted file mode 100644
index 06844d1a4b..0000000000
--- a/malloc/mtrace.awk
+++ /dev/null
@@ -1,50 +0,0 @@
-#
-#  Awk program to analyze mtrace.c output.
-#
-{
-  if ($1 == "@") {
-    where = " (" $2 ")"
-    n = 3
-  } else {
-    where = ""
-    n = 1
-  }
-  if ($n == "+") {
-    if (allocated[$(n+1)] != "")
-      print "+", $(n+1), "Alloc", NR, "duplicate:", allocated[$(n+1)], wherewas[$(n+1)], where;
-    else {
-      wherewas[$(n+1)] = where;
-      allocated[$(n+1)] = $(n+2);
-    }
-  } else if ($n == "-") {
-    if (allocated[$(n+1)] != "") {
-      wherewas[$(n+1)] = "";
-      allocated[$(n+1)] = "";
-      if (allocated[$(n+1)] != "")
-	print "DELETE FAILED", $(n+1), allocated[$(n+1)];
-    } else
-      print "-", $(n+1), "Free", NR, "was never alloc'd", where;
-  } else if ($n == "<")	{
-    if (allocated[$(n+1)] != "") {
-      wherewas[$(n+1)] = "";
-      allocated[$(n+1)] = "";
-    } else
-      print "-", $(n+1), "Realloc", NR, "was never alloc'd", where;
-  } else if ($n == ">") {
-    if (allocated[$(n+1)] != "")
-      print "+", $(n+1), "Realloc", NR, "duplicate:", allocated[$(n+1)], where;
-    else {
-      wherewas[$(n+1)] = $(n+2);
-      allocated[$(n+1)] = $(n+2);
-    }
-  } else if ($n == "=") {
-    # Ignore "= Start"
-  } else if ($n == "!") {
-    # Ignore failed realloc attempts for now
-  }
-}
-END {
-  for (x in allocated) 
-    if (allocated[x] != "")
-      print "+", x, allocated[x], wherewas[x];
-}
diff --git a/malloc/mtrace.c b/malloc/mtrace.c
index 3f0cbb9726..aeefd5600e 100644
--- a/malloc/mtrace.c
+++ b/malloc/mtrace.c
@@ -1,5 +1,5 @@
 /* More debugging hooks for `malloc'.
-   Copyright (C) 1991, 1992, 1993, 1994, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1991, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
 		 Written April 2, 1991 by John Gilmore of Cygnus Support.
 		 Based on mcheck.c by Mike Haertel.
 
@@ -28,6 +28,10 @@
 #include <bits/libc-lock.h>
 #endif
 
+#ifdef HAVE_ELF
+#include <link.h>
+#endif
+
 #include <stdio.h>
 
 #ifndef	__GNU_LIBRARY__
@@ -51,9 +55,12 @@ char *_mtrace_file;
 int _mtrace_line;
 
 /* Old hook values.  */
-static void (*tr_old_free_hook) __P ((__ptr_t ptr));
-static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size));
-static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size));
+static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
+static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size,
+					   const __ptr_t));
+static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
+					    __malloc_size_t size,
+					    const __ptr_t));
 
 /* This function is called when the block being alloc'd, realloc'd, or
    freed has an address matching the variable "mallwatch".  In a debugger,
@@ -66,51 +73,77 @@ tr_break ()
 {
 }
 
-static void tr_where __P ((void));
+static void tr_where __P ((const __ptr_t));
 static void
-tr_where ()
+tr_where (caller)
+     const __ptr_t caller;
 {
   if (_mtrace_file)
     {
       fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
       _mtrace_file = NULL;
     }
+  else if (caller != NULL)
+    {
+#ifdef HAVE_ELF
+      Dl_info info;
+      if (_dl_addr (caller, &info))
+	{
+	  fprintf (mallstream, "@ %s%s%s%s%s[%p]",
+		   info.dli_fname ?: "", info.dli_fname ? ":" : "",
+		   info.dli_sname ? "(" : "",
+		   info.dli_sname ?: "", info.dli_sname ? ") " : " ",
+		   caller);
+	}
+      else
+#endif
+	fprintf (mallstream, "@ [%p] ", caller);
+    }
 }
 
-static void tr_freehook __P ((__ptr_t));
+static void tr_freehook __P ((__ptr_t, const __ptr_t));
 static void
-tr_freehook (ptr)
+tr_freehook (ptr, caller)
      __ptr_t ptr;
+     const __ptr_t caller;
 {
-  tr_where ();
-  fprintf (mallstream, "- %p\n", ptr);	/* Be sure to print it first.  */
+  tr_where (caller);
+  /* Be sure to print it first.  */
+  fprintf (mallstream, "- %p\n", ptr);
   if (ptr == mallwatch)
     tr_break ();
   __libc_lock_lock (lock);
   __free_hook = tr_old_free_hook;
-  free (ptr);
+  if (tr_old_free_hook != NULL)
+    (*tr_old_free_hook) (ptr, caller);
+  else
+    free (ptr);
   __free_hook = tr_freehook;
   __libc_lock_unlock (lock);
 }
 
-static __ptr_t tr_mallochook __P ((__malloc_size_t));
+static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
 static __ptr_t
-tr_mallochook (size)
+tr_mallochook (size, caller)
      __malloc_size_t size;
+     const __ptr_t caller;
 {
   __ptr_t hdr;
 
   __libc_lock_lock (lock);
 
   __malloc_hook = tr_old_malloc_hook;
-  hdr = (__ptr_t) malloc (size);
+  if (tr_old_malloc_hook != NULL)
+    hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
+  else
+    hdr = (__ptr_t) malloc (size);
   __malloc_hook = tr_mallochook;
 
   __libc_lock_unlock (lock);
 
-  tr_where ();
+  tr_where (caller);
   /* We could be printing a NULL here; that's OK.  */
-  fprintf (mallstream, "+ %p %lx\n", hdr, (unsigned long)size);
+  fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long)size);
 
   if (hdr == mallwatch)
     tr_break ();
@@ -118,11 +151,12 @@ tr_mallochook (size)
   return hdr;
 }
 
-static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t));
+static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
 static __ptr_t
-tr_reallochook (ptr, size)
+tr_reallochook (ptr, size, caller)
      __ptr_t ptr;
      __malloc_size_t size;
+     const __ptr_t caller;
 {
   __ptr_t hdr;
 
@@ -134,21 +168,24 @@ tr_reallochook (ptr, size)
   __free_hook = tr_old_free_hook;
   __malloc_hook = tr_old_malloc_hook;
   __realloc_hook = tr_old_realloc_hook;
-  hdr = (__ptr_t) realloc (ptr, size);
+  if (tr_old_realloc_hook != NULL)
+    hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
+  else
+    hdr = (__ptr_t) realloc (ptr, size);
   __free_hook = tr_freehook;
   __malloc_hook = tr_mallochook;
   __realloc_hook = tr_reallochook;
 
   __libc_lock_unlock (lock);
 
-  tr_where ();
+  tr_where (caller);
   if (hdr == NULL)
     /* Failed realloc.  */
-    fprintf (mallstream, "! %p %lx\n", ptr, (unsigned long)size);
+    fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long)size);
   else if (ptr == NULL)
-    fprintf (mallstream, "+ %p %lx\n", hdr, (unsigned long)size);
+    fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long)size);
   else
-    fprintf (mallstream, "< %p\n> %p %lx\n", ptr, hdr, (unsigned long)size);
+    fprintf (mallstream, "< %p\n> %p %#lx\n", ptr, hdr, (unsigned long)size);
 
   if (hdr == mallwatch)
     tr_break ();
diff --git a/malloc/mtrace.pl b/malloc/mtrace.pl
new file mode 100644
index 0000000000..46d8425bee
--- /dev/null
+++ b/malloc/mtrace.pl
@@ -0,0 +1,192 @@
+#! @PERL@
+eval "exec @PERL@ -S $0 $*"
+    if 0;
+# Copyright (C) 1997 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1997.
+# Based on the mtrace.awk script.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU Library General Public
+# License along with the GNU C Library; see the file COPYING.LIB.  If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+$VERSION = "@VERSION@";
+$PACKAGE = "libc";
+$progname = $0;
+
+sub usage {
+    print "Usage: mtrace [OPTION]... [Binary] MtraceData\n";
+    print "  --help       print this help, then exit\n";
+    print "  --version    print version number, then exit\n";
+    exit 0;
+}
+
+# We expect two arguments:
+#   #1: the complete path to the binary
+#   #2: the mtrace data filename
+# The usual options are also recognized.
+
+arglist: while (@ARGV) {
+    if ($ARGV[0] eq "--v" || $ARGV[0] eq "--ve" || $ARGV[0] eq "--ver" ||
+	$ARGV[0] eq "--vers" || $ARGV[0] eq "--versi" ||
+	$ARGV[0] eq "--versio" || $ARGV[0] eq "--version") {
+	print "mtrace (GNU $PACKAGE) $VERSION\n";
+	print "Copyright (C) 1997 Free Software Foundation, Inc.\n";
+	print "This is free software; see the source for copying conditions.  There is NO\n";
+	print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
+	print "Written by Ulrich Drepper <drepper\@gnu.ai.mit.edu>\n";
+
+	exit 0;
+    } elsif ($ARGV[0] eq "--h" || $ARGV[0] eq "--he" || $ARGV[0] eq "--hel" ||
+	     $ARGV[0] eq "--help") {
+	&usage;
+    } elsif ($ARGV[0] =~ /^-/) {
+	print "$progname: unrecognized option `$ARGV[0]'\n";
+	print "Try `$progname --help' for more information.\n";
+	exit 1;
+    } else {
+	last arglist;
+    }
+}
+
+if ($#ARGV == 0) {
+    $binary="";
+    $data=$ARGV[0];
+} elsif ($#ARGV == 1) {
+    $binary=$ARGV[0];
+    $data=$ARGV[1];
+} else {
+    die "Wrong number of arguments.";
+}
+
+sub location {
+    my $str = pop(@_);
+    return $str if ($str eq "");
+    if ($str =~ /[[](0x[^]]*)]:(.)*/) {
+	my $addr = $1;
+	my $fct = $2;
+	return $cache{$addr} if (exists $cache{$addr});
+	if ($binary ne "" && open (ADDR, "addr2line -e $binary $addr|")) {
+	    my $line = <ADDR>;
+	    chomp $line;
+	    close (ADDR);
+	    if ($line ne '??:0') {
+		$cache{$addr} = $line;
+		return $cache{$addr};
+	    }
+	}
+	$cache{$addr} = $str = "$fct @ $addr";
+    } elsif ($str =~ /^[[](0x[^]]*)]$/) {
+	my $addr = $1;
+	return $cache{$addr} if (exists $cache{$addr});
+	if ($binary ne "" && open (ADDR, "addr2line -e $binary $addr|")) {
+	    my $line = <ADDR>;
+	    chomp $line;
+	    close (ADDR);
+	    if ($line ne '??:0') {
+		$cache{$addr} = $line;
+		return $cache{$addr};
+	    }
+	}
+	$cache{$addr} = $str = $addr;
+    }
+    return $str;
+}
+
+$nr=0;
+open(DATA, "<$data") || die "Cannot open mtrace data file";
+while (<DATA>) {
+    my @cols = split (' ');
+    my $n, $where;
+    if ($cols[0] eq "@") {
+	# We have address and/or function name.
+	$where=$cols[1];
+	$n=2;
+    } else {
+	$where="";
+	$n=0;
+    }
+
+    $allocaddr=$cols[$n + 1];
+    $howmuch=hex($cols[$n + 2]);
+
+    ++$nr;
+    SWITCH: {
+	if ($cols[$n] eq "+") {
+	    if (defined $allocated{$allocaddr}) {
+		printf ("+ %#010x Alloc %d duplicate: %s %s\n",
+			hex($allocaddr), $nr, $wherewas{$allocaddr}, $where);
+	    } else {
+		$allocated{$allocaddr}=$howmuch;
+		$wherewas{$allocaddr}=&location($where);
+	    }
+	    last SWITCH;
+	}
+	if ($cols[$n] eq "-") {
+	    if (defined $allocated{$allocaddr}) {
+		undef $allocated{$allocaddr};
+		undef $wherewas{$allocaddr};
+	    } else {
+		printf ("- %#010x Free %d was never alloc'd %s\n",
+			hex($allocaddr), $nr, &location($where));
+	    }
+	    last SWITCH;
+	}
+	if ($cols[$n] eq "<") {
+	    if (defined $allocated{$allocaddr}) {
+		undef $allocated{$allocaddr};
+		undef $wherewas{$allocaddr};
+	    } else {
+		printf ("- %#010x Realloc %d was never alloc'd %s\n",
+			hex($allocaddr), $nr, &location($where));
+	    }
+	    last SWITCH;
+	}
+	if ($cols[$n] eq ">") {
+	    if (defined $allocated{$allocaddr}) {
+		printf ("+ %#010x Realloc %d duplicate: %#010x %s %s\n",
+			hex($allocaddr), $nr, $allocated{$allocaddr},
+			$wherewas{$allocaddr}, &location($where));
+	    } else {
+		$allocated{$allocaddr}=$howmuch;
+		$wherewas{$allocaddr}=&location($where);
+	    }
+	    last SWITCH;
+	}
+	if ($cols[$n] eq "=") {
+	    # Ignore "= Start".
+	    last SWITCH;
+	}
+	if ($cols[$n] eq "!") {
+	    # Ignore failed realloc for now.
+	    last SWITCH;
+	}
+    }
+}
+close (DATA);
+
+# Now print all remaining entries.
+@addrs= keys %allocated;
+if ($#addrs >= 0) {
+    print "\nNot freed memory:\n-----------------\n";
+    print ' ' x (@XXX@ - 7), "Address     Size     Caller\n";
+    foreach $addr (sort @addrs) {
+	if (defined $allocated{$addr}) {
+	    printf ("%#0@XXX@x %#8x  at %s\n", hex($addr), $allocated{$addr},
+		    $wherewas{$addr});
+	}
+    }
+}
+
+exit 0;