*** empty log message ***
[glibc.git] / malloc / mtrace.c
blob6d56cf0b5cea29f0d8053f04b08f7e95f50edf17
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));
75 /* This function is called when the block being alloc'd, realloc'd, or
76 freed has an address matching the variable "mallwatch". In a debugger,
77 set "mallwatch" to the address of interest, then put a breakpoint on
78 tr_break. */
80 extern void tr_break __P ((void));
81 libc_hidden_proto (tr_break)
82 void
83 tr_break ()
86 libc_hidden_def (tr_break)
88 static void tr_where __P ((const __ptr_t)) internal_function;
89 static void
90 internal_function
91 tr_where (caller)
92 const __ptr_t caller;
94 #ifdef USE_MTRACE_FILE
95 if (_mtrace_file)
97 fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
98 _mtrace_file = NULL;
100 else
101 #endif
102 if (caller != NULL)
104 #ifdef HAVE_ELF
105 Dl_info info;
106 if (_dl_addr (caller, &info, NULL, NULL))
108 char *buf = (char *) "";
109 if (info.dli_sname != NULL)
111 size_t len = strlen (info.dli_sname);
112 buf = alloca (len + 6 + 2 * sizeof (void *));
114 buf[0] = '(';
115 __stpcpy (_fitoa (caller >= (const __ptr_t) info.dli_saddr
116 ? caller - (const __ptr_t) info.dli_saddr
117 : (const __ptr_t) info.dli_saddr - caller,
118 __stpcpy (__mempcpy (buf + 1, info.dli_sname,
119 len),
120 caller >= (__ptr_t) info.dli_saddr
121 ? "+0x" : "-0x"),
122 16, 0),
123 ")");
126 fprintf (mallstream, "@ %s%s%s[%p] ",
127 info.dli_fname ?: "", info.dli_fname ? ":" : "",
128 buf, caller);
130 else
131 #endif
132 fprintf (mallstream, "@ [%p] ", caller);
136 static void tr_freehook __P ((__ptr_t, const __ptr_t));
137 static void
138 tr_freehook (ptr, caller)
139 __ptr_t ptr;
140 const __ptr_t caller;
142 if (ptr == NULL)
143 return;
144 __libc_lock_lock (lock);
145 tr_where (caller);
146 /* Be sure to print it first. */
147 fprintf (mallstream, "- %p\n", ptr);
148 __libc_lock_unlock (lock);
149 if (ptr == mallwatch)
150 tr_break ();
151 __libc_lock_lock (lock);
152 __free_hook = tr_old_free_hook;
153 if (tr_old_free_hook != NULL)
154 (*tr_old_free_hook) (ptr, caller);
155 else
156 free (ptr);
157 __free_hook = tr_freehook;
158 __libc_lock_unlock (lock);
161 static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
162 static __ptr_t
163 tr_mallochook (size, caller)
164 __malloc_size_t size;
165 const __ptr_t caller;
167 __ptr_t hdr;
169 __libc_lock_lock (lock);
171 __malloc_hook = tr_old_malloc_hook;
172 if (tr_old_malloc_hook != NULL)
173 hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
174 else
175 hdr = (__ptr_t) malloc (size);
176 __malloc_hook = tr_mallochook;
178 tr_where (caller);
179 /* We could be printing a NULL here; that's OK. */
180 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
182 __libc_lock_unlock (lock);
184 if (hdr == mallwatch)
185 tr_break ();
187 return hdr;
190 static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
191 static __ptr_t
192 tr_reallochook (ptr, size, caller)
193 __ptr_t ptr;
194 __malloc_size_t size;
195 const __ptr_t caller;
197 __ptr_t hdr;
199 if (ptr == mallwatch)
200 tr_break ();
202 __libc_lock_lock (lock);
204 __free_hook = tr_old_free_hook;
205 __malloc_hook = tr_old_malloc_hook;
206 __realloc_hook = tr_old_realloc_hook;
207 if (tr_old_realloc_hook != NULL)
208 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
209 else
210 hdr = (__ptr_t) realloc (ptr, size);
211 __free_hook = tr_freehook;
212 __malloc_hook = tr_mallochook;
213 __realloc_hook = tr_reallochook;
215 tr_where (caller);
216 if (hdr == NULL)
217 /* Failed realloc. */
218 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
219 else if (ptr == NULL)
220 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
221 else
223 fprintf (mallstream, "< %p\n", ptr);
224 tr_where (caller);
225 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
228 __libc_lock_unlock (lock);
230 if (hdr == mallwatch)
231 tr_break ();
233 return hdr;
237 #ifdef _LIBC
239 /* This function gets called to make sure all memory the library
240 allocates get freed and so does not irritate the user when studying
241 the mtrace output. */
242 static void __libc_freeres_fn_section
243 release_libc_mem (void)
245 /* Only call the free function if we still are running in mtrace mode. */
246 if (mallstream != NULL)
247 __libc_freeres ();
249 #endif
252 /* We enable tracing if either the environment variable MALLOC_TRACE
253 is set, or if the variable mallwatch has been patched to an address
254 that the debugging user wants us to stop on. When patching mallwatch,
255 don't forget to set a breakpoint on tr_break! */
257 void
258 mtrace ()
260 #ifdef _LIBC
261 static int added_atexit_handler;
262 #endif
263 char *mallfile;
265 /* Don't panic if we're called more than once. */
266 if (mallstream != NULL)
267 return;
269 #ifdef _LIBC
270 /* When compiling the GNU libc we use the secure getenv function
271 which prevents the misuse in case of SUID or SGID enabled
272 programs. */
273 mallfile = __secure_getenv (mallenv);
274 #else
275 mallfile = getenv (mallenv);
276 #endif
277 if (mallfile != NULL || mallwatch != NULL)
279 char *mtb = malloc (TRACE_BUFFER_SIZE);
280 if (mtb == NULL)
281 return;
283 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
284 if (mallstream != NULL)
286 /* Make sure we close the file descriptor on exec. */
287 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
288 if (flags >= 0)
290 flags |= FD_CLOEXEC;
291 __fcntl (fileno (mallstream), F_SETFD, flags);
293 /* Be sure it doesn't malloc its buffer! */
294 malloc_trace_buffer = mtb;
295 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
296 fprintf (mallstream, "= Start\n");
297 tr_old_free_hook = __free_hook;
298 __free_hook = tr_freehook;
299 tr_old_malloc_hook = __malloc_hook;
300 __malloc_hook = tr_mallochook;
301 tr_old_realloc_hook = __realloc_hook;
302 __realloc_hook = tr_reallochook;
303 #ifdef _LIBC
304 if (!added_atexit_handler)
306 extern void *__dso_handle __attribute__ ((__weak__));
307 added_atexit_handler = 1;
308 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
309 &__dso_handle ? __dso_handle : NULL);
311 #endif
313 else
314 free (mtb);
318 void
319 muntrace ()
321 if (mallstream == NULL)
322 return;
324 fprintf (mallstream, "= End\n");
325 fclose (mallstream);
326 mallstream = NULL;
327 __free_hook = tr_old_free_hook;
328 __malloc_hook = tr_old_malloc_hook;
329 __realloc_hook = tr_old_realloc_hook;