1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-1994,1996-2004, 2008, 2011 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
22 #ifndef _MALLOC_INTERNAL
23 #define _MALLOC_INTERNAL
26 #include <bits/libc-lock.h>
35 #include <stdio-common/_itoa.h>
37 #include <libc-internal.h>
39 #include <libio/iolibio.h>
40 #define setvbuf(s, b, f, l) INTUSE(_IO_setvbuf) (s, b, f, l)
41 #define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
43 #include <kernel-features.h>
45 #ifndef attribute_hidden
46 # define attribute_hidden
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... */
60 /* Old hook values. */
61 static void (*tr_old_free_hook) (__ptr_t ptr, const __ptr_t);
62 static __ptr_t (*tr_old_malloc_hook) (__malloc_size_t size, const __ptr_t);
63 static __ptr_t (*tr_old_realloc_hook) (__ptr_t ptr, __malloc_size_t size,
65 static __ptr_t (*tr_old_memalign_hook) (__malloc_size_t __alignment,
66 __malloc_size_t __size,
69 /* This function is called when the block being alloc'd, realloc'd, or
70 freed has an address matching the variable "mallwatch". In a debugger,
71 set "mallwatch" to the address of interest, then put a breakpoint on
74 extern void tr_break (void) __THROW;
75 libc_hidden_proto (tr_break)
80 libc_hidden_def (tr_break)
82 static void tr_where (const __ptr_t, Dl_info *) __THROW internal_function;
85 tr_where (caller, info)
93 char *buf = (char *) "";
94 if (info->dli_sname != NULL)
96 size_t len = strlen (info->dli_sname);
97 buf = alloca (len + 6 + 2 * sizeof (void *));
100 __stpcpy (_fitoa (caller >= (const __ptr_t) info->dli_saddr
101 ? caller - (const __ptr_t) info->dli_saddr
102 : (const __ptr_t) info->dli_saddr - caller,
103 __stpcpy (__mempcpy (buf + 1, info->dli_sname,
105 caller >= (__ptr_t) info->dli_saddr
111 fprintf (mallstream, "@ %s%s%s[%p] ",
112 info->dli_fname ?: "", info->dli_fname ? ":" : "",
116 fprintf (mallstream, "@ [%p] ", caller);
122 lock_and_info (const __ptr_t caller, Dl_info *mem)
127 Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
129 __libc_lock_lock (lock);
135 static void tr_freehook (__ptr_t, const __ptr_t) __THROW;
137 tr_freehook (ptr, caller)
139 const __ptr_t caller;
145 Dl_info *info = lock_and_info (caller, &mem);
146 tr_where (caller, info);
147 /* Be sure to print it first. */
148 fprintf (mallstream, "- %p\n", ptr);
149 __libc_lock_unlock (lock);
150 if (ptr == mallwatch)
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);
158 __free_hook = tr_freehook;
159 __libc_lock_unlock (lock);
162 static __ptr_t tr_mallochook (__malloc_size_t, const __ptr_t) __THROW;
164 tr_mallochook (size, caller)
165 __malloc_size_t size;
166 const __ptr_t caller;
171 Dl_info *info = lock_and_info (caller, &mem);
173 __malloc_hook = tr_old_malloc_hook;
174 if (tr_old_malloc_hook != NULL)
175 hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
177 hdr = (__ptr_t) malloc (size);
178 __malloc_hook = tr_mallochook;
180 tr_where (caller, info);
181 /* We could be printing a NULL here; that's OK. */
182 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
184 __libc_lock_unlock (lock);
186 if (hdr == mallwatch)
192 static __ptr_t tr_reallochook (__ptr_t, __malloc_size_t, const __ptr_t)
195 tr_reallochook (ptr, size, caller)
197 __malloc_size_t size;
198 const __ptr_t caller;
202 if (ptr == mallwatch)
206 Dl_info *info = lock_and_info (caller, &mem);
208 __free_hook = tr_old_free_hook;
209 __malloc_hook = tr_old_malloc_hook;
210 __realloc_hook = tr_old_realloc_hook;
211 if (tr_old_realloc_hook != NULL)
212 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
214 hdr = (__ptr_t) realloc (ptr, size);
215 __free_hook = tr_freehook;
216 __malloc_hook = tr_mallochook;
217 __realloc_hook = tr_reallochook;
219 tr_where (caller, info);
221 /* Failed realloc. */
222 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
223 else if (ptr == NULL)
224 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
227 fprintf (mallstream, "< %p\n", ptr);
228 tr_where (caller, info);
229 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
232 __libc_lock_unlock (lock);
234 if (hdr == mallwatch)
240 static __ptr_t tr_memalignhook (__malloc_size_t, __malloc_size_t,
241 const __ptr_t) __THROW;
243 tr_memalignhook (alignment, size, caller)
244 __malloc_size_t alignment, size;
245 const __ptr_t caller;
250 Dl_info *info = lock_and_info (caller, &mem);
252 __memalign_hook = tr_old_memalign_hook;
253 __malloc_hook = tr_old_malloc_hook;
254 if (tr_old_memalign_hook != NULL)
255 hdr = (__ptr_t) (*tr_old_memalign_hook) (alignment, size, caller);
257 hdr = (__ptr_t) memalign (alignment, size);
258 __memalign_hook = tr_memalignhook;
259 __malloc_hook = tr_mallochook;
261 tr_where (caller, info);
262 /* We could be printing a NULL here; that's OK. */
263 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
265 __libc_lock_unlock (lock);
267 if (hdr == mallwatch)
277 /* This function gets called to make sure all memory the library
278 allocates get freed and so does not irritate the user when studying
279 the mtrace output. */
280 static void __libc_freeres_fn_section
281 release_libc_mem (void)
283 /* Only call the free function if we still are running in mtrace mode. */
284 if (mallstream != NULL)
290 /* We enable tracing if either the environment variable MALLOC_TRACE
291 is set, or if the variable mallwatch has been patched to an address
292 that the debugging user wants us to stop on. When patching mallwatch,
293 don't forget to set a breakpoint on tr_break! */
299 static int added_atexit_handler;
303 /* Don't panic if we're called more than once. */
304 if (mallstream != NULL)
308 /* When compiling the GNU libc we use the secure getenv function
309 which prevents the misuse in case of SUID or SGID enabled
311 mallfile = __secure_getenv (mallenv);
313 mallfile = getenv (mallenv);
315 if (mallfile != NULL || mallwatch != NULL)
317 char *mtb = malloc (TRACE_BUFFER_SIZE);
321 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
322 if (mallstream != NULL)
324 #ifndef __ASSUME_O_CLOEXEC
325 /* Make sure we close the file descriptor on exec. */
326 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
330 __fcntl (fileno (mallstream), F_SETFD, flags);
333 /* Be sure it doesn't malloc its buffer! */
334 malloc_trace_buffer = mtb;
335 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
336 fprintf (mallstream, "= Start\n");
337 tr_old_free_hook = __free_hook;
338 __free_hook = tr_freehook;
339 tr_old_malloc_hook = __malloc_hook;
340 __malloc_hook = tr_mallochook;
341 tr_old_realloc_hook = __realloc_hook;
342 __realloc_hook = tr_reallochook;
343 tr_old_memalign_hook = __memalign_hook;
344 __memalign_hook = tr_memalignhook;
346 if (!added_atexit_handler)
348 extern void *__dso_handle __attribute__ ((__weak__));
349 added_atexit_handler = 1;
350 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
351 &__dso_handle ? __dso_handle : NULL);
363 if (mallstream == NULL)
366 fprintf (mallstream, "= End\n");
369 __free_hook = tr_old_free_hook;
370 __malloc_hook = tr_old_malloc_hook;
371 __realloc_hook = tr_old_realloc_hook;
372 __memalign_hook = tr_old_memalign_hook;