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
) (__malloc_size_t size
, const __ptr_t
);
62 static __ptr_t (*tr_old_realloc_hook
) (__ptr_t ptr
, __malloc_size_t size
,
64 static __ptr_t (*tr_old_memalign_hook
) (__malloc_size_t __alignment
,
65 __malloc_size_t __size
,
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
73 extern void tr_break (void) __THROW
;
74 libc_hidden_proto (tr_break
)
79 libc_hidden_def (tr_break
)
81 static void tr_where (const __ptr_t
, Dl_info
*) __THROW internal_function
;
84 tr_where (caller
, info
)
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 *));
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
,
104 caller
>= (__ptr_t
) info
->dli_saddr
110 fprintf (mallstream
, "@ %s%s%s[%p] ",
111 info
->dli_fname
?: "", info
->dli_fname
? ":" : "",
115 fprintf (mallstream
, "@ [%p] ", caller
);
121 lock_and_info (const __ptr_t caller
, Dl_info
*mem
)
126 Dl_info
*res
= _dl_addr (caller
, mem
, NULL
, NULL
) ? mem
: NULL
;
128 __libc_lock_lock (lock
);
134 static void tr_freehook (__ptr_t
, const __ptr_t
) __THROW
;
136 tr_freehook (ptr
, caller
)
138 const __ptr_t caller
;
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
);
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
);
159 __free_hook
= tr_freehook
;
160 __libc_lock_unlock (lock
);
163 static __ptr_t
tr_mallochook (__malloc_size_t
, const __ptr_t
) __THROW
;
165 tr_mallochook (size
, caller
)
166 __malloc_size_t size
;
167 const __ptr_t caller
;
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
);
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
)
193 static __ptr_t
tr_reallochook (__ptr_t
, __malloc_size_t
, const __ptr_t
)
196 tr_reallochook (ptr
, size
, caller
)
198 __malloc_size_t size
;
199 const __ptr_t caller
;
203 if (ptr
== mallwatch
)
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
);
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
);
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
);
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
)
241 static __ptr_t
tr_memalignhook (__malloc_size_t
, __malloc_size_t
,
242 const __ptr_t
) __THROW
;
244 tr_memalignhook (alignment
, size
, caller
)
245 __malloc_size_t alignment
, size
;
246 const __ptr_t caller
;
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
);
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
)
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
)
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! */
300 static int added_atexit_handler
;
304 /* Don't panic if we're called more than once. */
305 if (mallstream
!= NULL
)
309 /* When compiling the GNU libc we use the secure getenv function
310 which prevents the misuse in case of SUID or SGID enabled
312 mallfile
= __libc_secure_getenv (mallenv
);
314 mallfile
= getenv (mallenv
);
316 if (mallfile
!= NULL
|| mallwatch
!= NULL
)
318 char *mtb
= malloc (TRACE_BUFFER_SIZE
);
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);
331 __fcntl (fileno (mallstream
), F_SETFD
, flags
);
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
;
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
);
364 if (mallstream
== NULL
)
367 /* Do the reverse of what done in mtrace: first reset the hooks and
368 MALLSTREAM, and only after that write the trailer and close the
370 FILE *f
= mallstream
;
372 __free_hook
= tr_old_free_hook
;
373 __malloc_hook
= tr_old_malloc_hook
;
374 __realloc_hook
= tr_old_realloc_hook
;
375 __memalign_hook
= tr_old_memalign_hook
;
377 fprintf (f
, "= End\n");