2002-09-17 Roland McGrath <roland@redhat.com>
[kopensolaris-gnu/glibc.git] / malloc / mtrace.c
index cdd7432..d9960bd 100644 (file)
@@ -1,25 +1,23 @@
 /* More debugging hooks for `malloc'.
 /* More debugging hooks for `malloc'.
-   Copyright (C) 1991, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
+   Copyright (C) 1991-1994,1996-2001,2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
                 Written April 2, 1991 by John Gilmore of Cygnus Support.
                 Based on mcheck.c by Mike Haertel.
 
                 Written April 2, 1991 by John Gilmore of Cygnus Support.
                 Based on mcheck.c by Mike Haertel.
 
-   This 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 free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
 
 
-   This library is distributed in the hope that it will be useful,
+   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
    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.
+   Lesser General Public License for more details.
 
 
-   You should have received a copy of the GNU Library General Public
-   License along with this 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.
-
-   The author may be reached (Email) at the address mike@ai.mit.edu,
-   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
 
 #ifndef        _MALLOC_INTERNAL
 #define        _MALLOC_INTERNAL
 
 #ifndef        _MALLOC_INTERNAL
 #define        _MALLOC_INTERNAL
 #include <bits/libc-lock.h>
 #endif
 
 #include <bits/libc-lock.h>
 #endif
 
-#ifdef HAVE_ELF
-#include <link.h>
-#endif
-
+#include <dlfcn.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdio.h>
-
-#ifndef        __GNU_LIBRARY__
-extern char *getenv ();
-#else
+#include <string.h>
 #include <stdlib.h>
 #include <stdlib.h>
+
+#include <stdio-common/_itoa.h>
+
+#ifdef _LIBC
+# include <libc-internal.h>
+
+# include <libio/iolibio.h>
+# define setvbuf(s, b, f, l) INTUSE(_IO_setvbuf) (s, b, f, l)
+# define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
+#endif
+
+#ifndef attribute_hidden
+# define attribute_hidden
 #endif
 
 #endif
 
+#define TRACE_BUFFER_SIZE 512
+
 static FILE *mallstream;
 static const char mallenv[]= "MALLOC_TRACE";
 static FILE *mallstream;
 static const char mallenv[]= "MALLOC_TRACE";
-static char mallbuf[BUFSIZ];   /* Buffer for the output.  */
+static char malloc_trace_buffer[TRACE_BUFFER_SIZE];
 
 __libc_lock_define_initialized (static, lock);
 
 /* Address to breakpoint on accesses to... */
 __ptr_t mallwatch;
 
 
 __libc_lock_define_initialized (static, lock);
 
 /* Address to breakpoint on accesses to... */
 __ptr_t mallwatch;
 
+#ifdef USE_MTRACE_FILE
 /* File name and line number information, for callers that had
    the foresight to call through a macro.  */
 char *_mtrace_file;
 int _mtrace_line;
 /* File name and line number information, for callers that had
    the foresight to call through a macro.  */
 char *_mtrace_file;
 int _mtrace_line;
+#endif
 
 /* Old hook values.  */
 static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
 
 /* Old hook values.  */
 static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
