Update.
[glibc.git] / malloc / mtrace.c
blobc4239ddfba6af8e8aaefcf88619b4c75489ee176
1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-1994,1996-2001,2002, 2003 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) __P ((__ptr_t ptr, const __ptr_t));
69 static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size,
70 const __ptr_t));
71 static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
72 __malloc_size_t size,
73 const __ptr_t));
74 static __ptr_t (*tr_old_memalign_hook) __P ((__malloc_size_t __alignment,
75 __malloc_size_t __size,
76 __const __ptr_t));
78 /* This function is called when the block being alloc'd, realloc'd, or
79 freed has an address matching the variable "mallwatch". In a debugger,
80 set "mallwatch" to the address of interest, then put a breakpoint on
81 tr_break. */
83 extern void tr_break __P ((void));
84 libc_hidden_proto (tr_break)
85 void
86 tr_break ()
89 libc_hidden_def (tr_break)
91 static void tr_where __P ((const __ptr_t)) internal_function;
92 static void
93 internal_function
94 tr_where (caller)
95 const __ptr_t caller;
97 #ifdef USE_MTRACE_FILE
98 if (_mtrace_file)
100 fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
101 _mtrace_file = NULL;
103 else
104 #endif
105 if (caller != NULL)
107 #ifdef HAVE_ELF
108 Dl_info info;
109 if (_dl_addr (caller, &info, NULL, NULL))
111 char *buf = (char *) "";
112 if (info.dli_sname != NULL)
114 size_t len = strlen (info.dli_sname);
115 buf = alloca (len + 6 + 2 * sizeof (void *));
117 buf[0] = '(';
118 __stpcpy (_fitoa (caller >= (const __ptr_t) info.dli_saddr
119 ? caller - (const __ptr_t) info.dli_saddr
120 : (const __ptr_t) info.dli_saddr - caller,
121 __stpcpy (__mempcpy (buf + 1, info.dli_sname,
122 len),
123 caller >= (__ptr_t) info.dli_saddr
124 ? "+0x" : "-0x"),
125 16, 0),
126 ")");
129 fprintf (mallstream, "@ %s%s%s[%p] ",
130 info.dli_fname ?: "", info.dli_fname ? ":" : "",
131 buf, caller);
133 else
134 #endif
135 fprintf (mallstream, "@ [%p] ", caller);
139 static void tr_freehook __P ((__ptr_t, const __ptr_t));
140 static void
141 tr_freehook (ptr, caller)
142 __ptr_t ptr;
143 const __ptr_t caller;
145 if (ptr == NULL)
146 return;
147 __libc_lock_lock (lock);
148 tr_where (caller);
149 /* Be sure to print it first. */
150 fprintf (mallstream, "- %p\n", ptr);
151 __libc_lock_unlock (lock);
152 if (ptr == mallwatch)
153 tr_break ();
154 __libc_lock_lock (lock);
155 __free_hook = tr_old_free_hook;
156 if (tr_old_free_hook != NULL)
157 (*tr_old_free_hook) (ptr, caller);
158 else
159 free (ptr);
160 __free_hook = tr_freehook;
161 __libc_lock_unlock (lock);
164 static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
165 static __ptr_t
166 tr_mallochook (size, caller)
167 __malloc_size_t size;
168 const __ptr_t caller;
170 __ptr_t hdr;
172 __libc_lock_lock (lock);
174 __malloc_hook = tr_old_malloc_hook;
175 if (tr_old_malloc_hook != NULL)
176 hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
177 else
178 hdr = (__ptr_t) malloc (size);
179 __malloc_hook = tr_mallochook;
181 tr_where (caller);
182 /* We could be printing a NULL here; that's OK. */
183 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
185 __libc_lock_unlock (lock);
187 if (hdr == mallwatch)
188 tr_break ();
190 return hdr;
193 static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
194 static __ptr_t
195 tr_reallochook (ptr, size, caller)
196 __ptr_t ptr;
197 __malloc_size_t size;
198 const __ptr_t caller;
200 __ptr_t hdr;
202 if (ptr == mallwatch)
203 tr_break ();
205 __libc_lock_lock (lock);
207 __free_hook = tr_old_free_hook;
208 __malloc_hook = tr_old_malloc_hook;
209 __realloc_hook = tr_old_realloc_hook;
210 if (tr_old_realloc_hook != NULL)
211 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
212 else
213 hdr = (__ptr_t) realloc (ptr, size);
214 __free_hook = tr_freehook;
215 __malloc_hook = tr_mallochook;
216 __realloc_hook = tr_reallochook;
218 tr_where (caller);
219 if (hdr == NULL)
220 /* Failed realloc. */
221 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
222 else if (ptr == NULL)
223 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
224 else
226 fprintf (mallstream, "< %p\n", ptr);
227 tr_where (caller);
228 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
231 __libc_lock_unlock (lock);
233 if (hdr == mallwatch)
234 tr_break ();
236 return hdr;
239 static __ptr_t tr_memalignhook __P ((__malloc_size_t, __malloc_size_t,
240 const __ptr_t));
241 static __ptr_t
242 tr_memalignhook (alignment, size, caller)
243 __malloc_size_t alignment, size;
244 const __ptr_t caller;
246 __ptr_t hdr;
248 __libc_lock_lock (lock);
250 __memalign_hook = tr_old_memalign_hook;
251 __malloc_hook = tr_old_malloc_hook;
252 if (tr_old_memalign_hook != NULL)
253 hdr = (__ptr_t) (*tr_old_memalign_hook) (alignment, size, caller);
254 else
255 hdr = (__ptr_t) memalign (alignment, size);
256 __memalign_hook = tr_memalignhook;
257 __malloc_hook = tr_mallochook;
259 tr_where (caller);
260 /* We could be printing a NULL here; that's OK. */
261 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
263 __libc_lock_unlock (lock);
265 if (hdr == mallwatch)
266 tr_break ();
268 return hdr;
273 #ifdef _LIBC
275 /* This function gets called to make sure all memory the library
276 allocates get freed and so does not irritate the user when studying
277 the mtrace output. */
278 static void __libc_freeres_fn_section
279 release_libc_mem (void)
281 /* Only call the free function if we still are running in mtrace mode. */
282 if (mallstream != NULL)
283 __libc_freeres ();
285 #endif
288 /* We enable tracing if either the environment variable MALLOC_TRACE
289 is set, or if the variable mallwatch has been patched to an address
290 that the debugging user wants us to stop on. When patching mallwatch,
291 don't forget to set a breakpoint on tr_break! */
293 void
294 mtrace ()
296 #ifdef _LIBC
297 static int added_atexit_handler;
298 #endif
299 char *mallfile;
301 /* Don't panic if we're called more than once. */
302 if (mallstream != NULL)
303 return;
305 #ifdef _LIBC
306 /* When compiling the GNU libc we use the secure getenv function
307 which prevents the misuse in case of SUID or SGID enabled
308 programs. */
309 mallfile = __secure_getenv (mallenv);
310 #else
311 mallfile = getenv (mallenv);
312 #endif
313 if (mallfile != NULL || mallwatch != NULL)
315 char *mtb = malloc (TRACE_BUFFER_SIZE);
316 if (mtb == NULL)
317 return;
319 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wc");
320 if (mallstream != NULL)
322 /* Make sure we close the file descriptor on exec. */
323 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
324 if (flags >= 0)
326 flags |= FD_CLOEXEC;
327 __fcntl (fileno (mallstream), F_SETFD, flags);
329 /* Be sure it doesn't malloc its buffer! */
330 malloc_trace_buffer = mtb;
331 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
332 fprintf (mallstream, "= Start\n");
333 tr_old_free_hook = __free_hook;
334 __free_hook = tr_freehook;
335 tr_old_malloc_hook = __malloc_hook;
336 __malloc_hook = tr_mallochook;
337 tr_old_realloc_hook = __realloc_hook;
338 __realloc_hook = tr_reallochook;
339 tr_old_memalign_hook = __memalign_hook;
340 __memalign_hook = tr_memalignhook;
341 #ifdef _LIBC
342 if (!added_atexit_handler)
344 extern void *__dso_handle __attribute__ ((__weak__));
345 added_atexit_handler = 1;
346 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
347 &__dso_handle ? __dso_handle : NULL);
349 #endif
351 else
352 free (mtb);
356 void
357 muntrace ()
359 if (mallstream == NULL)
360 return;
362 fprintf (mallstream, "= End\n");
363 fclose (mallstream);
364 mallstream = NULL;
365 __free_hook = tr_old_free_hook;
366 __malloc_hook = tr_old_malloc_hook;
367 __realloc_hook = tr_old_realloc_hook;
368 __memalign_hook = tr_old_memalign_hook;