1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-2014 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
;
82 internal_function
tr_where (caller
, info
)
90 char *buf
= (char *) "";
91 if (info
->dli_sname
!= NULL
)
93 size_t len
= strlen (info
->dli_sname
);
94 buf
= alloca (len
+ 6 + 2 * sizeof (void *));
97 __stpcpy (_fitoa (caller
>= (const __ptr_t
) info
->dli_saddr
98 ? caller
- (const __ptr_t
) info
->dli_saddr
99 : (const __ptr_t
) info
->dli_saddr
- caller
,
100 __stpcpy (__mempcpy (buf
+ 1, info
->dli_sname
,
102 caller
>= (__ptr_t
) info
->dli_saddr
108 fprintf (mallstream
, "@ %s%s%s[%p] ",
109 info
->dli_fname
? : "", info
->dli_fname
? ":" : "",
113 fprintf (mallstream
, "@ [%p] ", caller
);
119 lock_and_info (const __ptr_t caller
, Dl_info
*mem
)
124 Dl_info
*res
= _dl_addr (caller
, mem
, NULL
, NULL
) ? mem
: NULL
;
126 __libc_lock_lock (lock
);
132 static void tr_freehook (__ptr_t
, const __ptr_t
) __THROW
;
133 static void tr_freehook (ptr
, caller
)
135 const __ptr_t caller
;
141 Dl_info
*info
= lock_and_info (caller
, &mem
);
142 tr_where (caller
, info
);
143 /* Be sure to print it first. */
144 fprintf (mallstream
, "- %p\n", ptr
);
145 if (ptr
== mallwatch
)
147 __libc_lock_unlock (lock
);
149 __libc_lock_lock (lock
);
151 __free_hook
= tr_old_free_hook
;
152 if (tr_old_free_hook
!= NULL
)
153 (*tr_old_free_hook
)(ptr
, caller
);
156 __free_hook
= tr_freehook
;
157 __libc_lock_unlock (lock
);
160 static __ptr_t
tr_mallochook (size_t, const __ptr_t
) __THROW
;
161 static __ptr_t
tr_mallochook (size
, caller
)
163 const __ptr_t caller
;
168 Dl_info
*info
= lock_and_info (caller
, &mem
);
170 __malloc_hook
= tr_old_malloc_hook
;
171 if (tr_old_malloc_hook
!= NULL
)
172 hdr
= (__ptr_t
) (*tr_old_malloc_hook
)(size
, caller
);
174 hdr
= (__ptr_t
) malloc (size
);
175 __malloc_hook
= tr_mallochook
;
177 tr_where (caller
, info
);
178 /* We could be printing a NULL here; that's OK. */
179 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
181 __libc_lock_unlock (lock
);
183 if (hdr
== mallwatch
)
189 static __ptr_t
tr_reallochook (__ptr_t
, size_t, const __ptr_t
)
191 static __ptr_t
tr_reallochook (ptr
, size
, caller
)
194 const __ptr_t caller
;
198 if (ptr
== mallwatch
)
202 Dl_info
*info
= lock_and_info (caller
, &mem
);
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
);
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
, info
);
219 /* Failed realloc. */
220 fprintf (mallstream
, "! %p %#lx\n", ptr
, (unsigned long int) size
);
222 fprintf (mallstream
, "- %p\n", ptr
);
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 (size_t, size_t,
242 const __ptr_t
) __THROW
;
243 static __ptr_t
tr_memalignhook (alignment
, size
, caller
)
244 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
= __libc_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 /* Do the reverse of what done in mtrace: first reset the hooks and
367 MALLSTREAM, and only after that write the trailer and close the
369 FILE *f
= mallstream
;
371 __free_hook
= tr_old_free_hook
;
372 __malloc_hook
= tr_old_malloc_hook
;
373 __realloc_hook
= tr_old_realloc_hook
;
374 __memalign_hook
= tr_old_memalign_hook
;
376 fprintf (f
, "= End\n");