Updated to fedora-glibc-20080516T2152
[glibc.git] / malloc / mtrace.c
blob139ebc8153cc65789bb4de8295cf725b31902956
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.
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.
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.
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. */
22 #ifndef _MALLOC_INTERNAL
23 #define _MALLOC_INTERNAL
24 #include <malloc.h>
25 #include <mcheck.h>
26 #include <bits/libc-lock.h>
27 #endif
29 #include <dlfcn.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
35 #include <stdio-common/_itoa.h>
37 #ifdef _LIBC
38 # include <libc-internal.h>
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 extern __typeof (malloc) __libc_malloc;
44 extern __typeof (free) __libc_free;
45 extern __typeof (realloc) __libc_realloc;
46 libc_hidden_proto (__libc_malloc)
47 libc_hidden_proto (__libc_realloc)
48 libc_hidden_proto (__libc_free)
49 libc_hidden_proto (__libc_memalign)
50 #else
51 # define __libc_malloc(sz) malloc (sz)
52 # define __libc_free(ptr) free (ptr)
53 # define __libc_realloc(ptr, sz) realloc (ptr, sz)
54 # define __libc_memalign(al, sz) memalign (al, sz)
55 #endif
57 #ifndef attribute_hidden
58 # define attribute_hidden
59 #endif
61 #define TRACE_BUFFER_SIZE 512
63 static FILE *mallstream;
64 static const char mallenv[]= "MALLOC_TRACE";
65 static char *malloc_trace_buffer;
67 __libc_lock_define_initialized (static, lock);
69 /* Address to breakpoint on accesses to... */
70 __ptr_t mallwatch;
72 #ifdef USE_MTRACE_FILE
73 /* File name and line number information, for callers that had
74 the foresight to call through a macro. */
75 char *_mtrace_file;
76 int _mtrace_line;
77 #endif
79 /* Old hook values. */
80 static void (*tr_old_free_hook) (__ptr_t ptr, const __ptr_t);
81 static __ptr_t (*tr_old_malloc_hook) (__malloc_size_t size, const __ptr_t);
82 static __ptr_t (*tr_old_realloc_hook) (__ptr_t ptr, __malloc_size_t size,
83 const __ptr_t);
84 static __ptr_t (*tr_old_memalign_hook) (__malloc_size_t __alignment,
85 __malloc_size_t __size,
86 __const __ptr_t);
88 /* This function is called when the block being alloc'd, realloc'd, or
89 freed has an address matching the variable "mallwatch". In a debugger,
90 set "mallwatch" to the address of interest, then put a breakpoint on
91 tr_break. */
93 extern void tr_break (void) __THROW;
94 libc_hidden_proto (tr_break)
95 void
96 tr_break ()
99 libc_hidden_def (tr_break)
101 static void tr_where (const __ptr_t) __THROW internal_function;
102 static void
103 internal_function
104 tr_where (caller)
105 const __ptr_t caller;
107 #ifdef USE_MTRACE_FILE
108 if (_mtrace_file)
110 fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
111 _mtrace_file = NULL;
113 else
114 #endif
115 if (caller != NULL)
117 #ifdef HAVE_ELF
118 Dl_info info;
119 if (_dl_addr (caller, &info, NULL, NULL))
121 char *buf = (char *) "";
122 if (info.dli_sname != NULL)
124 size_t len = strlen (info.dli_sname);
125 buf = alloca (len + 6 + 2 * sizeof (void *));
127 buf[0] = '(';
128 __stpcpy (_fitoa (caller >= (const __ptr_t) info.dli_saddr
129 ? caller - (const __ptr_t) info.dli_saddr
130 : (const __ptr_t) info.dli_saddr - caller,
131 __stpcpy (__mempcpy (buf + 1, info.dli_sname,
132 len),
133 caller >= (__ptr_t) info.dli_saddr
134 ? "+0x" : "-0x"),
135 16, 0),
136 ")");
139 fprintf (mallstream, "@ %s%s%s[%p] ",
140 info.dli_fname ?: "", info.dli_fname ? ":" : "",
141 buf, caller);
143 else
144 #endif
145 fprintf (mallstream, "@ [%p] ", caller);
149 static void tr_freehook (__ptr_t, const __ptr_t) __THROW;
150 static void
151 tr_freehook (ptr, caller)
152 __ptr_t ptr;
153 const __ptr_t caller;
155 if (ptr == NULL)
156 return;
157 __libc_lock_lock (lock);
158 tr_where (caller);
159 /* Be sure to print it first. */
160 fprintf (mallstream, "- %p\n", ptr);
161 __libc_lock_unlock (lock);
162 if (ptr == mallwatch)
163 tr_break ();
164 __libc_lock_lock (lock);
165 __free_hook = tr_old_free_hook;
166 if (tr_old_free_hook != NULL)
167 (*tr_old_free_hook) (ptr, caller);
168 else
169 __libc_free (ptr);
170 __free_hook = tr_freehook;
171 __libc_lock_unlock (lock);
174 static __ptr_t tr_mallochook (__malloc_size_t, const __ptr_t) __THROW;
175 static __ptr_t
176 tr_mallochook (size, caller)
177 __malloc_size_t size;
178 const __ptr_t caller;
180 __ptr_t hdr;
182 __libc_lock_lock (lock);
184 __malloc_hook = tr_old_malloc_hook;
185 if (tr_old_malloc_hook != NULL)
186 hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
187 else
188 hdr = (__ptr_t) __libc_malloc (size);
189 __malloc_hook = tr_mallochook;
191 tr_where (caller);
192 /* We could be printing a NULL here; that's OK. */
193 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
195 __libc_lock_unlock (lock);
197 if (hdr == mallwatch)
198 tr_break ();
200 return hdr;
203 static __ptr_t tr_reallochook (__ptr_t, __malloc_size_t, const __ptr_t)
204 __THROW;
205 static __ptr_t
206 tr_reallochook (ptr, size, caller)
207 __ptr_t ptr;
208 __malloc_size_t size;
209 const __ptr_t caller;
211 __ptr_t hdr;
213 if (ptr == mallwatch)
214 tr_break ();
216 __libc_lock_lock (lock);
218 __free_hook = tr_old_free_hook;
219 __malloc_hook = tr_old_malloc_hook;
220 __realloc_hook = tr_old_realloc_hook;
221 if (tr_old_realloc_hook != NULL)
222 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
223 else
224 hdr = (__ptr_t) __libc_realloc (ptr, size);
225 __free_hook = tr_freehook;
226 __malloc_hook = tr_mallochook;
227 __realloc_hook = tr_reallochook;
229 tr_where (caller);
230 if (hdr == NULL)
231 /* Failed realloc. */
232 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
233 else if (ptr == NULL)
234 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
235 else
237 fprintf (mallstream, "< %p\n", ptr);
238 tr_where (caller);
239 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
242 __libc_lock_unlock (lock);
244 if (hdr == mallwatch)
245 tr_break ();
247 return hdr;
250 static __ptr_t tr_memalignhook (__malloc_size_t, __malloc_size_t,
251 const __ptr_t) __THROW;
252 static __ptr_t
253 tr_memalignhook (alignment, size, caller)
254 __malloc_size_t alignment, size;
255 const __ptr_t caller;
257 __ptr_t hdr;
259 __libc_lock_lock (lock);
261 __memalign_hook = tr_old_memalign_hook;
262 __malloc_hook = tr_old_malloc_hook;
263 if (tr_old_memalign_hook != NULL)
264 hdr = (__ptr_t) (*tr_old_memalign_hook) (alignment, size, caller);
265 else
266 hdr = (__ptr_t) __libc_memalign (alignment, size);
267 __memalign_hook = tr_memalignhook;
268 __malloc_hook = tr_mallochook;
270 tr_where (caller);
271 /* We could be printing a NULL here; that's OK. */
272 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
274 __libc_lock_unlock (lock);
276 if (hdr == mallwatch)
277 tr_break ();
279 return hdr;
284 #ifdef _LIBC
286 /* This function gets called to make sure all memory the library
287 allocates get freed and so does not irritate the user when studying
288 the mtrace output. */
289 static void __libc_freeres_fn_section
290 release_libc_mem (void)
292 /* Only call the free function if we still are running in mtrace mode. */
293 if (mallstream != NULL)
294 __libc_freeres ();
296 #endif
299 /* We enable tracing if either the environment variable MALLOC_TRACE
300 is set, or if the variable mallwatch has been patched to an address
301 that the debugging user wants us to stop on. When patching mallwatch,
302 don't forget to set a breakpoint on tr_break! */
304 void
305 mtrace ()
307 #ifdef _LIBC
308 static int added_atexit_handler;
309 #endif
310 char *mallfile;
312 /* Don't panic if we're called more than once. */
313 if (mallstream != NULL)
314 return;
316 #ifdef _LIBC
317 /* When compiling the GNU libc we use the secure getenv function
318 which prevents the misuse in case of SUID or SGID enabled
319 programs. */
320 mallfile = __secure_getenv (mallenv);
321 #else
322 mallfile = getenv (mallenv);
323 #endif
324 if (mallfile != NULL || mallwatch != NULL)
326 char *mtb = malloc (TRACE_BUFFER_SIZE);
327 if (mtb == NULL)
328 return;
330 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wc");
331 if (mallstream != NULL)
333 /* Make sure we close the file descriptor on exec. */
334 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
335 if (flags >= 0)
337 flags |= FD_CLOEXEC;
338 __fcntl (fileno (mallstream), F_SETFD, flags);
340 /* Be sure it doesn't malloc its buffer! */
341 malloc_trace_buffer = mtb;
342 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
343 fprintf (mallstream, "= Start\n");
344 tr_old_free_hook = __free_hook;
345 __free_hook = tr_freehook;
346 tr_old_malloc_hook = __malloc_hook;
347 __malloc_hook = tr_mallochook;
348 tr_old_realloc_hook = __realloc_hook;
349 __realloc_hook = tr_reallochook;
350 tr_old_memalign_hook = __memalign_hook;
351 __memalign_hook = tr_memalignhook;
352 #ifdef _LIBC
353 if (!added_atexit_handler)
355 extern void *__dso_handle __attribute__ ((__weak__));
356 added_atexit_handler = 1;
357 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
358 &__dso_handle ? __dso_handle : NULL);
360 #endif
362 else
363 free (mtb);
367 void
368 muntrace ()
370 if (mallstream == NULL)
371 return;
373 fprintf (mallstream, "= End\n");
374 fclose (mallstream);
375 mallstream = NULL;
376 __free_hook = tr_old_free_hook;
377 __malloc_hook = tr_old_malloc_hook;
378 __realloc_hook = tr_old_realloc_hook;
379 __memalign_hook = tr_old_memalign_hook;