]> sourceware.org Git - glibc.git/blame - malloc/mtrace.c
* malloc/memusage.c: Handle realloc with new size of zero and
[glibc.git] / malloc / mtrace.c
CommitLineData
6d52618b 1/* More debugging hooks for `malloc'.
06d6611a 2 Copyright (C) 1991-1994,1996-2003, 2004 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>
66539a73 39
08a0d60a 40# include <libio/iolibio.h>
77fe0b9c 41# define setvbuf(s, b, f, l) INTUSE(_IO_setvbuf) (s, b, f, l)
3ba06713 42# define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
50304ef0
UD
43#endif
44
ab26a24a
UD
45#ifndef attribute_hidden
46# define attribute_hidden
47#endif
48
e7993f20
UD
49#define TRACE_BUFFER_SIZE 512
50
6d52618b 51static FILE *mallstream;
bd355af0 52static const char mallenv[]= "MALLOC_TRACE";
c877418f 53static char *malloc_trace_buffer;
6d52618b
UD
54
55__libc_lock_define_initialized (static, lock);
56
57/* Address to breakpoint on accesses to... */
58__ptr_t mallwatch;
59
64ae9b09 60#ifdef USE_MTRACE_FILE
6d52618b
UD
61/* File name and line number information, for callers that had
62 the foresight to call through a macro. */
64ae9b09
UD
63char *_mtrace_file;
64int _mtrace_line;
65#endif
6d52618b
UD
66
67/* Old hook values. */
06d6611a
UD
68static void (*tr_old_free_hook) (__ptr_t ptr, const __ptr_t);
69static __ptr_t (*tr_old_malloc_hook) (__malloc_size_t size, const __ptr_t);
70static __ptr_t (*tr_old_realloc_hook) (__ptr_t ptr, __malloc_size_t size,
71 const __ptr_t);
72static __ptr_t (*tr_old_memalign_hook) (__malloc_size_t __alignment,
73 __malloc_size_t __size,
74 __const __ptr_t);
6d52618b
UD
75
76/* This function is called when the block being alloc'd, realloc'd, or
77 freed has an address matching the variable "mallwatch". In a debugger,
78 set "mallwatch" to the address of interest, then put a breakpoint on
79 tr_break. */
80
79937577 81extern void tr_break (void) __THROW;
ee2a5ae8 82libc_hidden_proto (tr_break)
6d52618b
UD
83void
84tr_break ()
85{
86}
ee2a5ae8 87libc_hidden_def (tr_break)
6d52618b 88
79937577 89static void tr_where (const __ptr_t) __THROW internal_function;
6d52618b 90static void
dfd2257a 91internal_function
a2b08ee5
UD
92tr_where (caller)
93 const __ptr_t caller;
6d52618b 94{
64ae9b09 95#ifdef USE_MTRACE_FILE
6d52618b
UD
96 if (_mtrace_file)
97 {
98 fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
99 _mtrace_file = NULL;
100 }
64ae9b09
UD
101 else
102#endif
103 if (caller != NULL)
a2b08ee5
UD
104 {
105#ifdef HAVE_ELF
106 Dl_info info;
8dd56993 107 if (_dl_addr (caller, &info, NULL, NULL))
a2b08ee5 108 {
604510f7 109 char *buf = (char *) "";
46b05e5d 110 if (info.dli_sname != NULL)
604510f7 111 {
d5cabaa4
UD
112 size_t len = strlen (info.dli_sname);
113 buf = alloca (len + 6 + 2 * sizeof (void *));
114
115 buf[0] = '(';
116 __stpcpy (_fitoa (caller >= (const __ptr_t) info.dli_saddr
117 ? caller - (const __ptr_t) info.dli_saddr
118 : (const __ptr_t) info.dli_saddr - caller,
119 __stpcpy (__mempcpy (buf + 1, info.dli_sname,
120 len),
121 caller >= (__ptr_t) info.dli_saddr
122 ? "+0x" : "-0x"),
123 16, 0),
124 ")");
604510f7
UD
125 }
126
127 fprintf (mallstream, "@ %s%s%s[%p] ",
a2b08ee5 128 info.dli_fname ?: "", info.dli_fname ? ":" : "",
604510f7 129 buf, caller);
a2b08ee5
UD
130 }
131 else
132#endif
133 fprintf (mallstream, "@ [%p] ", caller);
134 }
6d52618b
UD
135}
136
79937577 137static void tr_freehook (__ptr_t, const __ptr_t) __THROW;
6d52618b 138static void
a2b08ee5 139tr_freehook (ptr, caller)
6d52618b 140 __ptr_t ptr;
a2b08ee5 141 const __ptr_t caller;
6d52618b 142{
55465bd9
UD
143 if (ptr == NULL)
144 return;
92e4472f 145 __libc_lock_lock (lock);
a2b08ee5
UD
146 tr_where (caller);
147 /* Be sure to print it first. */
148 fprintf (mallstream, "- %p\n", ptr);
92e4472f 149 __libc_lock_unlock (lock);
6d52618b
UD
150 if (ptr == mallwatch)
151 tr_break ();
152 __libc_lock_lock (lock);
153 __free_hook = tr_old_free_hook;
a2b08ee5
UD
154 if (tr_old_free_hook != NULL)
155 (*tr_old_free_hook) (ptr, caller);
156 else
a334319f 157 free (ptr);
6d52618b
UD
158 __free_hook = tr_freehook;
159 __libc_lock_unlock (lock);
160}
161
79937577 162static __ptr_t tr_mallochook (__malloc_size_t, const __ptr_t) __THROW;
6d52618b 163static __ptr_t
a2b08ee5 164tr_mallochook (size, caller)
6d52618b 165 __malloc_size_t size;
a2b08ee5 166 const __ptr_t caller;
6d52618b
UD
167{
168 __ptr_t hdr;
169
170 __libc_lock_lock (lock);
171
172 __malloc_hook = tr_old_malloc_hook;
a2b08ee5
UD
173 if (tr_old_malloc_hook != NULL)
174 hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
175 else
a334319f 176 hdr = (__ptr_t) malloc (size);
6d52618b
UD
177 __malloc_hook = tr_mallochook;
178
a2b08ee5 179 tr_where (caller);
6d52618b 180 /* We could be printing a NULL here; that's OK. */
c0fb8a56 181 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
6d52618b 182
92e4472f
UD
183 __libc_lock_unlock (lock);
184
6d52618b
UD
185 if (hdr == mallwatch)
186 tr_break ();
187
188 return hdr;
189}
190
79937577
UD
191static __ptr_t tr_reallochook (__ptr_t, __malloc_size_t, const __ptr_t)
192 __THROW;
6d52618b 193static __ptr_t
a2b08ee5 194tr_reallochook (ptr, size, caller)
6d52618b
UD
195 __ptr_t ptr;
196 __malloc_size_t size;
a2b08ee5 197 const __ptr_t caller;
6d52618b
UD
198{
199 __ptr_t hdr;
200
201 if (ptr == mallwatch)
202 tr_break ();
203
204 __libc_lock_lock (lock);
205
206 __free_hook = tr_old_free_hook;
207 __malloc_hook = tr_old_malloc_hook;
208 __realloc_hook = tr_old_realloc_hook;
a2b08ee5
UD
209 if (tr_old_realloc_hook != NULL)
210 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
211 else
a334319f 212 hdr = (__ptr_t) realloc (ptr, size);
6d52618b
UD
213 __free_hook = tr_freehook;
214 __malloc_hook = tr_mallochook;
215 __realloc_hook = tr_reallochook;
216
a2b08ee5 217 tr_where (caller);
6d52618b
UD
218 if (hdr == NULL)
219 /* Failed realloc. */
c0fb8a56 220 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
6d52618b 221 else if (ptr == NULL)
c0fb8a56 222 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
6d52618b 223 else
8261bc4b
UD
224 {
225 fprintf (mallstream, "< %p\n", ptr);
226 tr_where (caller);
227 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
228 }
6d52618b 229
92e4472f
UD
230 __libc_lock_unlock (lock);
231
6d52618b
UD
232 if (hdr == mallwatch)
233 tr_break ();
234
235 return hdr;
236}
237
79937577
UD
238static __ptr_t tr_memalignhook (__malloc_size_t, __malloc_size_t,
239 const __ptr_t) __THROW;
e796f92f
UD
240static __ptr_t
241tr_memalignhook (alignment, size, caller)
242 __malloc_size_t alignment, size;
243 const __ptr_t caller;
244{
245 __ptr_t hdr;
246
247 __libc_lock_lock (lock);
248
249 __memalign_hook = tr_old_memalign_hook;
250 __malloc_hook = tr_old_malloc_hook;
251 if (tr_old_memalign_hook != NULL)
252 hdr = (__ptr_t) (*tr_old_memalign_hook) (alignment, size, caller);
253 else
a334319f 254 hdr = (__ptr_t) memalign (alignment, size);
e796f92f
UD
255 __memalign_hook = tr_memalignhook;
256 __malloc_hook = tr_mallochook;
257
258 tr_where (caller);
259 /* We could be printing a NULL here; that's OK. */
260 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
261
262 __libc_lock_unlock (lock);
263
264 if (hdr == mallwatch)
265 tr_break ();
266
267 return hdr;
268}
269
270
a5a0310d
UD
271
272#ifdef _LIBC
a5a0310d
UD
273
274/* This function gets called to make sure all memory the library
275 allocates get freed and so does not irritate the user when studying
276 the mtrace output. */
c877418f 277static void __libc_freeres_fn_section
a5a0310d
UD
278release_libc_mem (void)
279{
280 /* Only call the free function if we still are running in mtrace mode. */
281 if (mallstream != NULL)
282 __libc_freeres ();
283}
284#endif
285
286
6d52618b
UD
287/* We enable tracing if either the environment variable MALLOC_TRACE
288 is set, or if the variable mallwatch has been patched to an address
289 that the debugging user wants us to stop on. When patching mallwatch,
290 don't forget to set a breakpoint on tr_break! */
291
292void
293mtrace ()
294{
a5a0310d 295#ifdef _LIBC
c4563d2d 296 static int added_atexit_handler;
a5a0310d 297#endif
6d52618b
UD
298 char *mallfile;
299
300 /* Don't panic if we're called more than once. */
301 if (mallstream != NULL)
302 return;
303
304#ifdef _LIBC
305 /* When compiling the GNU libc we use the secure getenv function
306 which prevents the misuse in case of SUID or SGID enabled
307 programs. */
308 mallfile = __secure_getenv (mallenv);
309#else
310 mallfile = getenv (mallenv);
311#endif
312 if (mallfile != NULL || mallwatch != NULL)
313 {
c877418f
RM
314 char *mtb = malloc (TRACE_BUFFER_SIZE);
315 if (mtb == NULL)
316 return;
317
ee8449f7 318 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wc");
6d52618b
UD
319 if (mallstream != NULL)
320 {
755104ed
UD
321 /* Make sure we close the file descriptor on exec. */
322 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
323 if (flags >= 0)
324 {
325 flags |= FD_CLOEXEC;
326 __fcntl (fileno (mallstream), F_SETFD, flags);
327 }
6d52618b 328 /* Be sure it doesn't malloc its buffer! */
c877418f 329 malloc_trace_buffer = mtb;
479e9b3f 330 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
6d52618b
UD
331 fprintf (mallstream, "= Start\n");
332 tr_old_free_hook = __free_hook;
333 __free_hook = tr_freehook;
334 tr_old_malloc_hook = __malloc_hook;
335 __malloc_hook = tr_mallochook;
336 tr_old_realloc_hook = __realloc_hook;
337 __realloc_hook = tr_reallochook;
e796f92f
UD
338 tr_old_memalign_hook = __memalign_hook;
339 __memalign_hook = tr_memalignhook;
a5a0310d
UD
340#ifdef _LIBC
341 if (!added_atexit_handler)
342 {
c08bc50a 343 extern void *__dso_handle __attribute__ ((__weak__));
a5a0310d 344 added_atexit_handler = 1;
c08bc50a
UD
345 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
346 &__dso_handle ? __dso_handle : NULL);
a5a0310d
UD
347 }
348#endif
6d52618b 349 }
c877418f
RM
350 else
351 free (mtb);
6d52618b
UD
352 }
353}
354
355void
356muntrace ()
357{
358 if (mallstream == NULL)
359 return;
360
361 fprintf (mallstream, "= End\n");
362 fclose (mallstream);
363 mallstream = NULL;
364 __free_hook = tr_old_free_hook;
365 __malloc_hook = tr_old_malloc_hook;
366 __realloc_hook = tr_old_realloc_hook;
e796f92f 367 __memalign_hook = tr_old_memalign_hook;
6d52618b 368}
This page took 0.312986 seconds and 5 git commands to generate.