1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-2013 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
25 #include <bits/libc-lock.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
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... */
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
) (size_t size
, const __ptr_t
);
62 static __ptr_t (*tr_old_realloc_hook
) (__ptr_t ptr
, size_t size
,
64 static __ptr_t (*tr_old_memalign_hook
) (size_t __alignment
, size_t __size
,
67 /* This function is called when the block being alloc'd, realloc'd, or
68 freed has an address matching the variable "mallwatch". In a debugger,
69 set "mallwatch" to the address of interest, then put a breakpoint on
72 extern void tr_break (void) __THROW
;
73 libc_hidden_proto (tr_break
)
78 libc_hidden_def (tr_break
)
80 static void tr_where (const __ptr_t
, Dl_info
*) __THROW internal_function
;
83 tr_where (caller
, info
)
91 char *buf
= (char *) "";
92 if (info
->dli_sname
!= NULL
)
94 size_t len
= strlen (info
->dli_sname
);
95 buf
= alloca (len
+ 6 + 2 * sizeof (void *));
98 __stpcpy (_fitoa (caller
>= (const __ptr_t
) info
->dli_saddr
99 ? caller
- (const __ptr_t
) info
->dli_saddr
100 : (const __ptr_t
) info
->dli_saddr
- caller
,
101 __stpcpy (__mempcpy (buf
+ 1, info
->dli_sname
,
103 caller
>= (__ptr_t
) info
->dli_saddr
109 fprintf (mallstream
, "@ %s%s%s[%p] ",
110 info
->dli_fname
?: "", info
->dli_fname
? ":" : "",
114 fprintf (mallstream
, "@ [%p] ", caller
);
120 lock_and_info (const __ptr_t caller
, Dl_info
*mem
)
125 Dl_info
*res
= _dl_addr (caller
, mem
, NULL
, NULL
) ? mem
: NULL
;
127 __libc_lock_lock (lock
);
133 static void tr_freehook (__ptr_t
, const __ptr_t
) __THROW
;
135 tr_freehook (ptr
, caller
)
137 const __ptr_t caller
;
143 Dl_info
*info
= lock_and_info (caller
, &mem
);
144 tr_where (caller
, info
);
145 /* Be sure to print it first. */
146 fprintf (mallstream
, "- %p\n", ptr
);
147 if (ptr
== mallwatch
)
149 __libc_lock_unlock (lock
);
151 __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 (size_t, const __ptr_t
) __THROW
;
164 tr_mallochook (size
, caller
)
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
, size_t, const __ptr_t
)
195 tr_reallochook (ptr
, size
, caller
)
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
);
223 /* Failed realloc. */
224 fprintf (mallstream
, "! %p %#lx\n", ptr
, (unsigned long int) size
);
226 fprintf (mallstream
, "- %p\n", ptr
);
228 else if (ptr
== NULL
)
229 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
232 fprintf (mallstream
, "< %p\n", ptr
);
233 tr_where (caller
, info
);
234 fprintf (mallstream
, "> %p %#lx\n", hdr
, (unsigned long int) size
);
237 __libc_lock_unlock (lock
);
239 if (hdr
== mallwatch
)
245 static __ptr_t
tr_memalignhook (size_t, size_t,
246 const __ptr_t
) __THROW
;
248 tr_memalignhook (alignment
, size
, caller
)
249 size_t alignment
, size
;
250 const __ptr_t caller
;
255 Dl_info
*info
= lock_and_info (caller
, &mem
);
257 __memalign_hook
= tr_old_memalign_hook
;
258 __malloc_hook
= tr_old_malloc_hook
;
259 if (tr_old_memalign_hook
!= NULL
)
260 hdr
= (__ptr_t
) (*tr_old_memalign_hook
) (alignment
, size
, caller
);
262 hdr
= (__ptr_t
) memalign (alignment
, size
);
263 __memalign_hook
= tr_memalignhook
;
264 __malloc_hook
= tr_mallochook
;
266 tr_where (caller
, info
);
267 /* We could be printing a NULL here; that's OK. */
268 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
270 __libc_lock_unlock (lock
);
272 if (hdr
== mallwatch
)
282 /* This function gets called to make sure all memory the library
283 allocates get freed and so does not irritate the user when studying
284 the mtrace output. */
285 static void __libc_freeres_fn_section
286 release_libc_mem (void)
288 /* Only call the free function if we still are running in mtrace mode. */
289 if (mallstream
!= NULL
)
295 /* We enable tracing if either the environment variable MALLOC_TRACE
296 is set, or if the variable mallwatch has been patched to an address
297 that the debugging user wants us to stop on. When patching mallwatch,
298 don't forget to set a breakpoint on tr_break! */
304 static int added_atexit_handler
;
308 /* Don't panic if we're called more than once. */
309 if (mallstream
!= NULL
)
313 /* When compiling the GNU libc we use the secure getenv function
314 which prevents the misuse in case of SUID or SGID enabled
316 mallfile
= __libc_secure_getenv (mallenv
);
318 mallfile
= getenv (mallenv
);
320 if (mallfile
!= NULL
|| mallwatch
!= NULL
)
322 char *mtb
= malloc (TRACE_BUFFER_SIZE
);
326 mallstream
= fopen (mallfile
!= NULL
? mallfile
: "/dev/null", "wce");
327 if (mallstream
!= NULL
)
329 #ifndef __ASSUME_O_CLOEXEC
330 /* Make sure we close the file descriptor on exec. */
331 int flags
= __fcntl (fileno (mallstream
), F_GETFD
, 0);
335 __fcntl (fileno (mallstream
), F_SETFD
, flags
);
338 /* Be sure it doesn't malloc its buffer! */
339 malloc_trace_buffer
= mtb
;
340 setvbuf (mallstream
, malloc_trace_buffer
, _IOFBF
, TRACE_BUFFER_SIZE
);
341 fprintf (mallstream
, "= Start\n");
342 tr_old_free_hook
= __free_hook
;
343 __free_hook
= tr_freehook
;
344 tr_old_malloc_hook
= __malloc_hook
;
345 __malloc_hook
= tr_mallochook
;
346 tr_old_realloc_hook
= __realloc_hook
;
347 __realloc_hook
= tr_reallochook
;
348 tr_old_memalign_hook
= __memalign_hook
;
349 __memalign_hook
= tr_memalignhook
;
351 if (!added_atexit_handler
)
353 extern void *__dso_handle
__attribute__ ((__weak__
));
354 added_atexit_handler
= 1;
355 __cxa_atexit ((void (*) (void *)) release_libc_mem
, NULL
,
356 &__dso_handle
? __dso_handle
: NULL
);
368 if (mallstream
== NULL
)
371 /* Do the reverse of what done in mtrace: first reset the hooks and
372 MALLSTREAM, and only after that write the trailer and close the
374 FILE *f
= mallstream
;
376 __free_hook
= tr_old_free_hook
;
377 __malloc_hook
= tr_old_malloc_hook
;
378 __realloc_hook
= tr_old_realloc_hook
;
379 __memalign_hook
= tr_old_memalign_hook
;
381 fprintf (f
, "= End\n");