1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991, 92, 93, 94, 96, 97, 98 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>
36 #ifndef __GNU_LIBRARY__
37 extern char *getenv ();
42 #if defined _LIBC && defined USE_IN_LIBIO
43 # include <libio/iolibio.h>
44 # define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
47 #define TRACE_BUFFER_SIZE 512
49 static FILE *mallstream;
50 static const char mallenv[]= "MALLOC_TRACE";
51 static char malloc_trace_buffer[TRACE_BUFFER_SIZE];
53 __libc_lock_define_initialized (static, lock);
55 /* Address to breakpoint on accesses to... */
58 /* File name and line number information, for callers that had
59 the foresight to call through a macro. */
63 /* Old hook values. */
64 static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
65 static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size,
67 static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
71 /* This function is called when the block being alloc'd, realloc'd, or
72 freed has an address matching the variable "mallwatch". In a debugger,
73 set "mallwatch" to the address of interest, then put a breakpoint on
76 void tr_break __P ((void));
82 static void tr_where __P ((const __ptr_t)) internal_function;
90 fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
93 else if (caller != NULL)
97 if (_dl_addr (caller, &info))
99 char *buf = (char *) "";
100 if (info.dli_sname && info.dli_sname[0])
102 size_t len = strlen (info.dli_sname) + 22;
104 if (caller >= (const __ptr_t) info.dli_saddr)
105 snprintf (buf, len, "(%s+0x%x)", info.dli_sname,
106 caller - (const __ptr_t) info.dli_saddr);
108 snprintf (buf, len, "(%s-0x%x)", info.dli_sname,
109 (const __ptr_t) info.dli_saddr - caller);
112 fprintf (mallstream, "@ %s%s%s[%p] ",
113 info.dli_fname ?: "", info.dli_fname ? ":" : "",
118 fprintf (mallstream, "@ [%p] ", caller);
122 static void tr_freehook __P ((__ptr_t, const __ptr_t));
124 tr_freehook (ptr, caller)
126 const __ptr_t caller;
129 /* Be sure to print it first. */
130 fprintf (mallstream, "- %p\n", ptr);
131 if (ptr == mallwatch)
133 __libc_lock_lock (lock);
134 __free_hook = tr_old_free_hook;
135 if (tr_old_free_hook != NULL)
136 (*tr_old_free_hook) (ptr, caller);
139 __free_hook = tr_freehook;
140 __libc_lock_unlock (lock);
143 static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
145 tr_mallochook (size, caller)
146 __malloc_size_t size;
147 const __ptr_t caller;
151 __libc_lock_lock (lock);
153 __malloc_hook = tr_old_malloc_hook;
154 if (tr_old_malloc_hook != NULL)
155 hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
157 hdr = (__ptr_t) malloc (size);
158 __malloc_hook = tr_mallochook;
160 __libc_lock_unlock (lock);
163 /* We could be printing a NULL here; that's OK. */
164 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
166 if (hdr == mallwatch)
172 static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
174 tr_reallochook (ptr, size, caller)
176 __malloc_size_t size;
177 const __ptr_t caller;
181 if (ptr == mallwatch)
184 __libc_lock_lock (lock);
186 __free_hook = tr_old_free_hook;
187 __malloc_hook = tr_old_malloc_hook;
188 __realloc_hook = tr_old_realloc_hook;
189 if (tr_old_realloc_hook != NULL)
190 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
192 hdr = (__ptr_t) realloc (ptr, size);
193 __free_hook = tr_freehook;
194 __malloc_hook = tr_mallochook;
195 __realloc_hook = tr_reallochook;
197 __libc_lock_unlock (lock);
201 /* Failed realloc. */
202 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
203 else if (ptr == NULL)
204 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
207 fprintf (mallstream, "< %p\n", ptr);
209 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
212 if (hdr == mallwatch)
220 extern void __libc_freeres (void);
222 /* This function gets called to make sure all memory the library
223 allocates get freed and so does not irritate the user when studying
224 the mtrace output. */
226 release_libc_mem (void)
228 /* Only call the free function if we still are running in mtrace mode. */
229 if (mallstream != NULL)
235 /* We enable tracing if either the environment variable MALLOC_TRACE
236 is set, or if the variable mallwatch has been patched to an address
237 that the debugging user wants us to stop on. When patching mallwatch,
238 don't forget to set a breakpoint on tr_break! */
244 static int added_atexit_handler = 0;
248 /* Don't panic if we're called more than once. */
249 if (mallstream != NULL)
253 /* When compiling the GNU libc we use the secure getenv function
254 which prevents the misuse in case of SUID or SGID enabled
256 mallfile = __secure_getenv (mallenv);
258 mallfile = getenv (mallenv);
260 if (mallfile != NULL || mallwatch != NULL)
262 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
263 if (mallstream != NULL)
265 /* Be sure it doesn't malloc its buffer! */
266 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
267 fprintf (mallstream, "= Start\n");
268 tr_old_free_hook = __free_hook;
269 __free_hook = tr_freehook;
270 tr_old_malloc_hook = __malloc_hook;
271 __malloc_hook = tr_mallochook;
272 tr_old_realloc_hook = __realloc_hook;
273 __realloc_hook = tr_reallochook;
275 if (!added_atexit_handler)
277 added_atexit_handler = 1;
278 atexit (release_libc_mem);
288 if (mallstream == NULL)
291 fprintf (mallstream, "= End\n");
294 __free_hook = tr_old_free_hook;
295 __malloc_hook = tr_old_malloc_hook;
296 __realloc_hook = tr_old_realloc_hook;