]> git.ipfire.org Git - thirdparty/glibc.git/blame - malloc/mtrace.c
Update.
[thirdparty/glibc.git] / malloc / mtrace.c
CommitLineData
6d52618b 1/* More debugging hooks for `malloc'.
77fe0b9c 2 Copyright (C) 1991-1994,1996-2001,2002 Free Software Foundation, Inc.
41bdb6e2 3 This file is part of the GNU C Library.
6d52618b
UD
4 Written April 2, 1991 by John Gilmore of Cygnus Support.
5 Based on mcheck.c by Mike Haertel.
6
41bdb6e2
AJ
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.
6d52618b 11
41bdb6e2 12 The GNU C Library is distributed in the hope that it will be useful,
6d52618b
UD
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 15 Lesser General Public License for more details.
6d52618b 16
41bdb6e2
AJ
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. */
6d52618b
UD
21
22#ifndef _MALLOC_INTERNAL
23#define _MALLOC_INTERNAL
24#include <malloc.h>
25#include <mcheck.h>
5107cf1d 26#include <bits/libc-lock.h>
6d52618b
UD
27#endif
28
b3fc5f84 29#include <dlfcn.h>
755104ed 30#include <fcntl.h>
6d52618b 31#include <stdio.h>
e03c3361 32#include <string.h>
6d52618b 33#include <stdlib.h>
6d52618b 34
d5cabaa4
UD
35#include <stdio-common/_itoa.h>
36
66539a73
AJ
37#ifdef _LIBC
38# include <libc-internal.h>
39#endif
40
d5cabaa4 41#ifdef USE_IN_LIBIO
08a0d60a 42# include <libio/iolibio.h>
4c48dc93 43# define fopen(f, n) _IO_fopen64 (f, n)
77fe0b9c 44# define setvbuf(s, b, f, l) INTUSE(_IO_setvbuf) (s, b, f, l)
50304ef0
UD
45#endif
46
e7993f20
UD
47#define TRACE_BUFFER_SIZE 512
48
6d52618b 49static FILE *mallstream;
bd355af0 50static const char mallenv[]= "MALLOC_TRACE";
e7993f20 51static char malloc_trace_buffer[TRACE_BUFFER_SIZE];
6d52618b
UD
52
53__libc_lock_define_initialized (static, lock);
54
55/* Address to breakpoint on accesses to... */
56__ptr_t mallwatch;
57
58/* File name and line number information, for callers that had
59 the foresight to call through a macro. */
60char *_mtrace_file;
61int _mtrace_line;
62
63/* Old hook values. */
a2b08ee5
UD
64static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
65static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size,
66 const __ptr_t));
67static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
68 __malloc_size_t size,
69 const __ptr_t));
6d52618b
UD
70
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. */
75
76void tr_break __P ((void));
77void
78tr_break ()
79{
80}
81
dfd2257a 82static void tr_where __P ((const __ptr_t)) internal_function;
6d52618b 83static void
dfd2257a 84internal_function
a2b08ee5
UD
85tr_where (caller)
86 const __ptr_t caller;
6d52618b
UD
87{
88 if (_mtrace_file)
89 {
90 fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
91 _mtrace_file = NULL;
92 }
a2b08ee5
UD
93 else if (caller != NULL)
94 {
95#ifdef HAVE_ELF
96 Dl_info info;
97 if (_dl_addr (caller, &info))
98 {
604510f7 99 char *buf = (char *) "";
46b05e5d 100 if (info.dli_sname != NULL)
604510f7 101 {
d5cabaa4
UD
102 size_t len = strlen (info.dli_sname);
103 buf = alloca (len + 6 + 2 * sizeof (void *));
104
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 ")");
604510f7
UD
115 }
116
117 fprintf (mallstream, "@ %s%s%s[%p] ",
a2b08ee5 118 info.dli_fname ?: "", info.dli_fname ? ":" : "",
604510f7 119 buf, caller);
a2b08ee5
UD
120 }
121 else
122#endif
123 fprintf (mallstream, "@ [%p] ", caller);
124 }
6d52618b
UD
125}
126
a2b08ee5 127static void tr_freehook __P ((__ptr_t, const __ptr_t));
6d52618b 128static void
a2b08ee5 129tr_freehook (ptr, caller)
6d52618b 130 __ptr_t ptr;
a2b08ee5 131 const __ptr_t caller;
6d52618b 132{
55465bd9
UD
133 if (ptr == NULL)
134 return;
92e4472f 135 __libc_lock_lock (lock);
a2b08ee5
UD
136 tr_where (caller);
137 /* Be sure to print it first. */
138 fprintf (mallstream, "- %p\n", ptr);
92e4472f 139 __libc_lock_unlock (lock);
6d52618b
UD
140 if (ptr == mallwatch)
141 tr_break ();
142 __libc_lock_lock (lock);
143 __free_hook = tr_old_free_hook;
a2b08ee5
UD
144 if (tr_old_free_hook != NULL)
145 (*tr_old_free_hook) (ptr, caller);
146 else
147 free (ptr);
6d52618b
UD
148 __free_hook = tr_freehook;
149 __libc_lock_unlock (lock);
150}
151
a2b08ee5 152static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
6d52618b 153static __ptr_t
a2b08ee5 154tr_mallochook (size, caller)
6d52618b 155 __malloc_size_t size;
a2b08ee5 156 const __ptr_t caller;
6d52618b
UD
157{
158 __ptr_t hdr;
159
160 __libc_lock_lock (lock);
161
162 __malloc_hook = tr_old_malloc_hook;
a2b08ee5
UD
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);
6d52618b
UD
167 __malloc_hook = tr_mallochook;
168
a2b08ee5 169 tr_where (caller);
6d52618b 170 /* We could be printing a NULL here; that's OK. */
c0fb8a56 171 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
6d52618b 172
92e4472f
UD
173 __libc_lock_unlock (lock);
174
6d52618b
UD
175 if (hdr == mallwatch)
176 tr_break ();
177
178 return hdr;
179}
180
a2b08ee5 181static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
6d52618b 182static __ptr_t
a2b08ee5 183tr_reallochook (ptr, size, caller)
6d52618b
UD
184 __ptr_t ptr;
185 __malloc_size_t size;
a2b08ee5 186 const __ptr_t caller;
6d52618b
UD
187{
188 __ptr_t hdr;
189
190 if (ptr == mallwatch)
191 tr_break ();
192
193 __libc_lock_lock (lock);
194
195 __free_hook = tr_old_free_hook;
196 __malloc_hook = tr_old_malloc_hook;
197 __realloc_hook = tr_old_realloc_hook;
a2b08ee5
UD
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);
6d52618b
UD
202 __free_hook = tr_freehook;
203 __malloc_hook = tr_mallochook;
204 __realloc_hook = tr_reallochook;
205
a2b08ee5 206 tr_where (caller);
6d52618b
UD
207 if (hdr == NULL)
208 /* Failed realloc. */
c0fb8a56 209 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
6d52618b 210 else if (ptr == NULL)
c0fb8a56 211 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
6d52618b 212 else
8261bc4b
UD
213 {
214 fprintf (mallstream, "< %p\n", ptr);
215 tr_where (caller);
216 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
217 }
6d52618b 218
92e4472f
UD
219 __libc_lock_unlock (lock);
220
6d52618b
UD
221 if (hdr == mallwatch)
222 tr_break ();
223
224 return hdr;
225}
226
a5a0310d
UD
227
228#ifdef _LIBC
a5a0310d
UD
229
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. */
233static void
234release_libc_mem (void)
235{
236 /* Only call the free function if we still are running in mtrace mode. */
237 if (mallstream != NULL)
238 __libc_freeres ();
239}
240#endif
241
242
6d52618b
UD
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! */
247
248void
249mtrace ()
250{
a5a0310d 251#ifdef _LIBC
c4563d2d 252 static int added_atexit_handler;
a5a0310d 253#endif
6d52618b
UD
254 char *mallfile;
255
256 /* Don't panic if we're called more than once. */
257 if (mallstream != NULL)
258 return;
259
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)
269 {
4c48dc93 270 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
6d52618b
UD
271 if (mallstream != NULL)
272 {
755104ed
UD
273 /* Make sure we close the file descriptor on exec. */
274 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
275 if (flags >= 0)
276 {
277 flags |= FD_CLOEXEC;
278 __fcntl (fileno (mallstream), F_SETFD, flags);
279 }
6d52618b 280 /* Be sure it doesn't malloc its buffer! */
479e9b3f 281 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
6d52618b
UD
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;
a5a0310d
UD
289#ifdef _LIBC
290 if (!added_atexit_handler)
291 {
c08bc50a 292 extern void *__dso_handle __attribute__ ((__weak__));
a5a0310d 293 added_atexit_handler = 1;
c08bc50a
UD
294 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
295 &__dso_handle ? __dso_handle : NULL);
a5a0310d
UD
296 }
297#endif
6d52618b
UD
298 }
299 }
300}
301
302void
303muntrace ()
304{
305 if (mallstream == NULL)
306 return;
307
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;
314}