Update ChangeLog
[glibc.git] / malloc / mtrace.c
blobd7a032a86a50ced64ca49712fc3a859c836dd733
1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-2012 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, see
19 <http://www.gnu.org/licenses/>. */
21 #ifndef _MALLOC_INTERNAL
22 #define _MALLOC_INTERNAL
23 #include <malloc.h>
24 #include <mcheck.h>
25 #include <bits/libc-lock.h>
26 #endif
28 #include <dlfcn.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
34 #include <_itoa.h>
36 #include <libc-internal.h>
38 #include <libio/iolibio.h>
39 #define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
40 #define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
42 #include <kernel-features.h>
44 #ifndef attribute_hidden
45 # define attribute_hidden
46 #endif
48 #define TRACE_BUFFER_SIZE 512
50 static FILE *mallstream;
51 static const char mallenv[]= "MALLOC_TRACE";
52 static char *malloc_trace_buffer;
54 __libc_lock_define_initialized (static, lock);
56 /* Address to breakpoint on accesses to... */
57 __ptr_t mallwatch;
59 /* Old hook values. */
60 static void (*tr_old_free_hook) (__ptr_t ptr, const __ptr_t);
61 static __ptr_t (*tr_old_malloc_hook) (__malloc_size_t size, const __ptr_t);
62 static __ptr_t (*tr_old_realloc_hook) (__ptr_t ptr, __malloc_size_t size,
63 const __ptr_t);
64 static __ptr_t (*tr_old_memalign_hook) (__malloc_size_t __alignment,
65 __malloc_size_t __size,
66 const __ptr_t);
68 /* This function is called when the block being alloc'd, realloc'd, or
69 freed has an address matching the variable "mallwatch". In a debugger,
70 set "mallwatch" to the address of interest, then put a breakpoint on
71 tr_break. */
73 extern void tr_break (void) __THROW;
74 libc_hidden_proto (tr_break)
75 void
76 tr_break ()
79 libc_hidden_def (tr_break)
81 static void tr_where (const __ptr_t, Dl_info *) __THROW internal_function;
82 static void
83 internal_function
84 tr_where (caller, info)
85 const __ptr_t caller;
86 Dl_info *info;
88 if (caller != NULL)
90 if (info != NULL)
92 char *buf = (char *) "";
93 if (info->dli_sname != NULL)
95 size_t len = strlen (info->dli_sname);
96 buf = alloca (len + 6 + 2 * sizeof (void *));
98 buf[0] = '(';
99 __stpcpy (_fitoa (caller >= (const __ptr_t) info->dli_saddr
100 ? caller - (const __ptr_t) info->dli_saddr
101 : (const __ptr_t) info->dli_saddr - caller,
102 __stpcpy (__mempcpy (buf + 1, info->dli_sname,
103 len),
104 caller >= (__ptr_t) info->dli_saddr
105 ? "+0x" : "-0x"),
106 16, 0),
107 ")");
110 fprintf (mallstream, "@ %s%s%s[%p] ",
111 info->dli_fname ?: "", info->dli_fname ? ":" : "",
112 buf, caller);
114 else
115 fprintf (mallstream, "@ [%p] ", caller);
120 static Dl_info *
121 lock_and_info (const __ptr_t caller, Dl_info *mem)
123 if (caller == NULL)
124 return NULL;
126 Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
128 __libc_lock_lock (lock);
130 return res;
134 static void tr_freehook (__ptr_t, const __ptr_t) __THROW;
135 static void
136 tr_freehook (ptr, caller)
137 __ptr_t ptr;
138 const __ptr_t caller;
140 if (ptr == NULL)
141 return;
143 Dl_info mem;
144 Dl_info *info = lock_and_info (caller, &mem);
145 tr_where (caller, info);
146 /* Be sure to print it first. */
147 fprintf (mallstream, "- %p\n", ptr);
148 if (ptr == mallwatch)
150 __libc_lock_unlock (lock);
151 tr_break ();
152 __libc_lock_lock (lock);
154 __free_hook = tr_old_free_hook;
155 if (tr_old_free_hook != NULL)
156 (*tr_old_free_hook) (ptr, caller);
157 else
158 free (ptr);
159 __free_hook = tr_freehook;
160 __libc_lock_unlock (lock);
163 static __ptr_t tr_mallochook (__malloc_size_t, const __ptr_t) __THROW;
164 static __ptr_t
165 tr_mallochook (size, caller)
166 __malloc_size_t size;
167 const __ptr_t caller;
169 __ptr_t hdr;
171 Dl_info mem;
172 Dl_info *info = lock_and_info (caller, &mem);
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, info);
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 (__ptr_t, __malloc_size_t, const __ptr_t)
194 __THROW;
195 static __ptr_t
196 tr_reallochook (ptr, size, caller)
197 __ptr_t ptr;
198 __malloc_size_t size;
199 const __ptr_t caller;
201 __ptr_t hdr;
203 if (ptr == mallwatch)
204 tr_break ();
206 Dl_info mem;
207 Dl_info *info = lock_and_info (caller, &mem);
209 __free_hook = tr_old_free_hook;
210 __malloc_hook = tr_old_malloc_hook;
211 __realloc_hook = tr_old_realloc_hook;
212 if (tr_old_realloc_hook != NULL)
213 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
214 else
215 hdr = (__ptr_t) realloc (ptr, size);
216 __free_hook = tr_freehook;
217 __malloc_hook = tr_mallochook;
218 __realloc_hook = tr_reallochook;
220 tr_where (caller, info);
221 if (hdr == NULL)
222 /* Failed realloc. */
223 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
224 else if (ptr == NULL)
225 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
226 else
228 fprintf (mallstream, "< %p\n", ptr);
229 tr_where (caller, info);
230 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
233 __libc_lock_unlock (lock);
235 if (hdr == mallwatch)
236 tr_break ();
238 return hdr;
241 static __ptr_t tr_memalignhook (__malloc_size_t, __malloc_size_t,
242 const __ptr_t) __THROW;
243 static __ptr_t
244 tr_memalignhook (alignment, size, caller)
245 __malloc_size_t alignment, size;
246 const __ptr_t caller;
248 __ptr_t hdr;
250 Dl_info mem;
251 Dl_info *info = lock_and_info (caller, &mem);
253 __memalign_hook = tr_old_memalign_hook;
254 __malloc_hook = tr_old_malloc_hook;
255 if (tr_old_memalign_hook != NULL)
256 hdr = (__ptr_t) (*tr_old_memalign_hook) (alignment, size, caller);
257 else
258 hdr = (__ptr_t) memalign (alignment, size);
259 __memalign_hook = tr_memalignhook;
260 __malloc_hook = tr_mallochook;
262 tr_where (caller, info);
263 /* We could be printing a NULL here; that's OK. */
264 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
266 __libc_lock_unlock (lock);
268 if (hdr == mallwatch)
269 tr_break ();
271 return hdr;
276 #ifdef _LIBC
278 /* This function gets called to make sure all memory the library
279 allocates get freed and so does not irritate the user when studying
280 the mtrace output. */
281 static void __libc_freeres_fn_section
282 release_libc_mem (void)
284 /* Only call the free function if we still are running in mtrace mode. */
285 if (mallstream != NULL)
286 __libc_freeres ();
288 #endif
291 /* We enable tracing if either the environment variable MALLOC_TRACE
292 is set, or if the variable mallwatch has been patched to an address
293 that the debugging user wants us to stop on. When patching mallwatch,
294 don't forget to set a breakpoint on tr_break! */
296 void
297 mtrace ()
299 #ifdef _LIBC
300 static int added_atexit_handler;
301 #endif
302 char *mallfile;
304 /* Don't panic if we're called more than once. */
305 if (mallstream != NULL)
306 return;
308 #ifdef _LIBC
309 /* When compiling the GNU libc we use the secure getenv function
310 which prevents the misuse in case of SUID or SGID enabled
311 programs. */
312 mallfile = __libc_secure_getenv (mallenv);
313 #else
314 mallfile = getenv (mallenv);
315 #endif
316 if (mallfile != NULL || mallwatch != NULL)
318 char *mtb = malloc (TRACE_BUFFER_SIZE);
319 if (mtb == NULL)
320 return;
322 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
323 if (mallstream != NULL)
325 #ifndef __ASSUME_O_CLOEXEC
326 /* Make sure we close the file descriptor on exec. */
327 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
328 if (flags >= 0)
330 flags |= FD_CLOEXEC;
331 __fcntl (fileno (mallstream), F_SETFD, flags);
333 #endif
334 /* Be sure it doesn't malloc its buffer! */
335 malloc_trace_buffer = mtb;
336 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
337 fprintf (mallstream, "= Start\n");
338 tr_old_free_hook = __free_hook;
339 __free_hook = tr_freehook;
340 tr_old_malloc_hook = __malloc_hook;
341 __malloc_hook = tr_mallochook;
342 tr_old_realloc_hook = __realloc_hook;
343 __realloc_hook = tr_reallochook;
344 tr_old_memalign_hook = __memalign_hook;
345 __memalign_hook = tr_memalignhook;
346 #ifdef _LIBC
347 if (!added_atexit_handler)
349 extern void *__dso_handle __attribute__ ((__weak__));
350 added_atexit_handler = 1;
351 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
352 &__dso_handle ? __dso_handle : NULL);
354 #endif
356 else
357 free (mtb);
361 void
362 muntrace ()
364 if (mallstream == NULL)
365 return;
367 fprintf (mallstream, "= End\n");
368 fclose (mallstream);
369 mallstream = NULL;
370 __free_hook = tr_old_free_hook;
371 __malloc_hook = tr_old_malloc_hook;
372 __realloc_hook = tr_old_realloc_hook;
373 __memalign_hook = tr_old_memalign_hook;