1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-2018 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>
37 #include <dso_handle.h>
39 #include <libio/iolibio.h>
40 #define setvbuf(s, b, f, l) _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 #define TRACE_BUFFER_SIZE 512
47 static FILE *mallstream
;
48 static const char mallenv
[] = "MALLOC_TRACE";
49 static char *malloc_trace_buffer
;
51 __libc_lock_define_initialized (static, lock
);
53 /* Address to breakpoint on accesses to... */
56 /* Old hook values. */
57 static void (*tr_old_free_hook
) (void *ptr
, const void *);
58 static void *(*tr_old_malloc_hook
) (size_t size
, const void *);
59 static void *(*tr_old_realloc_hook
) (void *ptr
, size_t size
,
61 static void *(*tr_old_memalign_hook
) (size_t __alignment
, size_t __size
,
64 /* This function is called when the block being alloc'd, realloc'd, or
65 freed has an address matching the variable "mallwatch". In a debugger,
66 set "mallwatch" to the address of interest, then put a breakpoint on
69 extern void tr_break (void) __THROW
;
70 libc_hidden_proto (tr_break
)
75 libc_hidden_def (tr_break
)
78 tr_where (const void *caller
, Dl_info
*info
)
84 char *buf
= (char *) "";
85 if (info
->dli_sname
!= NULL
)
87 size_t len
= strlen (info
->dli_sname
);
88 buf
= alloca (len
+ 6 + 2 * sizeof (void *));
91 __stpcpy (_fitoa (caller
>= (const void *) info
->dli_saddr
92 ? caller
- (const void *) info
->dli_saddr
93 : (const void *) info
->dli_saddr
- caller
,
94 __stpcpy (__mempcpy (buf
+ 1, info
->dli_sname
,
96 caller
>= (void *) info
->dli_saddr
102 fprintf (mallstream
, "@ %s%s%s[%p] ",
103 info
->dli_fname
? : "", info
->dli_fname
? ":" : "",
107 fprintf (mallstream
, "@ [%p] ", caller
);
112 lock_and_info (const void *caller
, Dl_info
*mem
)
117 Dl_info
*res
= _dl_addr (caller
, mem
, NULL
, NULL
) ? mem
: NULL
;
119 __libc_lock_lock (lock
);
125 tr_freehook (void *ptr
, const void *caller
)
131 Dl_info
*info
= lock_and_info (caller
, &mem
);
132 tr_where (caller
, info
);
133 /* Be sure to print it first. */
134 fprintf (mallstream
, "- %p\n", ptr
);
135 if (ptr
== mallwatch
)
137 __libc_lock_unlock (lock
);
139 __libc_lock_lock (lock
);
141 __free_hook
= tr_old_free_hook
;
142 if (tr_old_free_hook
!= NULL
)
143 (*tr_old_free_hook
)(ptr
, caller
);
146 __free_hook
= tr_freehook
;
147 __libc_lock_unlock (lock
);
151 tr_mallochook (size_t size
, const void *caller
)
156 Dl_info
*info
= lock_and_info (caller
, &mem
);
158 __malloc_hook
= tr_old_malloc_hook
;
159 if (tr_old_malloc_hook
!= NULL
)
160 hdr
= (void *) (*tr_old_malloc_hook
)(size
, caller
);
162 hdr
= (void *) malloc (size
);
163 __malloc_hook
= tr_mallochook
;
165 tr_where (caller
, info
);
166 /* We could be printing a NULL here; that's OK. */
167 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
169 __libc_lock_unlock (lock
);
171 if (hdr
== mallwatch
)
178 tr_reallochook (void *ptr
, size_t size
, const void *caller
)
182 if (ptr
== mallwatch
)
186 Dl_info
*info
= lock_and_info (caller
, &mem
);
188 __free_hook
= tr_old_free_hook
;
189 __malloc_hook
= tr_old_malloc_hook
;
190 __realloc_hook
= tr_old_realloc_hook
;
191 if (tr_old_realloc_hook
!= NULL
)
192 hdr
= (void *) (*tr_old_realloc_hook
)(ptr
, size
, caller
);
194 hdr
= (void *) realloc (ptr
, size
);
195 __free_hook
= tr_freehook
;
196 __malloc_hook
= tr_mallochook
;
197 __realloc_hook
= tr_reallochook
;
199 tr_where (caller
, info
);
203 /* Failed realloc. */
204 fprintf (mallstream
, "! %p %#lx\n", ptr
, (unsigned long int) size
);
206 fprintf (mallstream
, "- %p\n", ptr
);
208 else if (ptr
== NULL
)
209 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
212 fprintf (mallstream
, "< %p\n", ptr
);
213 tr_where (caller
, info
);
214 fprintf (mallstream
, "> %p %#lx\n", hdr
, (unsigned long int) size
);
217 __libc_lock_unlock (lock
);
219 if (hdr
== mallwatch
)
226 tr_memalignhook (size_t alignment
, size_t size
, const void *caller
)
231 Dl_info
*info
= lock_and_info (caller
, &mem
);
233 __memalign_hook
= tr_old_memalign_hook
;
234 __malloc_hook
= tr_old_malloc_hook
;
235 if (tr_old_memalign_hook
!= NULL
)
236 hdr
= (void *) (*tr_old_memalign_hook
)(alignment
, size
, caller
);
238 hdr
= (void *) memalign (alignment
, size
);
239 __memalign_hook
= tr_memalignhook
;
240 __malloc_hook
= tr_mallochook
;
242 tr_where (caller
, info
);
243 /* We could be printing a NULL here; that's OK. */
244 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
246 __libc_lock_unlock (lock
);
248 if (hdr
== mallwatch
)
257 /* This function gets called to make sure all memory the library
258 allocates get freed and so does not irritate the user when studying
259 the mtrace output. */
260 static void __libc_freeres_fn_section
261 release_libc_mem (void)
263 /* Only call the free function if we still are running in mtrace mode. */
264 if (mallstream
!= NULL
)
270 /* We enable tracing if either the environment variable MALLOC_TRACE
271 is set, or if the variable mallwatch has been patched to an address
272 that the debugging user wants us to stop on. When patching mallwatch,
273 don't forget to set a breakpoint on tr_break! */
279 static int added_atexit_handler
;
283 /* Don't panic if we're called more than once. */
284 if (mallstream
!= NULL
)
288 /* When compiling the GNU libc we use the secure getenv function
289 which prevents the misuse in case of SUID or SGID enabled
291 mallfile
= __libc_secure_getenv (mallenv
);
293 mallfile
= getenv (mallenv
);
295 if (mallfile
!= NULL
|| mallwatch
!= NULL
)
297 char *mtb
= malloc (TRACE_BUFFER_SIZE
);
301 mallstream
= fopen (mallfile
!= NULL
? mallfile
: "/dev/null", "wce");
302 if (mallstream
!= NULL
)
304 /* Be sure it doesn't malloc its buffer! */
305 malloc_trace_buffer
= mtb
;
306 setvbuf (mallstream
, malloc_trace_buffer
, _IOFBF
, TRACE_BUFFER_SIZE
);
307 fprintf (mallstream
, "= Start\n");
308 tr_old_free_hook
= __free_hook
;
309 __free_hook
= tr_freehook
;
310 tr_old_malloc_hook
= __malloc_hook
;
311 __malloc_hook
= tr_mallochook
;
312 tr_old_realloc_hook
= __realloc_hook
;
313 __realloc_hook
= tr_reallochook
;
314 tr_old_memalign_hook
= __memalign_hook
;
315 __memalign_hook
= tr_memalignhook
;
317 if (!added_atexit_handler
)
319 added_atexit_handler
= 1;
320 __cxa_atexit ((void (*)(void *))release_libc_mem
, NULL
,
333 if (mallstream
== NULL
)
336 /* Do the reverse of what done in mtrace: first reset the hooks and
337 MALLSTREAM, and only after that write the trailer and close the
339 FILE *f
= mallstream
;
341 __free_hook
= tr_old_free_hook
;
342 __malloc_hook
= tr_old_malloc_hook
;
343 __realloc_hook
= tr_old_realloc_hook
;
344 __memalign_hook
= tr_old_memalign_hook
;
346 fprintf (f
, "= End\n");