cdd7432a76d0913833cbd9eb10cb920d990ce158
[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 const 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)) internal_function;
77 static void
78 internal_function
79 tr_where (caller)
80      const __ptr_t caller;
81 {
82   if (_mtrace_file)
83     {
84       fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
85       _mtrace_file = NULL;
86     }
87   else if (caller != NULL)
88     {
89 #ifdef HAVE_ELF
90       Dl_info info;
91       if (_dl_addr (caller, &info))
92         {
93           fprintf (mallstream, "@ %s%s%s%s%s[%p]",
94                    info.dli_fname ?: "", info.dli_fname ? ":" : "",
95                    info.dli_sname ? "(" : "",
96                    info.dli_sname ?: "", info.dli_sname ? ") " : " ",
97                    caller);
98         }
99       else
100 #endif
101         fprintf (mallstream, "@ [%p] ", caller);
102     }
103 }
104
105 static void tr_freehook __P ((__ptr_t, const __ptr_t));
106 static void
107 tr_freehook (ptr, caller)
108      __ptr_t ptr;
109      const __ptr_t caller;
110 {
111   tr_where (caller);
112   /* Be sure to print it first.  */
113   fprintf (mallstream, "- %p\n", ptr);
114   if (ptr == mallwatch)
115     tr_break ();
116   __libc_lock_lock (lock);
117   __free_hook = tr_old_free_hook;
118   if (tr_old_free_hook != NULL)
119     (*tr_old_free_hook) (ptr, caller);
120   else
121     free (ptr);
122   __free_hook = tr_freehook;
123   __libc_lock_unlock (lock);
124 }
125
126 static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
127 static __ptr_t
128 tr_mallochook (size, caller)
129      __malloc_size_t size;
130      const __ptr_t caller;
131 {
132   __ptr_t hdr;
133
134   __libc_lock_lock (lock);
135
136   __malloc_hook = tr_old_malloc_hook;
137   if (tr_old_malloc_hook != NULL)
138     hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
139   else
140     hdr = (__ptr_t) malloc (size);
141   __malloc_hook = tr_mallochook;
142
143   __libc_lock_unlock (lock);
144
145   tr_where (caller);
146   /* We could be printing a NULL here; that's OK.  */
147   fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long)size);
148
149   if (hdr == mallwatch)
150     tr_break ();
151
152   return hdr;
153 }
154
155 static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
156 static __ptr_t
157 tr_reallochook (ptr, size, caller)
158      __ptr_t ptr;
159      __malloc_size_t size;
160      const __ptr_t caller;
161 {
162   __ptr_t hdr;
163
164   if (ptr == mallwatch)
165     tr_break ();
166
167   __libc_lock_lock (lock);
168
169   __free_hook = tr_old_free_hook;
170   __malloc_hook = tr_old_malloc_hook;
171   __realloc_hook = tr_old_realloc_hook;
172   if (tr_old_realloc_hook != NULL)
173     hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
174   else
175     hdr = (__ptr_t) realloc (ptr, size);
176   __free_hook = tr_freehook;
177   __malloc_hook = tr_mallochook;
178   __realloc_hook = tr_reallochook;
179
180   __libc_lock_unlock (lock);
181
182   tr_where (caller);
183   if (hdr == NULL)
184     /* Failed realloc.  */
185     fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long)size);
186   else if (ptr == NULL)
187     fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long)size);
188   else
189     fprintf (mallstream, "< %p\n> %p %#lx\n", ptr, hdr, (unsigned long)size);
190
191   if (hdr == mallwatch)
192     tr_break ();
193
194   return hdr;
195 }
196
197
198 #ifdef _LIBC
199 extern void __libc_freeres (void);
200
201 /* This function gets called to make sure all memory the library
202    allocates get freed and so does not irritate the user when studying
203    the mtrace output.  */
204 static void
205 release_libc_mem (void)
206 {
207   /* Only call the free function if we still are running in mtrace mode.  */
208   if (mallstream != NULL)
209     __libc_freeres ();
210 }
211 #endif
212
213
214 /* We enable tracing if either the environment variable MALLOC_TRACE
215    is set, or if the variable mallwatch has been patched to an address
216    that the debugging user wants us to stop on.  When patching mallwatch,
217    don't forget to set a breakpoint on tr_break!  */
218
219 void
220 mtrace ()
221 {
222 #ifdef _LIBC
223   static int added_atexit_handler = 0;
224 #endif
225   char *mallfile;
226
227   /* Don't panic if we're called more than once.  */
228   if (mallstream != NULL)
229     return;
230
231 #ifdef _LIBC
232   /* When compiling the GNU libc we use the secure getenv function
233      which prevents the misuse in case of SUID or SGID enabled
234      programs.  */
235   mallfile = __secure_getenv (mallenv);
236 #else
237   mallfile = getenv (mallenv);
238 #endif
239   if (mallfile != NULL || mallwatch != NULL)
240     {
241       mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
242       if (mallstream != NULL)
243         {
244           /* Be sure it doesn't malloc its buffer!  */
245           setbuf (mallstream, mallbuf);
246           fprintf (mallstream, "= Start\n");
247           tr_old_free_hook = __free_hook;
248           __free_hook = tr_freehook;
249           tr_old_malloc_hook = __malloc_hook;
250           __malloc_hook = tr_mallochook;
251           tr_old_realloc_hook = __realloc_hook;
252           __realloc_hook = tr_reallochook;
253 #ifdef _LIBC
254           if (!added_atexit_handler)
255             {
256               added_atexit_handler = 1;
257               atexit (release_libc_mem);
258             }
259 #endif
260         }
261     }
262 }
263
264 void
265 muntrace ()
266 {
267   if (mallstream == NULL)
268     return;
269
270   fprintf (mallstream, "= End\n");
271   fclose (mallstream);
272   mallstream = NULL;
273   __free_hook = tr_old_free_hook;
274   __malloc_hook = tr_old_malloc_hook;
275   __realloc_hook = tr_old_realloc_hook;
276 }