1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-2016 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 <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 #define TRACE_BUFFER_SIZE 512
46 static FILE *mallstream
;
47 static const char mallenv
[] = "MALLOC_TRACE";
48 static char *malloc_trace_buffer
;
50 __libc_lock_define_initialized (static, lock
);
52 /* Address to breakpoint on accesses to... */
55 /* Old hook values. */
56 static void (*tr_old_free_hook
) (__ptr_t ptr
, const __ptr_t
);
57 static __ptr_t (*tr_old_malloc_hook
) (size_t size
, const __ptr_t
);
58 static __ptr_t (*tr_old_realloc_hook
) (__ptr_t ptr
, size_t size
,
60 static __ptr_t (*tr_old_memalign_hook
) (size_t __alignment
, size_t __size
,
63 /* This function is called when the block being alloc'd, realloc'd, or
64 freed has an address matching the variable "mallwatch". In a debugger,
65 set "mallwatch" to the address of interest, then put a breakpoint on
68 extern void tr_break (void) __THROW
;
69 libc_hidden_proto (tr_break
)
74 libc_hidden_def (tr_break
)
76 static void internal_function
77 tr_where (const __ptr_t caller
, Dl_info
*info
)
83 char *buf
= (char *) "";
84 if (info
->dli_sname
!= NULL
)
86 size_t len
= strlen (info
->dli_sname
);
87 buf
= alloca (len
+ 6 + 2 * sizeof (void *));
90 __stpcpy (_fitoa (caller
>= (const __ptr_t
) info
->dli_saddr
91 ? caller
- (const __ptr_t
) info
->dli_saddr
92 : (const __ptr_t
) info
->dli_saddr
- caller
,
93 __stpcpy (__mempcpy (buf
+ 1, info
->dli_sname
,
95 caller
>= (__ptr_t
) info
->dli_saddr
101 fprintf (mallstream
, "@ %s%s%s[%p] ",
102 info
->dli_fname
? : "", info
->dli_fname
? ":" : "",
106 fprintf (mallstream
, "@ [%p] ", caller
);
111 lock_and_info (const __ptr_t caller
, Dl_info
*mem
)
116 Dl_info
*res
= _dl_addr (caller
, mem
, NULL
, NULL
) ? mem
: NULL
;
118 __libc_lock_lock (lock
);
124 tr_freehook (__ptr_t ptr
, const __ptr_t caller
)
130 Dl_info
*info
= lock_and_info (caller
, &mem
);
131 tr_where (caller
, info
);
132 /* Be sure to print it first. */
133 fprintf (mallstream
, "- %p\n", ptr
);
134 if (ptr
== mallwatch
)
136 __libc_lock_unlock (lock
);
138 __libc_lock_lock (lock
);
140 __free_hook
= tr_old_free_hook
;
141 if (tr_old_free_hook
!= NULL
)
142 (*tr_old_free_hook
)(ptr
, caller
);
145 __free_hook
= tr_freehook
;
146 __libc_lock_unlock (lock
);
150 tr_mallochook (size_t size
, const __ptr_t caller
)
155 Dl_info
*info
= lock_and_info (caller
, &mem
);
157 __malloc_hook
= tr_old_malloc_hook
;
158 if (tr_old_malloc_hook
!= NULL
)
159 hdr
= (__ptr_t
) (*tr_old_malloc_hook
)(size
, caller
);
161 hdr
= (__ptr_t
) malloc (size
);
162 __malloc_hook
= tr_mallochook
;
164 tr_where (caller
, info
);
165 /* We could be printing a NULL here; that's OK. */
166 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
168 __libc_lock_unlock (lock
);
170 if (hdr
== mallwatch
)
177 tr_reallochook (__ptr_t ptr
, size_t size
, const __ptr_t caller
)
181 if (ptr
== mallwatch
)
185 Dl_info
*info
= lock_and_info (caller
, &mem
);
187 __free_hook
= tr_old_free_hook
;
188 __malloc_hook
= tr_old_malloc_hook
;
189 __realloc_hook
= tr_old_realloc_hook
;
190 if (tr_old_realloc_hook
!= NULL
)
191 hdr
= (__ptr_t
) (*tr_old_realloc_hook
)(ptr
, size
, caller
);
193 hdr
= (__ptr_t
) realloc (ptr
, size
);
194 __free_hook
= tr_freehook
;
195 __malloc_hook
= tr_mallochook
;
196 __realloc_hook
= tr_reallochook
;
198 tr_where (caller
, info
);
202 /* Failed realloc. */
203 fprintf (mallstream
, "! %p %#lx\n", ptr
, (unsigned long int) size
);
205 fprintf (mallstream
, "- %p\n", ptr
);
207 else if (ptr
== NULL
)
208 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
211 fprintf (mallstream
, "< %p\n", ptr
);
212 tr_where (caller
, info
);
213 fprintf (mallstream
, "> %p %#lx\n", hdr
, (unsigned long int) size
);
216 __libc_lock_unlock (lock
);
218 if (hdr
== mallwatch
)
225 tr_memalignhook (size_t alignment
, size_t size
, const __ptr_t caller
)
230 Dl_info
*info
= lock_and_info (caller
, &mem
);
232 __memalign_hook
= tr_old_memalign_hook
;
233 __malloc_hook
= tr_old_malloc_hook
;
234 if (tr_old_memalign_hook
!= NULL
)
235 hdr
= (__ptr_t
) (*tr_old_memalign_hook
)(alignment
, size
, caller
);
237 hdr
= (__ptr_t
) memalign (alignment
, size
);
238 __memalign_hook
= tr_memalignhook
;
239 __malloc_hook
= tr_mallochook
;
241 tr_where (caller
, info
);
242 /* We could be printing a NULL here; that's OK. */
243 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
245 __libc_lock_unlock (lock
);
247 if (hdr
== mallwatch
)
256 /* This function gets called to make sure all memory the library
257 allocates get freed and so does not irritate the user when studying
258 the mtrace output. */
259 static void __libc_freeres_fn_section
260 release_libc_mem (void)
262 /* Only call the free function if we still are running in mtrace mode. */
263 if (mallstream
!= NULL
)
269 /* We enable tracing if either the environment variable MALLOC_TRACE
270 is set, or if the variable mallwatch has been patched to an address
271 that the debugging user wants us to stop on. When patching mallwatch,
272 don't forget to set a breakpoint on tr_break! */
278 static int added_atexit_handler
;
282 /* Don't panic if we're called more than once. */
283 if (mallstream
!= NULL
)
287 /* When compiling the GNU libc we use the secure getenv function
288 which prevents the misuse in case of SUID or SGID enabled
290 mallfile
= __libc_secure_getenv (mallenv
);
292 mallfile
= getenv (mallenv
);
294 if (mallfile
!= NULL
|| mallwatch
!= NULL
)
296 char *mtb
= malloc (TRACE_BUFFER_SIZE
);
300 mallstream
= fopen (mallfile
!= NULL
? mallfile
: "/dev/null", "wce");
301 if (mallstream
!= NULL
)
303 #ifndef __ASSUME_O_CLOEXEC
304 /* Make sure we close the file descriptor on exec. */
305 int flags
= __fcntl (fileno (mallstream
), F_GETFD
, 0);
309 __fcntl (fileno (mallstream
), F_SETFD
, flags
);
312 /* Be sure it doesn't malloc its buffer! */
313 malloc_trace_buffer
= mtb
;
314 setvbuf (mallstream
, malloc_trace_buffer
, _IOFBF
, TRACE_BUFFER_SIZE
);
315 fprintf (mallstream
, "= Start\n");
316 tr_old_free_hook
= __free_hook
;
317 __free_hook
= tr_freehook
;
318 tr_old_malloc_hook
= __malloc_hook
;
319 __malloc_hook
= tr_mallochook
;
320 tr_old_realloc_hook
= __realloc_hook
;
321 __realloc_hook
= tr_reallochook
;
322 tr_old_memalign_hook
= __memalign_hook
;
323 __memalign_hook
= tr_memalignhook
;
325 if (!added_atexit_handler
)
327 extern void *__dso_handle
__attribute__ ((__weak__
));
328 added_atexit_handler
= 1;
329 __cxa_atexit ((void (*)(void *))release_libc_mem
, NULL
,
330 &__dso_handle
? __dso_handle
: NULL
);
342 if (mallstream
== NULL
)
345 /* Do the reverse of what done in mtrace: first reset the hooks and
346 MALLSTREAM, and only after that write the trailer and close the
348 FILE *f
= mallstream
;
350 __free_hook
= tr_old_free_hook
;
351 __malloc_hook
= tr_old_malloc_hook
;
352 __realloc_hook
= tr_old_realloc_hook
;
353 __memalign_hook
= tr_old_memalign_hook
;
355 fprintf (f
, "= End\n");