@@ -79,22 +89,41 @@ internal_function
 tr_where (caller)
      const __ptr_t caller;
 {
 tr_where (caller)
      const __ptr_t caller;
 {
+#ifdef USE_MTRACE_FILE
   if (_mtrace_file)
     {
       fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
       _mtrace_file = NULL;
     }
   if (_mtrace_file)
     {
       fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
       _mtrace_file = NULL;
     }
-  else if (caller != NULL)
+  else
+#endif
+    if (caller != NULL)
     {
 #ifdef HAVE_ELF
       Dl_info info;
       if (_dl_addr (caller, &info))
        {
     {
 #ifdef HAVE_ELF
       Dl_info info;
       if (_dl_addr (caller, &info))
        {
-         fprintf (mallstream, "@ %s%s%s%s%s[%p]",
+         char *buf = (char *) "";
+         if (info.dli_sname != NULL)
+           {
+             size_t len = strlen (info.dli_sname);
+             buf = alloca (len + 6 + 2 * sizeof (void *));
+
+             buf[0] = '(';
+             __stpcpy (_fitoa (caller >= (const __ptr_t) info.dli_saddr
+                               ? caller - (const __ptr_t) info.dli_saddr
+                               : (const __ptr_t) info.dli_saddr - caller,
+                               __stpcpy (__mempcpy (buf + 1, info.dli_sname,
+                                                    len),
+                                         caller >= (__ptr_t) info.dli_saddr
+                                         ? "+0x" : "-0x"),
+                               16, 0),
+                       ")");
+           }
+
+         fprintf (mallstream, "@ %s%s%s[%p] ",
                   info.dli_fname ?: "", info.dli_fname ? ":" : "",
                   info.dli_fname ?: "", info.dli_fname ? ":" : "",
-                  info.dli_sname ? "(" : "",
-                  info.dli_sname ?: "", info.dli_sname ? ") " : " ",
-                  caller);
+                  buf, caller);
        }
       else
 #endif
        }
       else
 #endif
@@ -108,9 +137,13 @@ tr_freehook (ptr, caller)
      __ptr_t ptr;
      const __ptr_t caller;
 {
      __ptr_t ptr;
      const __ptr_t caller;
 {
+  if (ptr == NULL)
+    return;
+  __libc_lock_lock (lock);
   tr_where (caller);
   /* Be sure to print it first.  */
   fprintf (mallstream, "- %p\n", ptr);
   tr_where (caller);
   /* Be sure to print it first.  */
   fprintf (mallstream, "- %p\n", ptr);
+  __libc_lock_unlock (lock);
   if (ptr == mallwatch)
     tr_break ();
   __libc_lock_lock (lock);
   if (ptr == mallwatch)
     tr_break ();
   __libc_lock_lock (lock);
@@ -140,11 +173,11 @@ tr_mallochook (size, caller)
     hdr = (__ptr_t) malloc (size);
   __malloc_hook = tr_mallochook;
 
     hdr = (__ptr_t) malloc (size);
   __malloc_hook = tr_mallochook;
 
-  __libc_lock_unlock (lock);
-
   tr_where (caller);
   /* We could be printing a NULL here; that's OK.  */
   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 int) size);
+
+  __libc_lock_unlock (lock);
 
   if (hdr == mallwatch)
     tr_break ();
 
   if (hdr == mallwatch)
     tr_break ();
@@ -177,16 +210,20 @@ tr_reallochook (ptr, size, caller)
   __malloc_hook = tr_mallochook;
   __realloc_hook = tr_reallochook;
 
   __malloc_hook = tr_mallochook;
   __realloc_hook = tr_reallochook;
 
-  __libc_lock_unlock (lock);
-
   tr_where (caller);
   if (hdr == NULL)
     /* Failed realloc.  */
   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 int) size);
   else if (ptr == NULL)
   else if (ptr == NULL)
-    fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long)size);
+    fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
   else
   else
-    fprintf (mallstream, "< %p\n> %p %#lx\n", ptr, hdr, (unsigned long)size);
+    {
+      fprintf (mallstream, "< %p\n", ptr);
+      tr_where (caller);
+      fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
+    }
+
+  __libc_lock_unlock (lock);
 
   if (hdr == mallwatch)
     tr_break ();
 
   if (hdr == mallwatch)
     tr_break ();
@@ -196,7 +233,6 @@ tr_reallochook (ptr, size, caller)
 
 
 #ifdef _LIBC
 
 
 #ifdef _LIBC
-extern void __libc_freeres (void);
 
 /* This function gets called to make sure all memory the library
    allocates get freed and so does not irritate the user when studying
 
 /* This function gets called to make sure all memory the library
    allocates get freed and so does not irritate the user when studying
@@ -220,7 +256,7 @@ void
 mtrace ()
 {
 #ifdef _LIBC
 mtrace ()
 {
 #ifdef _LIBC
-  static int added_atexit_handler = 0;
+  static int added_atexit_handler;
 #endif
   char *mallfile;
 
 #endif
   char *mallfile;
 
@@ -241,8 +277,15 @@ mtrace ()
       mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
       if (mallstream != NULL)
        {
       mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
       if (mallstream != NULL)
        {
+         /* Make sure we close the file descriptor on exec.  */
+         int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
+         if (flags >= 0)
+           {
+             flags |= FD_CLOEXEC;
+             __fcntl (fileno (mallstream), F_SETFD, flags);
+           }
          /* Be sure it doesn't malloc its buffer!  */
          /* Be sure it doesn't malloc its buffer!  */
-         setbuf (mallstream, mallbuf);
+         setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
          fprintf (mallstream, "= Start\n");
          tr_old_free_hook = __free_hook;
          __free_hook = tr_freehook;
          fprintf (mallstream, "= Start\n");
          tr_old_free_hook = __free_hook;
          __free_hook = tr_freehook;
@@ -253,8 +296,10 @@ mtrace ()
 #ifdef _LIBC
          if (!added_atexit_handler)
            {
 #ifdef _LIBC
          if (!added_atexit_handler)
            {
+             extern void *__dso_handle __attribute__ ((__weak__));
              added_atexit_handler = 1;
              added_atexit_handler = 1;
-             atexit (release_libc_mem);
+             __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
+                            &__dso_handle ? __dso_handle : NULL);
            }
 #endif
        }
            }
 #endif
        }