Define function release_libc_mem which calls the __libc_subfreeres handler.
[kopensolaris-gnu/glibc.git] / malloc / mtrace.c
1 /* More debugging hooks for `malloc'.
2    Copyright (C) 1991, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
3                  Written April 2, 1991 by John Gilmore of Cygnus Support.
4                  Based on mcheck.c by Mike Haertel.
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with this library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.
20
21    The author may be reached (Email) at the address mike@ai.mit.edu,
22    or (US mail) as Mike Haertel c/o Free Software Foundation.  */
23
24 #ifndef _MALLOC_INTERNAL
25 #define _MALLOC_INTERNAL
26 #include <malloc.h>
27 #include <mcheck.h>
28 #include <bits/libc-lock.h>
29 #endif
30
31 #ifdef HAVE_ELF
32 #include <link.h>
33 #endif
34
35 #include <stdio.h>
36
37 #ifndef __GNU_LIBRARY__
38 extern char *getenv ();
39 #else
40 #include <stdlib.h>
41 #endif
42
43 static FILE *mallstream;
44 static char mallenv[]= "MALLOC_TRACE";
45 static char mallbuf[BUFSIZ];    /* Buffer for the output.  */
46
47 __libc_lock_define_initialized (static, lock);
48
49 /* Address to breakpoint on accesses to... */
50 __ptr_t mallwatch;
51
52 /* File name and line number information, for callers that had
53    the foresight to call through a macro.  */
54 char *_mtrace_file;
55 int _mtrace_line;
56
57 /* Old hook values.  */
58 static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
59 static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size,
60                                            const __ptr_t));
61 static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
62                                             __malloc_size_t size,
63                                             const __ptr_t));
64
65 /* This function is called when the block being alloc'd, realloc'd, or
66    freed has an address matching the variable "mallwatch".  In a debugger,
67    set "mallwatch" to the address of interest, then put a breakpoint on
68    tr_break.  */
69
70 void tr_break __P ((void));
71 void
72 tr_break ()
73 {
74 }
75
76 static void tr_where __P ((const __ptr_t));
77 static void
78 tr_where (caller)
79      const __ptr_t caller;
80 {
81   if (_mtrace_file)
82     {
83       fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
84       _mtrace_file = NULL;
85     }
86   else if (caller != NULL)
87     {
88 #ifdef HAVE_ELF
89       Dl_info info;
90       if (_dl_addr (caller, &info))
91         {
92           fprintf (mallstream, "@ %s%s%s%s%s[%p]",
93                    info.dli_fname ?: "", info.dli_fname ? ":" : "",
94                    info.dli_sname ? "(" : "",
95                    info.dli_sname ?: "", info.dli_sname ? ") " : " ",
96                    caller);
97         }
98       else
99 #endif
100         fprintf (mallstream, "@ [%p] ", caller);
101     }
102 }
103
104 static void tr_freehook __P ((__ptr_t, const __ptr_t));
105 static void
106 tr_freehook (ptr, caller)
107      __ptr_t ptr;
108      const __ptr_t caller;
109 {
110   tr_where (caller);
111   /* Be sure to print it first.  */
112   fprintf (mallstream, "- %p\n", ptr);
113   if (ptr == mallwatch)
114     tr_break ();
115   __libc_lock_lock (lock);
116   __free_hook = tr_old_free_hook;
117   if (tr_old_free_hook != NULL)
118     (*tr_old_free_hook) (ptr, caller);
119   else
120     free (ptr);
121   __free_hook = tr_freehook;
122   __libc_lock_unlock (lock);
123 }
124
125 static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
126 static __ptr_t
127 tr_mallochook (size, caller)
128      __malloc_size_t size;
129      const __ptr_t caller;
130 {
131   __ptr_t hdr;
132
133   __libc_lock_lock (lock);
134
135   __malloc_hook = tr_old_malloc_hook;
136   if (tr_old_malloc_hook != NULL)
137     hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
138   else
139     hdr = (__ptr_t) malloc (size);
140   __malloc_hook = tr_mallochook;
141
142   __libc_lock_unlock (lock);
143
144   tr_where (caller);
145   /* We could be printing a NULL here; that's OK.  */
146   fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long)size);
147
148   if (hdr == mallwatch)
149     tr_break ();
150
151   return hdr;
152 }
153
154 static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
155 static __ptr_t
156 tr_reallochook (ptr, size, caller)
157      __ptr_t ptr;
158      __malloc_size_t size;
159      const __ptr_t caller;
160 {
161   __ptr_t hdr;
162
163   if (ptr == mallwatch)
164     tr_break ();
165
166   __libc_lock_lock (lock);
167
168   __free_hook = tr_old_free_hook;
169   __malloc_hook = tr_old_malloc_hook;
170   __realloc_hook = tr_old_realloc_hook;
171   if (tr_old_realloc_hook != NULL)
172     hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
173   else
174     hdr = (__ptr_t) realloc (ptr, size);
175   __free_hook = tr_freehook;
176   __malloc_hook = tr_mallochook;
177   __realloc_hook = tr_reallochook;
178
179   __libc_lock_unlock (lock);
180
181   tr_where (caller);
182   if (hdr == NULL)
183     /* Failed realloc.  */
184     fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long)size);
185   else if (ptr == NULL)
186     fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long)size);
187   else
188     fprintf (mallstream, "< %p\n> %p %#lx\n", ptr, hdr, (unsigned long)size);
189
190   if (hdr == mallwatch)
191     tr_break ();
192
193   return hdr;
194 }
195
196
197 #ifdef _LIBC
198 extern void __libc_freeres (void);
199
200 /* This function gets called to make sure all memory the library
201    allocates get freed and so does not irritate the user when studying
202    the mtrace output.  */
203 static void
204 release_libc_mem (void)
205 {
206   /* Only call the free function if we still are running in mtrace mode.  */
207   if (mallstream != NULL)
208     __libc_freeres ();
209 }
210 #endif
211
212
213 /* We enable tracing if either the environment variable MALLOC_TRACE
214    is set, or if the variable mallwatch has been patched to an address
215    that the debugging user wants us to stop on.  When patching mallwatch,
216    don't forget to set a breakpoint on tr_break!  */
217
218 void
219 mtrace ()
220 {
221 #ifdef _LIBC
222   static int added_atexit_handler = 0;
223 #endif
224   char *mallfile;
225
226   /* Don't panic if we're called more than once.  */
227   if (mallstream != NULL)
228     return;
229
230 #ifdef _LIBC
231   /* When compiling the GNU libc we use the secure getenv function
232      which prevents the misuse in case of SUID or SGID enabled
233      programs.  */
234   mallfile = __secure_getenv (mallenv);
235 #else
236   mallfile = getenv (mallenv);
237 #endif
238   if (mallfile != NULL || mallwatch != NULL)
239     {
240       mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
241       if (mallstream != NULL)
242         {
243           /* Be sure it doesn't malloc its buffer!  */
244           setbuf (mallstream, mallbuf);
245           fprintf (mallstream, "= Start\n");
246           tr_old_free_hook = __free_hook;
247           __free_hook = tr_freehook;
248           tr_old_malloc_hook = __malloc_hook;
249           __malloc_hook = tr_mallochook;
250           tr_old_realloc_hook = __realloc_hook;
251           __realloc_hook = tr_reallochook;
252 #ifdef _LIBC
253           if (!added_atexit_handler)
254             {
255               added_atexit_handler = 1;
256               atexit (release_libc_mem);
257             }
258 #endif
259         }
260     }
261 }
262
263 void
264 muntrace ()
265 {
266   if (mallstream == NULL)
267     return;
268
269   fprintf (mallstream, "= End\n");
270   fclose (mallstream);
271   mallstream = NULL;
272   __free_hook = tr_old_free_hook;
273   __malloc_hook = tr_old_malloc_hook;
274   __realloc_hook = tr_old_realloc_hook;
275 }