2005-02-21 Alan Modra <amodra@bigpond.net.au>
[glibc/history.git] / malloc / mtrace.c
blob1a9522b09de37f96fb9e4ed807f3cc1dedaca3fb
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 #endif
45 #ifndef attribute_hidden
46 # define attribute_hidden
47 #endif
49 #define TRACE_BUFFER_SIZE 512
51 static FILE *mallstream;
52 static const char mallenv[]= "MALLOC_TRACE";
53 static char *malloc_trace_buffer;
55 __libc_lock_define_initialized (static, lock);
57 /* Address to breakpoint on accesses to... */
58 __ptr_t mallwatch;
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
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);
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. */
81 extern void tr_break (void) __THROW;
82 libc_hidden_proto (tr_break)
83 void
84 tr_break ()
87 libc_hidden_def (tr_break)
89 static void tr_where (const __ptr_t) __THROW internal_function;
90 static void
91 internal_function
92 tr_where (caller)
93 const __ptr_t caller;
95 #ifdef USE_MTRACE_FILE
96 if (_mtrace_file)
98 fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
99 _mtrace_file = NULL;
101 else
102 #endif
103 if (caller != NULL)
105 #ifdef HAVE_ELF
106 Dl_info info;
107 if (_dl_addr (caller, &info, NULL, NULL))
109 char *buf = (char *) "";
110 if (info.dli_sname != NULL)
112 size_t len = strlen (info.dli_sname);
113 buf = alloca (len + 6 + 2 * sizeof (void *));
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 ")");
127 fprintf (mallstream, "@ %s%s%s[%p] ",
128 info.dli_fname ?: "", info.dli_fname ? ":" : "",
129 buf, caller);
131 else
132 #endif
133 fprintf (mallstream, "@ [%p] ", caller);
137 static void tr_freehook (__ptr_t, const __ptr_t) __THROW;
138 static void
139 tr_freehook (ptr, caller)
140 __ptr_t ptr;
141 const __ptr_t caller;
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);
162 static __ptr_t tr_mallochook (__malloc_size_t, const __ptr_t) __THROW;
163 static __ptr_t
164 tr_mallochook (size, caller)
165 __malloc_size_t size;
166 const __ptr_t caller;
168 __ptr_t hdr;
170 __libc_lock_lock (lock);
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;
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);
183 __libc_lock_unlock (lock);
185 if (hdr == mallwatch)
186 tr_break ();
188 return hdr;
191 static __ptr_t tr_reallochook (__ptr_t, __malloc_size_t, const __ptr_t)
192 __THROW;
193 static __ptr_t
194 tr_reallochook (ptr, size, caller)
195 __ptr_t ptr;
196 __malloc_size_t size;
197 const __ptr_t caller;
199 __ptr_t hdr;
201 if (ptr == mallwatch)
202 tr_break ();
204 __libc_lock_lock (lock);
206 __free_hook = tr_old_free_hook;
207 __malloc_hook = tr_old_malloc_hook;
208 __realloc_hook = tr_old_realloc_hook;
209 if (tr_old_realloc_hook != NULL)
210 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
211 else
212 hdr = (__ptr_t) realloc (ptr, size);
213 __free_hook = tr_freehook;
214 __malloc_hook = tr_mallochook;
215 __realloc_hook = tr_reallochook;
217 tr_where (caller);
218 if (hdr == NULL)
219 /* Failed realloc. */
220 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
221 else if (ptr == NULL)
222 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
223 else
225 fprintf (mallstream, "< %p\n", ptr);
226 tr_where (caller);
227 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
230 __libc_lock_unlock (lock);
232 if (hdr == mallwatch)
233 tr_break ();
235 return hdr;
238 static __ptr_t tr_memalignhook (__malloc_size_t, __malloc_size_t,
239 const __ptr_t) __THROW;
240 static __ptr_t
241 tr_memalignhook (alignment, size, caller)
242 __malloc_size_t alignment, size;
243 const __ptr_t caller;
245 __ptr_t hdr;
247 __libc_lock_lock (lock);
249 __memalign_hook = tr_old_memalign_hook;
250 __malloc_hook = tr_old_malloc_hook;
251 if (tr_old_memalign_hook != NULL)
252 hdr = (__ptr_t) (*tr_old_memalign_hook) (alignment, size, caller);
253 else
254 hdr = (__ptr_t) memalign (alignment, size);
255 __memalign_hook = tr_memalignhook;
256 __malloc_hook = tr_mallochook;
258 tr_where (caller);
259 /* We could be printing a NULL here; that's OK. */
260 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
262 __libc_lock_unlock (lock);
264 if (hdr == mallwatch)
265 tr_break ();
267 return hdr;
272 #ifdef _LIBC
274 /* This function gets called to make sure all memory the library
275 allocates get freed and so does not irritate the user when studying
276 the mtrace output. */
277 static void __libc_freeres_fn_section
278 release_libc_mem (void)
280 /* Only call the free function if we still are running in mtrace mode. */
281 if (mallstream != NULL)
282 __libc_freeres ();
284 #endif
287 /* We enable tracing if either the environment variable MALLOC_TRACE
288 is set, or if the variable mallwatch has been patched to an address
289 that the debugging user wants us to stop on. When patching mallwatch,
290 don't forget to set a breakpoint on tr_break! */
292 void
293 mtrace ()
295 #ifdef _LIBC
296 static int added_atexit_handler;
297 #endif
298 char *mallfile;
300 /* Don't panic if we're called more than once. */
301 if (mallstream != NULL)
302 return;
304 #ifdef _LIBC
305 /* When compiling the GNU libc we use the secure getenv function
306 which prevents the misuse in case of SUID or SGID enabled
307 programs. */
308 mallfile = __secure_getenv (mallenv);
309 #else
310 mallfile = getenv (mallenv);
311 #endif
312 if (mallfile != NULL || mallwatch != NULL)
314 char *mtb = malloc (TRACE_BUFFER_SIZE);
315 if (mtb == NULL)
316 return;
318 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wc");
319 if (mallstream != NULL)
321 /* Make sure we close the file descriptor on exec. */
322 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
323 if (flags >= 0)
325 flags |= FD_CLOEXEC;
326 __fcntl (fileno (mallstream), F_SETFD, flags);
328 /* Be sure it doesn't malloc its buffer! */
329 malloc_trace_buffer = mtb;
330 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
331 fprintf (mallstream, "= Start\n");
332 tr_old_free_hook = __free_hook;
333 __free_hook = tr_freehook;
334 tr_old_malloc_hook = __malloc_hook;
335 __malloc_hook = tr_mallochook;
336 tr_old_realloc_hook = __realloc_hook;
337 __realloc_hook = tr_reallochook;
338 tr_old_memalign_hook = __memalign_hook;
339 __memalign_hook = tr_memalignhook;
340 #ifdef _LIBC
341 if (!added_atexit_handler)
343 extern void *__dso_handle __attribute__ ((__weak__));
344 added_atexit_handler = 1;
345 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
346 &__dso_handle ? __dso_handle : NULL);
348 #endif
350 else
351 free (mtb);
355 void
356 muntrace ()
358 if (mallstream == NULL)
359 return;
361 fprintf (mallstream, "= End\n");
362 fclose (mallstream);
363 mallstream = NULL;
364 __free_hook = tr_old_free_hook;
365 __malloc_hook = tr_old_malloc_hook;
366 __realloc_hook = tr_old_realloc_hook;
367 __memalign_hook = tr_old_memalign_hook;