(ipc_perm): Put back __key.
[glibc.git] / malloc / mtrace.c
blobfddf137fa63c5888749be2d5f7df50578d9c822d
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
26 #include <malloc.h>
27 #include <mcheck.h>
28 #include <bits/libc-lock.h>
29 #endif
31 #include <dlfcn.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdlib.h>
37 #include <stdio-common/_itoa.h>
39 #ifdef _LIBC
40 # include <libc-internal.h>
41 #endif
43 #ifdef USE_IN_LIBIO
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)
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 /* File name and line number information, for callers that had
61 the foresight to call through a macro. */
62 char *_mtrace_file;
63 int _mtrace_line;
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,
68 const __ptr_t));
69 static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
70 __malloc_size_t size,
71 const __ptr_t));
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
76 tr_break. */
78 void tr_break __P ((void));
79 void
80 tr_break ()
84 static void tr_where __P ((const __ptr_t)) internal_function;
85 static void
86 internal_function
87 tr_where (caller)
88 const __ptr_t caller;
90 if (_mtrace_file)
92 fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
93 _mtrace_file = NULL;
95 else if (caller != NULL)
97 #ifdef HAVE_ELF
98 Dl_info info;
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 *));
107 buf[0] = '(';
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,
112 len),
113 caller >= (__ptr_t) info.dli_saddr
114 ? "+0x" : "-0x"),
115 16, 0),
116 ")");
119 fprintf (mallstream, "@ %s%s%s[%p] ",
120 info.dli_fname ?: "", info.dli_fname ? ":" : "",
121 buf, caller);
123 else
124 #endif
125 fprintf (mallstream, "@ [%p] ", caller);
129 static void tr_freehook __P ((__ptr_t, const __ptr_t));
130 static void
131 tr_freehook (ptr, caller)
132 __ptr_t ptr;
133 const __ptr_t caller;
135 if (ptr == NULL)
136 return;
137 __libc_lock_lock (lock);
138 tr_where (caller);
139 /* Be sure to print it first. */
140 fprintf (mallstream, "- %p\n", ptr);
141 __libc_lock_unlock (lock);
142 if (ptr == mallwatch)
143 tr_break ();
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);
148 else
149 free (ptr);
150 __free_hook = tr_freehook;
151 __libc_lock_unlock (lock);
154 static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
155 static __ptr_t
156 tr_mallochook (size, caller)
157 __malloc_size_t size;
158 const __ptr_t caller;
160 __ptr_t hdr;
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);
167 else
168 hdr = (__ptr_t) malloc (size);
169 __malloc_hook = tr_mallochook;
171 tr_where (caller);
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)
178 tr_break ();
180 return hdr;
183 static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
184 static __ptr_t
185 tr_reallochook (ptr, size, caller)
186 __ptr_t ptr;
187 __malloc_size_t size;
188 const __ptr_t caller;
190 __ptr_t hdr;
192 if (ptr == mallwatch)
193 tr_break ();
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);
202 else
203 hdr = (__ptr_t) realloc (ptr, size);
204 __free_hook = tr_freehook;
205 __malloc_hook = tr_mallochook;
206 __realloc_hook = tr_reallochook;
208 tr_where (caller);
209 if (hdr == NULL)
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);
214 else
216 fprintf (mallstream, "< %p\n", ptr);
217 tr_where (caller);
218 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
221 __libc_lock_unlock (lock);
223 if (hdr == mallwatch)
224 tr_break ();
226 return hdr;
230 #ifdef _LIBC
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. */
235 static void
236 release_libc_mem (void)
238 /* Only call the free function if we still are running in mtrace mode. */
239 if (mallstream != NULL)
240 __libc_freeres ();
242 #endif
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! */
250 void
251 mtrace ()
253 #ifdef _LIBC
254 static int added_atexit_handler;
255 #endif
256 char *mallfile;
258 /* Don't panic if we're called more than once. */
259 if (mallstream != NULL)
260 return;
262 #ifdef _LIBC
263 /* When compiling the GNU libc we use the secure getenv function
264 which prevents the misuse in case of SUID or SGID enabled
265 programs. */
266 mallfile = __secure_getenv (mallenv);
267 #else
268 mallfile = getenv (mallenv);
269 #endif
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);
277 if (flags >= 0)
279 flags |= FD_CLOEXEC;
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;
291 #ifdef _LIBC
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);
299 #endif
304 void
305 muntrace ()
307 if (mallstream == NULL)
308 return;
310 fprintf (mallstream, "= End\n");
311 fclose (mallstream);
312 mallstream = NULL;
313 __free_hook = tr_old_free_hook;
314 __malloc_hook = tr_old_malloc_hook;
315 __realloc_hook = tr_old_realloc_hook;