Update.
[glibc.git] / malloc / mtrace.c
blobacee3c411b03f350292ad204730801e02e0d659f
1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-1994,1996-2001,2002 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, write to the Free
19 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA. */
22 #ifndef _MALLOC_INTERNAL
23 #define _MALLOC_INTERNAL
24 #include <malloc.h>
25 #include <mcheck.h>
26 #include <bits/libc-lock.h>
27 #endif
29 #include <dlfcn.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
35 #include <stdio-common/_itoa.h>
37 #ifdef _LIBC
38 # include <libc-internal.h>
39 #endif
41 #ifdef USE_IN_LIBIO
42 # include <libio/iolibio.h>
43 # define fopen(f, n) _IO_fopen64 (f, n)
44 # define setvbuf(s, b, f, l) INTUSE(_IO_setvbuf) (s, b, f, l)
45 #endif
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... */
56 __ptr_t mallwatch;
58 /* File name and line number information, for callers that had
59 the foresight to call through a macro. */
60 char *_mtrace_file;
61 int _mtrace_line;
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,
66 const __ptr_t));
67 static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
68 __malloc_size_t size,
69 const __ptr_t));
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
74 tr_break. */
76 void tr_break __P ((void));
77 void
78 tr_break ()
82 static void tr_where __P ((const __ptr_t)) internal_function;
83 static void
84 internal_function
85 tr_where (caller)
86 const __ptr_t caller;
88 if (_mtrace_file)
90 fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
91 _mtrace_file = NULL;
93 else if (caller != NULL)
95 #ifdef HAVE_ELF
96 Dl_info info;
97 if (_dl_addr (caller, &info))
99 char *buf = (char *) "";
100 if (info.dli_sname != NULL)
102 size_t len = strlen (info.dli_sname);
103 buf = alloca (len + 6 + 2 * sizeof (void *));
105 buf[0] = '(';
106 __stpcpy (_fitoa (caller >= (const __ptr_t) info.dli_saddr
107 ? caller - (const __ptr_t) info.dli_saddr
108 : (const __ptr_t) info.dli_saddr - caller,
109 __stpcpy (__mempcpy (buf + 1, info.dli_sname,
110 len),
111 caller >= (__ptr_t) info.dli_saddr
112 ? "+0x" : "-0x"),
113 16, 0),
114 ")");
117 fprintf (mallstream, "@ %s%s%s[%p] ",
118 info.dli_fname ?: "", info.dli_fname ? ":" : "",
119 buf, caller);
121 else
122 #endif
123 fprintf (mallstream, "@ [%p] ", caller);
127 static void tr_freehook __P ((__ptr_t, const __ptr_t));
128 static void
129 tr_freehook (ptr, caller)
130 __ptr_t ptr;
131 const __ptr_t caller;
133 if (ptr == NULL)
134 return;
135 __libc_lock_lock (lock);
136 tr_where (caller);
137 /* Be sure to print it first. */
138 fprintf (mallstream, "- %p\n", ptr);
139 __libc_lock_unlock (lock);
140 if (ptr == mallwatch)
141 tr_break ();
142 __libc_lock_lock (lock);
143 __free_hook = tr_old_free_hook;
144 if (tr_old_free_hook != NULL)
145 (*tr_old_free_hook) (ptr, caller);
146 else
147 free (ptr);
148 __free_hook = tr_freehook;
149 __libc_lock_unlock (lock);
152 static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
153 static __ptr_t
154 tr_mallochook (size, caller)
155 __malloc_size_t size;
156 const __ptr_t caller;
158 __ptr_t hdr;
160 __libc_lock_lock (lock);
162 __malloc_hook = tr_old_malloc_hook;
163 if (tr_old_malloc_hook != NULL)
164 hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
165 else
166 hdr = (__ptr_t) malloc (size);
167 __malloc_hook = tr_mallochook;
169 tr_where (caller);
170 /* We could be printing a NULL here; that's OK. */
171 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
173 __libc_lock_unlock (lock);
175 if (hdr == mallwatch)
176 tr_break ();
178 return hdr;
181 static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
182 static __ptr_t
183 tr_reallochook (ptr, size, caller)
184 __ptr_t ptr;
185 __malloc_size_t size;
186 const __ptr_t caller;
188 __ptr_t hdr;
190 if (ptr == mallwatch)
191 tr_break ();
193 __libc_lock_lock (lock);
195 __free_hook = tr_old_free_hook;
196 __malloc_hook = tr_old_malloc_hook;
197 __realloc_hook = tr_old_realloc_hook;
198 if (tr_old_realloc_hook != NULL)
199 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
200 else
201 hdr = (__ptr_t) realloc (ptr, size);
202 __free_hook = tr_freehook;
203 __malloc_hook = tr_mallochook;
204 __realloc_hook = tr_reallochook;
206 tr_where (caller);
207 if (hdr == NULL)
208 /* Failed realloc. */
209 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
210 else if (ptr == NULL)
211 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
212 else
214 fprintf (mallstream, "< %p\n", ptr);
215 tr_where (caller);
216 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
219 __libc_lock_unlock (lock);
221 if (hdr == mallwatch)
222 tr_break ();
224 return hdr;
228 #ifdef _LIBC
230 /* This function gets called to make sure all memory the library
231 allocates get freed and so does not irritate the user when studying
232 the mtrace output. */
233 static void
234 release_libc_mem (void)
236 /* Only call the free function if we still are running in mtrace mode. */
237 if (mallstream != NULL)
238 __libc_freeres ();
240 #endif
243 /* We enable tracing if either the environment variable MALLOC_TRACE
244 is set, or if the variable mallwatch has been patched to an address
245 that the debugging user wants us to stop on. When patching mallwatch,
246 don't forget to set a breakpoint on tr_break! */
248 void
249 mtrace ()
251 #ifdef _LIBC
252 static int added_atexit_handler;
253 #endif
254 char *mallfile;
256 /* Don't panic if we're called more than once. */
257 if (mallstream != NULL)
258 return;
260 #ifdef _LIBC
261 /* When compiling the GNU libc we use the secure getenv function
262 which prevents the misuse in case of SUID or SGID enabled
263 programs. */
264 mallfile = __secure_getenv (mallenv);
265 #else
266 mallfile = getenv (mallenv);
267 #endif
268 if (mallfile != NULL || mallwatch != NULL)
270 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
271 if (mallstream != NULL)
273 /* Make sure we close the file descriptor on exec. */
274 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
275 if (flags >= 0)
277 flags |= FD_CLOEXEC;
278 __fcntl (fileno (mallstream), F_SETFD, flags);
280 /* Be sure it doesn't malloc its buffer! */
281 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
282 fprintf (mallstream, "= Start\n");
283 tr_old_free_hook = __free_hook;
284 __free_hook = tr_freehook;
285 tr_old_malloc_hook = __malloc_hook;
286 __malloc_hook = tr_mallochook;
287 tr_old_realloc_hook = __realloc_hook;
288 __realloc_hook = tr_reallochook;
289 #ifdef _LIBC
290 if (!added_atexit_handler)
292 extern void *__dso_handle __attribute__ ((__weak__));
293 added_atexit_handler = 1;
294 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
295 &__dso_handle ? __dso_handle : NULL);
297 #endif
302 void
303 muntrace ()
305 if (mallstream == NULL)
306 return;
308 fprintf (mallstream, "= End\n");
309 fclose (mallstream);
310 mallstream = NULL;
311 __free_hook = tr_old_free_hook;
312 __malloc_hook = tr_old_malloc_hook;
313 __realloc_hook = tr_old_realloc_hook;