Update.
[glibc.git] / malloc / mtrace.c
blobd9960bdaf3dbab6d63d26990d8f87a1cc8ff5e2b
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>
40 # include <libio/iolibio.h>
41 # define setvbuf(s, b, f, l) INTUSE(_IO_setvbuf) (s, b, f, l)
42 # define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
43 #endif
45 #ifndef attribute_hidden
46 # define attribute_hidden
47 #endif
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... */
58 __ptr_t mallwatch;
60 #ifdef USE_MTRACE_FILE
61 /* File name and line number information, for callers that had
62 the foresight to call through a macro. */
63 char *_mtrace_file;
64 int _mtrace_line;
65 #endif
67 /* Old hook values. */
68 static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
69 static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size,
70 const __ptr_t));
71 static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
72 __malloc_size_t size,
73 const __ptr_t));
75 /* This function is called when the block being alloc'd, realloc'd, or
76 freed has an address matching the variable "mallwatch". In a debugger,
77 set "mallwatch" to the address of interest, then put a breakpoint on
78 tr_break. */
80 void tr_break __P ((void));
81 void
82 tr_break ()
86 static void tr_where __P ((const __ptr_t)) internal_function;
87 static void
88 internal_function
89 tr_where (caller)
90 const __ptr_t caller;
92 #ifdef USE_MTRACE_FILE
93 if (_mtrace_file)
95 fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
96 _mtrace_file = NULL;
98 else
99 #endif
100 if (caller != NULL)
102 #ifdef HAVE_ELF
103 Dl_info info;
104 if (_dl_addr (caller, &info))
106 char *buf = (char *) "";
107 if (info.dli_sname != NULL)
109 size_t len = strlen (info.dli_sname);
110 buf = alloca (len + 6 + 2 * sizeof (void *));
112 buf[0] = '(';
113 __stpcpy (_fitoa (caller >= (const __ptr_t) info.dli_saddr
114 ? caller - (const __ptr_t) info.dli_saddr
115 : (const __ptr_t) info.dli_saddr - caller,
116 __stpcpy (__mempcpy (buf + 1, info.dli_sname,
117 len),
118 caller >= (__ptr_t) info.dli_saddr
119 ? "+0x" : "-0x"),
120 16, 0),
121 ")");
124 fprintf (mallstream, "@ %s%s%s[%p] ",
125 info.dli_fname ?: "", info.dli_fname ? ":" : "",
126 buf, caller);
128 else
129 #endif
130 fprintf (mallstream, "@ [%p] ", caller);
134 static void tr_freehook __P ((__ptr_t, const __ptr_t));
135 static void
136 tr_freehook (ptr, caller)
137 __ptr_t ptr;
138 const __ptr_t caller;
140 if (ptr == NULL)
141 return;
142 __libc_lock_lock (lock);
143 tr_where (caller);
144 /* Be sure to print it first. */
145 fprintf (mallstream, "- %p\n", ptr);
146 __libc_lock_unlock (lock);
147 if (ptr == mallwatch)
148 tr_break ();
149 __libc_lock_lock (lock);
150 __free_hook = tr_old_free_hook;
151 if (tr_old_free_hook != NULL)
152 (*tr_old_free_hook) (ptr, caller);
153 else
154 free (ptr);
155 __free_hook = tr_freehook;
156 __libc_lock_unlock (lock);
159 static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
160 static __ptr_t
161 tr_mallochook (size, caller)
162 __malloc_size_t size;
163 const __ptr_t caller;
165 __ptr_t hdr;
167 __libc_lock_lock (lock);
169 __malloc_hook = tr_old_malloc_hook;
170 if (tr_old_malloc_hook != NULL)
171 hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
172 else
173 hdr = (__ptr_t) malloc (size);
174 __malloc_hook = tr_mallochook;
176 tr_where (caller);
177 /* We could be printing a NULL here; that's OK. */
178 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
180 __libc_lock_unlock (lock);
182 if (hdr == mallwatch)
183 tr_break ();
185 return hdr;
188 static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
189 static __ptr_t
190 tr_reallochook (ptr, size, caller)
191 __ptr_t ptr;
192 __malloc_size_t size;
193 const __ptr_t caller;
195 __ptr_t hdr;
197 if (ptr == mallwatch)
198 tr_break ();
200 __libc_lock_lock (lock);
202 __free_hook = tr_old_free_hook;
203 __malloc_hook = tr_old_malloc_hook;
204 __realloc_hook = tr_old_realloc_hook;
205 if (tr_old_realloc_hook != NULL)
206 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
207 else
208 hdr = (__ptr_t) realloc (ptr, size);
209 __free_hook = tr_freehook;
210 __malloc_hook = tr_mallochook;
211 __realloc_hook = tr_reallochook;
213 tr_where (caller);
214 if (hdr == NULL)
215 /* Failed realloc. */
216 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
217 else if (ptr == NULL)
218 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
219 else
221 fprintf (mallstream, "< %p\n", ptr);
222 tr_where (caller);
223 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
226 __libc_lock_unlock (lock);
228 if (hdr == mallwatch)
229 tr_break ();
231 return hdr;
235 #ifdef _LIBC
237 /* This function gets called to make sure all memory the library
238 allocates get freed and so does not irritate the user when studying
239 the mtrace output. */
240 static void
241 release_libc_mem (void)
243 /* Only call the free function if we still are running in mtrace mode. */
244 if (mallstream != NULL)
245 __libc_freeres ();
247 #endif
250 /* We enable tracing if either the environment variable MALLOC_TRACE
251 is set, or if the variable mallwatch has been patched to an address
252 that the debugging user wants us to stop on. When patching mallwatch,
253 don't forget to set a breakpoint on tr_break! */
255 void
256 mtrace ()
258 #ifdef _LIBC
259 static int added_atexit_handler;
260 #endif
261 char *mallfile;
263 /* Don't panic if we're called more than once. */
264 if (mallstream != NULL)
265 return;
267 #ifdef _LIBC
268 /* When compiling the GNU libc we use the secure getenv function
269 which prevents the misuse in case of SUID or SGID enabled
270 programs. */
271 mallfile = __secure_getenv (mallenv);
272 #else
273 mallfile = getenv (mallenv);
274 #endif
275 if (mallfile != NULL || mallwatch != NULL)
277 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
278 if (mallstream != NULL)
280 /* Make sure we close the file descriptor on exec. */
281 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
282 if (flags >= 0)
284 flags |= FD_CLOEXEC;
285 __fcntl (fileno (mallstream), F_SETFD, flags);
287 /* Be sure it doesn't malloc its buffer! */
288 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
289 fprintf (mallstream, "= Start\n");
290 tr_old_free_hook = __free_hook;
291 __free_hook = tr_freehook;
292 tr_old_malloc_hook = __malloc_hook;
293 __malloc_hook = tr_mallochook;
294 tr_old_realloc_hook = __realloc_hook;
295 __realloc_hook = tr_reallochook;
296 #ifdef _LIBC
297 if (!added_atexit_handler)
299 extern void *__dso_handle __attribute__ ((__weak__));
300 added_atexit_handler = 1;
301 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
302 &__dso_handle ? __dso_handle : NULL);
304 #endif
309 void
310 muntrace ()
312 if (mallstream == NULL)
313 return;
315 fprintf (mallstream, "= End\n");
316 fclose (mallstream);
317 mallstream = NULL;
318 __free_hook = tr_old_free_hook;
319 __malloc_hook = tr_old_malloc_hook;
320 __realloc_hook = tr_old_realloc_hook;