Adjust malloc_printf_nc callers.
[kopensolaris-gnu/glibc.git] / malloc / mtrace.c
1 /* More debugging hooks for `malloc'.
2    Copyright (C) 1991-1994,1996-2003, 2004 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4                  Written April 2, 1991 by John Gilmore of Cygnus Support.
5                  Based on mcheck.c by Mike Haertel.
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, write to the Free
19    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20    02111-1307 USA.  */
21
22 #ifndef _MALLOC_INTERNAL
23 #define _MALLOC_INTERNAL
24 #include <malloc.h>
25 #include <mcheck.h>
26 #include <bits/libc-lock.h>
27 #endif
28
29 #include <dlfcn.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34
35 #include <stdio-common/_itoa.h>
36
37 #ifdef _LIBC
38 # include <libc-internal.h>
39
40 # include <libio/iolibio.h>
41 # define setvbuf(s, b, f, l) INTUSE(_IO_setvbuf) (s, b, f, l)
42 # define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
43 #endif
44
45 #ifndef attribute_hidden
46 # define attribute_hidden
47 #endif
48
49 #define TRACE_BUFFER_SIZE 512
50
51 static FILE *mallstream;
52 static const char mallenv[]= "MALLOC_TRACE";
53 static char *malloc_trace_buffer;
54
55 __libc_lock_define_initialized (static, lock);
56
57 /* Address to breakpoint on accesses to... */
58 __ptr_t mallwatch;
59
60 #ifdef USE_MTRACE_FILE
61 /* File name and line number information, for callers that had
62    the foresight to call through a macro.  */
63 char *_mtrace_file;
64 int _mtrace_line;
65 #endif
66
67 /* Old hook values.  */
68 static void (*tr_old_free_hook) (__ptr_t ptr, const __ptr_t);
69 static __ptr_t (*tr_old_malloc_hook) (__malloc_size_t size, const __ptr_t);
70 static __ptr_t (*tr_old_realloc_hook) (__ptr_t ptr, __malloc_size_t size,
71                                        const __ptr_t);
72 static __ptr_t (*tr_old_memalign_hook) (__malloc_size_t __alignment,
73                                         __malloc_size_t __size,
74                                         __const __ptr_t);
75
76 /* This function is called when the block being alloc'd, realloc'd, or
77    freed has an address matching the variable "mallwatch".  In a debugger,
78    set "mallwatch" to the address of interest, then put a breakpoint on
79    tr_break.  */
80
81 extern void tr_break __P ((void));
82 libc_hidden_proto (tr_break)
83 void
84 tr_break ()
85 {
86 }
87 libc_hidden_def (tr_break)
88
89 static void tr_where __P ((const __ptr_t)) internal_function;
90 static void
91 internal_function
92 tr_where (caller)
93      const __ptr_t caller;
94 {
95 #ifdef USE_MTRACE_FILE
96   if (_mtrace_file)
97     {
98       fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
99       _mtrace_file = NULL;
100     }
101   else
102 #endif
103     if (caller != NULL)
104     {
105 #ifdef HAVE_ELF
106       Dl_info info;
107       if (_dl_addr (caller, &info, NULL, NULL))
108         {
109           char *buf = (char *) "";
110           if (info.dli_sname != NULL)
111             {
112               size_t len = strlen (info.dli_sname);
113               buf = alloca (len + 6 + 2 * sizeof (void *));
114
115               buf[0] = '(';
116               __stpcpy (_fitoa (caller >= (const __ptr_t) info.dli_saddr
117                                 ? caller - (const __ptr_t) info.dli_saddr
118                                 : (const __ptr_t) info.dli_saddr - caller,
119                                 __stpcpy (__mempcpy (buf + 1, info.dli_sname,
120                                                      len),
121                                           caller >= (__ptr_t) info.dli_saddr
122                                           ? "+0x" : "-0x"),
123                                 16, 0),
124                         ")");
125             }
126
127           fprintf (mallstream, "@ %s%s%s[%p] ",
128                    info.dli_fname ?: "", info.dli_fname ? ":" : "",
129                    buf, caller);
130         }
131       else
132 #endif
133         fprintf (mallstream, "@ [%p] ", caller);
134     }
135 }
136
137 static void tr_freehook __P ((__ptr_t, const __ptr_t));
138 static void
139 tr_freehook (ptr, caller)
140      __ptr_t ptr;
141      const __ptr_t caller;
142 {
143   if (ptr == NULL)
144     return;
145   __libc_lock_lock (lock);
146   tr_where (caller);
147   /* Be sure to print it first.  */
148   fprintf (mallstream, "- %p\n", ptr);
149   __libc_lock_unlock (lock);
150   if (ptr == mallwatch)
151     tr_break ();
152   __libc_lock_lock (lock);
153   __free_hook = tr_old_free_hook;
154   if (tr_old_free_hook != NULL)
155     (*tr_old_free_hook) (ptr, caller);
156   else
157     free (ptr);
158   __free_hook = tr_freehook;
159   __libc_lock_unlock (lock);
160 }
161
162 static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
163 static __ptr_t
164 tr_mallochook (size, caller)
165      __malloc_size_t size;
166      const __ptr_t caller;
167 {
168   __ptr_t hdr;
169
170   __libc_lock_lock (lock);
171
172   __malloc_hook = tr_old_malloc_hook;
173   if (tr_old_malloc_hook != NULL)
174     hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
175   else
176     hdr = (__ptr_t) malloc (size);
177   __malloc_hook = tr_mallochook;
178
179   tr_where (caller);
180   /* We could be printing a NULL here; that's OK.  */
181   fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
182
183   __libc_lock_unlock (lock);
184
185   if (hdr == mallwatch)
186     tr_break ();
187
188   return hdr;
189 }
190
191 static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
192 static __ptr_t
193 tr_reallochook (ptr, size, caller)
194      __ptr_t ptr;
195      __malloc_size_t size;
196      const __ptr_t caller;
197 {
198   __ptr_t hdr;
199
200   if (ptr == mallwatch)
201     tr_break ();
202
203   __libc_lock_lock (lock);
204
205   __free_hook = tr_old_free_hook;
206   __malloc_hook = tr_old_malloc_hook;
207   __realloc_hook = tr_old_realloc_hook;
208   if (tr_old_realloc_hook != NULL)
209     hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
210   else
211     hdr = (__ptr_t) realloc (ptr, size);
212   __free_hook = tr_freehook;
213   __malloc_hook = tr_mallochook;
214   __realloc_hook = tr_reallochook;
215
216   tr_where (caller);
217   if (hdr == NULL)
218     /* Failed realloc.  */
219     fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
220   else if (ptr == NULL)
221     fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
222   else
223     {
224       fprintf (mallstream, "< %p\n", ptr);
225       tr_where (caller);
226       fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
227     }
228
229   __libc_lock_unlock (lock);
230
231   if (hdr == mallwatch)
232     tr_break ();
233
234   return hdr;
235 }
236
237 static __ptr_t tr_memalignhook __P ((__malloc_size_t, __malloc_size_t,
238                                      const __ptr_t));
239 static __ptr_t
240 tr_memalignhook (alignment, size, caller)
241      __malloc_size_t alignment, size;
242      const __ptr_t caller;
243 {
244   __ptr_t hdr;
245
246   __libc_lock_lock (lock);
247
248   __memalign_hook = tr_old_memalign_hook;
249   __malloc_hook = tr_old_malloc_hook;
250   if (tr_old_memalign_hook != NULL)
251     hdr = (__ptr_t) (*tr_old_memalign_hook) (alignment, size, caller);
252   else
253     hdr = (__ptr_t) memalign (alignment, size);
254   __memalign_hook = tr_memalignhook;
255   __malloc_hook = tr_mallochook;
256
257   tr_where (caller);
258   /* We could be printing a NULL here; that's OK.  */
259   fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
260
261   __libc_lock_unlock (lock);
262
263   if (hdr == mallwatch)
264     tr_break ();
265
266   return hdr;
267 }
268
269
270
271 #ifdef _LIBC
272
273 /* This function gets called to make sure all memory the library
274    allocates get freed and so does not irritate the user when studying
275    the mtrace output.  */
276 static void __libc_freeres_fn_section
277 release_libc_mem (void)
278 {
279   /* Only call the free function if we still are running in mtrace mode.  */
280   if (mallstream != NULL)
281     __libc_freeres ();
282 }
283 #endif
284
285
286 /* We enable tracing if either the environment variable MALLOC_TRACE
287    is set, or if the variable mallwatch has been patched to an address
288    that the debugging user wants us to stop on.  When patching mallwatch,
289    don't forget to set a breakpoint on tr_break!  */
290
291 void
292 mtrace ()
293 {
294 #ifdef _LIBC
295   static int added_atexit_handler;
296 #endif
297   char *mallfile;
298
299   /* Don't panic if we're called more than once.  */
300   if (mallstream != NULL)
301     return;
302
303 #ifdef _LIBC
304   /* When compiling the GNU libc we use the secure getenv function
305      which prevents the misuse in case of SUID or SGID enabled
306      programs.  */
307   mallfile = __secure_getenv (mallenv);
308 #else
309   mallfile = getenv (mallenv);
310 #endif
311   if (mallfile != NULL || mallwatch != NULL)
312     {
313       char *mtb = malloc (TRACE_BUFFER_SIZE);
314       if (mtb == NULL)
315         return;
316
317       mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wc");
318       if (mallstream != NULL)
319         {
320           /* Make sure we close the file descriptor on exec.  */
321           int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
322           if (flags >= 0)
323             {
324               flags |= FD_CLOEXEC;
325               __fcntl (fileno (mallstream), F_SETFD, flags);
326             }
327           /* Be sure it doesn't malloc its buffer!  */
328           malloc_trace_buffer = mtb;
329           setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
330           fprintf (mallstream, "= Start\n");
331           tr_old_free_hook = __free_hook;
332           __free_hook = tr_freehook;
333           tr_old_malloc_hook = __malloc_hook;
334           __malloc_hook = tr_mallochook;
335           tr_old_realloc_hook = __realloc_hook;
336           __realloc_hook = tr_reallochook;
337           tr_old_memalign_hook = __memalign_hook;
338           __memalign_hook = tr_memalignhook;
339 #ifdef _LIBC
340           if (!added_atexit_handler)
341             {
342               extern void *__dso_handle __attribute__ ((__weak__));
343               added_atexit_handler = 1;
344               __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
345                              &__dso_handle ? __dso_handle : NULL);
346             }
347 #endif
348         }
349       else
350         free (mtb);
351     }
352 }
353
354 void
355 muntrace ()
356 {
357   if (mallstream == NULL)
358     return;
359
360   fprintf (mallstream, "= End\n");
361   fclose (mallstream);
362   mallstream = NULL;
363   __free_hook = tr_old_free_hook;
364   __malloc_hook = tr_old_malloc_hook;
365   __realloc_hook = tr_old_realloc_hook;
366   __memalign_hook = tr_old_memalign_hook;
367 }