]> sourceware.org Git - glibc.git/blame - malloc/mtrace.c
* include/libc-symbols.h (__libc_freeres_fn_section, libc_freeres_fn):
[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>
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. */
a2b08ee5
UD
68static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
69static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size,
70 const __ptr_t));
71static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
72 __malloc_size_t size,
73 const __ptr_t));
6d52618b
UD
74
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. */
79
80void tr_break __P ((void));
81void
82tr_break ()
83{
84}
85
dfd2257a 86static void tr_where __P ((const __ptr_t)) internal_function;
6d52618b 87static void
dfd2257a 88internal_function
a2b08ee5
UD
89tr_where (caller)
90 const __ptr_t caller;
6d52618b 91{
64ae9b09 92#ifdef USE_MTRACE_FILE
6d52618b
UD
93 if (_mtrace_file)
94 {
95 fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
96 _mtrace_file = NULL;
97 }
64ae9b09
UD
98 else
99#endif
100 if (caller != NULL)
a2b08ee5
UD
101 {
102#ifdef HAVE_ELF
103 Dl_info info;
104 if (_dl_addr (caller, &info))
105 {
604510f7 106 char *buf = (char *) "";
46b05e5d 107 if (info.dli_sname != NULL)
604510f7 108 {
d5cabaa4
UD
109 size_t len = strlen (info.dli_sname);
110 buf = alloca (len + 6 + 2 * sizeof (void *));
111
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 ")");
604510f7
UD
122 }
123
124 fprintf (mallstream, "@ %s%s%s[%p] ",
a2b08ee5 125 info.dli_fname ?: "", info.dli_fname ? ":" : "",
604510f7 126 buf, caller);
a2b08ee5
UD
127 }
128 else
129#endif
130 fprintf (mallstream, "@ [%p] ", caller);
131 }
6d52618b
UD
132}
133
a2b08ee5 134static void tr_freehook __P ((__ptr_t, const __ptr_t));
6d52618b 135static void
a2b08ee5 136tr_freehook (ptr, caller)
6d52618b 137 __ptr_t ptr;
a2b08ee5 138 const __ptr_t caller;
6d52618b 139{
55465bd9
UD
140 if (ptr == NULL)
141 return;
92e4472f 142 __libc_lock_lock (lock);
a2b08ee5
UD
143 tr_where (caller);
144 /* Be sure to print it first. */
145 fprintf (mallstream, "- %p\n", ptr);
92e4472f 146 __libc_lock_unlock (lock);
6d52618b
UD
147 if (ptr == mallwatch)
148 tr_break ();
149 __libc_lock_lock (lock);
150 __free_hook = tr_old_free_hook;
a2b08ee5
UD
151 if (tr_old_free_hook != NULL)
152 (*tr_old_free_hook) (ptr, caller);
153 else
154 free (ptr);
6d52618b
UD
155 __free_hook = tr_freehook;
156 __libc_lock_unlock (lock);
157}
158
a2b08ee5 159static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
6d52618b 160static __ptr_t
a2b08ee5 161tr_mallochook (size, caller)
6d52618b 162 __malloc_size_t size;
a2b08ee5 163 const __ptr_t caller;
6d52618b
UD
164{
165 __ptr_t hdr;
166
167 __libc_lock_lock (lock);
168
169 __malloc_hook = tr_old_malloc_hook;
a2b08ee5
UD
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);
6d52618b
UD
174 __malloc_hook = tr_mallochook;
175
a2b08ee5 176 tr_where (caller);
6d52618b 177 /* We could be printing a NULL here; that's OK. */
c0fb8a56 178 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
6d52618b 179
92e4472f
UD
180 __libc_lock_unlock (lock);
181
6d52618b
UD
182 if (hdr == mallwatch)
183 tr_break ();
184
185 return hdr;
186}
187
a2b08ee5 188static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
6d52618b 189static __ptr_t
a2b08ee5 190tr_reallochook (ptr, size, caller)
6d52618b
UD
191 __ptr_t ptr;
192 __malloc_size_t size;
a2b08ee5 193 const __ptr_t caller;
6d52618b
UD
194{
195 __ptr_t hdr;
196
197 if (ptr == mallwatch)
198 tr_break ();
199
200 __libc_lock_lock (lock);
201
202 __free_hook = tr_old_free_hook;
203 __malloc_hook = tr_old_malloc_hook;
204 __realloc_hook = tr_old_realloc_hook;
a2b08ee5
UD
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);
6d52618b
UD
209 __free_hook = tr_freehook;
210 __malloc_hook = tr_mallochook;
211 __realloc_hook = tr_reallochook;
212
a2b08ee5 213 tr_where (caller);
6d52618b
UD
214 if (hdr == NULL)
215 /* Failed realloc. */
c0fb8a56 216 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
6d52618b 217 else if (ptr == NULL)
c0fb8a56 218 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
6d52618b 219 else
8261bc4b
UD
220 {
221 fprintf (mallstream, "< %p\n", ptr);
222 tr_where (caller);
223 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
224 }
6d52618b 225
92e4472f
UD
226 __libc_lock_unlock (lock);
227
6d52618b
UD
228 if (hdr == mallwatch)
229 tr_break ();
230
231 return hdr;
232}
233
a5a0310d
UD
234
235#ifdef _LIBC
a5a0310d
UD
236
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. */
c877418f 240static void __libc_freeres_fn_section
a5a0310d
UD
241release_libc_mem (void)
242{
243 /* Only call the free function if we still are running in mtrace mode. */
244 if (mallstream != NULL)
245 __libc_freeres ();
246}
247#endif
248
249
6d52618b
UD
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! */
254
255void
256mtrace ()
257{
a5a0310d 258#ifdef _LIBC
c4563d2d 259 static int added_atexit_handler;
a5a0310d 260#endif
6d52618b
UD
261 char *mallfile;
262
263 /* Don't panic if we're called more than once. */
264 if (mallstream != NULL)
265 return;
266
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)
276 {
c877418f
RM
277 char *mtb = malloc (TRACE_BUFFER_SIZE);
278 if (mtb == NULL)
279 return;
280
4c48dc93 281 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
6d52618b
UD
282 if (mallstream != NULL)
283 {
755104ed
UD
284 /* Make sure we close the file descriptor on exec. */
285 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
286 if (flags >= 0)
287 {
288 flags |= FD_CLOEXEC;
289 __fcntl (fileno (mallstream), F_SETFD, flags);
290 }
6d52618b 291 /* Be sure it doesn't malloc its buffer! */
c877418f 292 malloc_trace_buffer = mtb;
479e9b3f 293 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
6d52618b
UD
294 fprintf (mallstream, "= Start\n");
295 tr_old_free_hook = __free_hook;
296 __free_hook = tr_freehook;
297 tr_old_malloc_hook = __malloc_hook;
298 __malloc_hook = tr_mallochook;
299 tr_old_realloc_hook = __realloc_hook;
300 __realloc_hook = tr_reallochook;
a5a0310d
UD
301#ifdef _LIBC
302 if (!added_atexit_handler)
303 {
c08bc50a 304 extern void *__dso_handle __attribute__ ((__weak__));
a5a0310d 305 added_atexit_handler = 1;
c08bc50a
UD
306 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
307 &__dso_handle ? __dso_handle : NULL);
a5a0310d
UD
308 }
309#endif
6d52618b 310 }
c877418f
RM
311 else
312 free (mtb);
6d52618b
UD
313 }
314}
315
316void
317muntrace ()
318{
319 if (mallstream == NULL)
320 return;
321
322 fprintf (mallstream, "= End\n");
323 fclose (mallstream);
324 mallstream = NULL;
325 __free_hook = tr_old_free_hook;
326 __malloc_hook = tr_old_malloc_hook;
327 __realloc_hook = tr_old_realloc_hook;
328}
This page took 0.216151 seconds and 5 git commands to generate.