1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-1994,1996-1999,2000,2001 Free Software Foundation, Inc.
3 Written April 2, 1991 by John Gilmore of Cygnus Support.
4 Based on mcheck.c by Mike Haertel.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with this library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
21 The author may be reached (Email) at the address mike@ai.mit.edu,
22 or (US mail) as Mike Haertel c/o Free Software Foundation. */
24 #ifndef _MALLOC_INTERNAL
25 #define _MALLOC_INTERNAL
28 #include <bits/libc-lock.h>
37 #include <stdio-common/_itoa.h>
40 # include <libc-internal.h>
44 # include <libio/iolibio.h>
45 # define fopen(f, n) _IO_fopen64 (f, n)
46 # define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
49 #define TRACE_BUFFER_SIZE 512
51 static FILE *mallstream
;
52 static const char mallenv
[]= "MALLOC_TRACE";
53 static char malloc_trace_buffer
[TRACE_BUFFER_SIZE
];
55 __libc_lock_define_initialized (static, lock
);
57 /* Address to breakpoint on accesses to... */
60 /* File name and line number information, for callers that had
61 the foresight to call through a macro. */
65 /* Old hook values. */
66 static void (*tr_old_free_hook
) __P ((__ptr_t ptr
, const __ptr_t
));
67 static __ptr_t (*tr_old_malloc_hook
) __P ((__malloc_size_t size
,
69 static __ptr_t (*tr_old_realloc_hook
) __P ((__ptr_t ptr
,
73 /* This function is called when the block being alloc'd, realloc'd, or
74 freed has an address matching the variable "mallwatch". In a debugger,
75 set "mallwatch" to the address of interest, then put a breakpoint on
78 void tr_break
__P ((void));
84 static void tr_where
__P ((const __ptr_t
)) internal_function
;
92 fprintf (mallstream
, "@ %s:%d ", _mtrace_file
, _mtrace_line
);
95 else if (caller
!= NULL
)
99 if (_dl_addr (caller
, &info
))
101 char *buf
= (char *) "";
102 if (info
.dli_sname
&& info
.dli_sname
[0])
104 size_t len
= strlen (info
.dli_sname
);
105 buf
= alloca (len
+ 6 + 2 * sizeof (void *));
108 __stpcpy (_fitoa (caller
>= (const __ptr_t
) info
.dli_saddr
109 ? caller
- (const __ptr_t
) info
.dli_saddr
110 : (const __ptr_t
) info
.dli_saddr
- caller
,
111 __stpcpy (__mempcpy (buf
+ 1, info
.dli_sname
,
113 caller
>= (__ptr_t
) info
.dli_saddr
119 fprintf (mallstream
, "@ %s%s%s[%p] ",
120 info
.dli_fname
?: "", info
.dli_fname
? ":" : "",
125 fprintf (mallstream
, "@ [%p] ", caller
);
129 static void tr_freehook
__P ((__ptr_t
, const __ptr_t
));
131 tr_freehook (ptr
, caller
)
133 const __ptr_t caller
;
137 __libc_lock_lock (lock
);
139 /* Be sure to print it first. */
140 fprintf (mallstream
, "- %p\n", ptr
);
141 __libc_lock_unlock (lock
);
142 if (ptr
== mallwatch
)
144 __libc_lock_lock (lock
);
145 __free_hook
= tr_old_free_hook
;
146 if (tr_old_free_hook
!= NULL
)
147 (*tr_old_free_hook
) (ptr
, caller
);
150 __free_hook
= tr_freehook
;
151 __libc_lock_unlock (lock
);
154 static __ptr_t tr_mallochook
__P ((__malloc_size_t
, const __ptr_t
));
156 tr_mallochook (size
, caller
)
157 __malloc_size_t size
;
158 const __ptr_t caller
;
162 __libc_lock_lock (lock
);
164 __malloc_hook
= tr_old_malloc_hook
;
165 if (tr_old_malloc_hook
!= NULL
)
166 hdr
= (__ptr_t
) (*tr_old_malloc_hook
) (size
, caller
);
168 hdr
= (__ptr_t
) malloc (size
);
169 __malloc_hook
= tr_mallochook
;
172 /* We could be printing a NULL here; that's OK. */
173 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
175 __libc_lock_unlock (lock
);
177 if (hdr
== mallwatch
)
183 static __ptr_t tr_reallochook
__P ((__ptr_t
, __malloc_size_t
, const __ptr_t
));
185 tr_reallochook (ptr
, size
, caller
)
187 __malloc_size_t size
;
188 const __ptr_t caller
;
192 if (ptr
== mallwatch
)
195 __libc_lock_lock (lock
);
197 __free_hook
= tr_old_free_hook
;
198 __malloc_hook
= tr_old_malloc_hook
;
199 __realloc_hook
= tr_old_realloc_hook
;
200 if (tr_old_realloc_hook
!= NULL
)
201 hdr
= (__ptr_t
) (*tr_old_realloc_hook
) (ptr
, size
, caller
);
203 hdr
= (__ptr_t
) realloc (ptr
, size
);
204 __free_hook
= tr_freehook
;
205 __malloc_hook
= tr_mallochook
;
206 __realloc_hook
= tr_reallochook
;
210 /* Failed realloc. */
211 fprintf (mallstream
, "! %p %#lx\n", ptr
, (unsigned long int) size
);
212 else if (ptr
== NULL
)
213 fprintf (mallstream
, "+ %p %#lx\n", hdr
, (unsigned long int) size
);
216 fprintf (mallstream
, "< %p\n", ptr
);
218 fprintf (mallstream
, "> %p %#lx\n", hdr
, (unsigned long int) size
);
221 __libc_lock_unlock (lock
);
223 if (hdr
== mallwatch
)
232 /* This function gets called to make sure all memory the library
233 allocates get freed and so does not irritate the user when studying
234 the mtrace output. */
236 release_libc_mem (void)
238 /* Only call the free function if we still are running in mtrace mode. */
239 if (mallstream
!= NULL
)
245 /* We enable tracing if either the environment variable MALLOC_TRACE
246 is set, or if the variable mallwatch has been patched to an address
247 that the debugging user wants us to stop on. When patching mallwatch,
248 don't forget to set a breakpoint on tr_break! */
254 static int added_atexit_handler
;
258 /* Don't panic if we're called more than once. */
259 if (mallstream
!= NULL
)
263 /* When compiling the GNU libc we use the secure getenv function
264 which prevents the misuse in case of SUID or SGID enabled
266 mallfile
= __secure_getenv (mallenv
);
268 mallfile
= getenv (mallenv
);
270 if (mallfile
!= NULL
|| mallwatch
!= NULL
)
272 mallstream
= fopen (mallfile
!= NULL
? mallfile
: "/dev/null", "w");
273 if (mallstream
!= NULL
)
275 /* Make sure we close the file descriptor on exec. */
276 int flags
= __fcntl (fileno (mallstream
), F_GETFD
, 0);
280 __fcntl (fileno (mallstream
), F_SETFD
, flags
);
282 /* Be sure it doesn't malloc its buffer! */
283 setvbuf (mallstream
, malloc_trace_buffer
, _IOFBF
, TRACE_BUFFER_SIZE
);
284 fprintf (mallstream
, "= Start\n");
285 tr_old_free_hook
= __free_hook
;
286 __free_hook
= tr_freehook
;
287 tr_old_malloc_hook
= __malloc_hook
;
288 __malloc_hook
= tr_mallochook
;
289 tr_old_realloc_hook
= __realloc_hook
;
290 __realloc_hook
= tr_reallochook
;
292 if (!added_atexit_handler
)
294 extern void *__dso_handle
__attribute__ ((__weak__
));
295 added_atexit_handler
= 1;
296 __cxa_atexit ((void (*) (void *)) release_libc_mem
, NULL
,
297 &__dso_handle
? __dso_handle
: NULL
);
307 if (mallstream
== NULL
)
310 fprintf (mallstream
, "= End\n");
313 __free_hook
= tr_old_free_hook
;
314 __malloc_hook
= tr_old_malloc_hook
;
315 __realloc_hook
= tr_old_realloc_hook
;