]> 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'.
a2b08ee5 2 Copyright (C) 1991, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
6d52618b
UD
3 Written April 2, 1991 by John Gilmore of Cygnus Support.
4 Based on mcheck.c by Mike Haertel.
5
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.
10
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.
15
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.
20
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. */
23
24#ifndef _MALLOC_INTERNAL
25#define _MALLOC_INTERNAL
26#include <malloc.h>
27#include <mcheck.h>
5107cf1d 28#include <bits/libc-lock.h>
6d52618b
UD
29#endif
30
a2b08ee5
UD
31#ifdef HAVE_ELF
32#include <link.h>
33#endif
34
6d52618b
UD
35#include <stdio.h>
36
37#ifndef __GNU_LIBRARY__
38extern char *getenv ();
39#else
40#include <stdlib.h>
41#endif
42
43static FILE *mallstream;
bd355af0 44static const char mallenv[]= "MALLOC_TRACE";
6d52618b
UD
45static char mallbuf[BUFSIZ]; /* Buffer for the output. */
46
47__libc_lock_define_initialized (static, lock);
48
49/* Address to breakpoint on accesses to... */
50__ptr_t mallwatch;
51
52/* File name and line number information, for callers that had
53 the foresight to call through a macro. */
54char *_mtrace_file;
55int _mtrace_line;
56
57/* Old hook values. */
a2b08ee5
UD
58static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
59static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size,
60 const __ptr_t));
61static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
62 __malloc_size_t size,
63 const __ptr_t));
6d52618b
UD
64
65/* This function is called when the block being alloc'd, realloc'd, or
66 freed has an address matching the variable "mallwatch". In a debugger,
67 set "mallwatch" to the address of interest, then put a breakpoint on
68 tr_break. */
69
70void tr_break __P ((void));
71void
72tr_break ()
73{
74}
75
dfd2257a 76static void tr_where __P ((const __ptr_t)) internal_function;
6d52618b 77static void
dfd2257a 78internal_function
a2b08ee5
UD
79tr_where (caller)
80 const __ptr_t caller;
6d52618b
UD
81{
82 if (_mtrace_file)
83 {
84 fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
85 _mtrace_file = NULL;
86 }
a2b08ee5
UD
87 else if (caller != NULL)
88 {
89#ifdef HAVE_ELF
90 Dl_info info;
91 if (_dl_addr (caller, &info))
92 {
93 fprintf (mallstream, "@ %s%s%s%s%s[%p]",
94 info.dli_fname ?: "", info.dli_fname ? ":" : "",
95 info.dli_sname ? "(" : "",
96 info.dli_sname ?: "", info.dli_sname ? ") " : " ",
97 caller);
98 }
99 else
100#endif
101 fprintf (mallstream, "@ [%p] ", caller);
102 }
6d52618b
UD
103}
104
a2b08ee5 105static void tr_freehook __P ((__ptr_t, const __ptr_t));
6d52618b 106static void
a2b08ee5 107tr_freehook (ptr, caller)
6d52618b 108 __ptr_t ptr;
a2b08ee5 109 const __ptr_t caller;
6d52618b 110{
a2b08ee5
UD
111 tr_where (caller);
112 /* Be sure to print it first. */
113 fprintf (mallstream, "- %p\n", ptr);
6d52618b
UD
114 if (ptr == mallwatch)
115 tr_break ();
116 __libc_lock_lock (lock);
117 __free_hook = tr_old_free_hook;
a2b08ee5
UD
118 if (tr_old_free_hook != NULL)
119 (*tr_old_free_hook) (ptr, caller);
120 else
121 free (ptr);
6d52618b
UD
122 __free_hook = tr_freehook;
123 __libc_lock_unlock (lock);
124}
125
a2b08ee5 126static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
6d52618b 127static __ptr_t
a2b08ee5 128tr_mallochook (size, caller)
6d52618b 129 __malloc_size_t size;
a2b08ee5 130 const __ptr_t caller;
6d52618b
UD
131{
132 __ptr_t hdr;
133
134 __libc_lock_lock (lock);
135
136 __malloc_hook = tr_old_malloc_hook;
a2b08ee5
UD
137 if (tr_old_malloc_hook != NULL)
138 hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
139 else
140 hdr = (__ptr_t) malloc (size);
6d52618b
UD
141 __malloc_hook = tr_mallochook;
142
143 __libc_lock_unlock (lock);
144
a2b08ee5 145 tr_where (caller);
6d52618b 146 /* We could be printing a NULL here; that's OK. */
a2b08ee5 147 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long)size);
6d52618b
UD
148
149 if (hdr == mallwatch)
150 tr_break ();
151
152 return hdr;
153}
154
a2b08ee5 155static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
6d52618b 156static __ptr_t
a2b08ee5 157tr_reallochook (ptr, size, caller)
6d52618b
UD
158 __ptr_t ptr;
159 __malloc_size_t size;
a2b08ee5 160 const __ptr_t caller;
6d52618b
UD
161{
162 __ptr_t hdr;
163
164 if (ptr == mallwatch)
165 tr_break ();
166
167 __libc_lock_lock (lock);
168
169 __free_hook = tr_old_free_hook;
170 __malloc_hook = tr_old_malloc_hook;
171 __realloc_hook = tr_old_realloc_hook;
a2b08ee5
UD
172 if (tr_old_realloc_hook != NULL)
173 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
174 else
175 hdr = (__ptr_t) realloc (ptr, size);
6d52618b
UD
176 __free_hook = tr_freehook;
177 __malloc_hook = tr_mallochook;
178 __realloc_hook = tr_reallochook;
179
180 __libc_lock_unlock (lock);
181
a2b08ee5 182 tr_where (caller);
6d52618b
UD
183 if (hdr == NULL)
184 /* Failed realloc. */
a2b08ee5 185 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long)size);
6d52618b 186 else if (ptr == NULL)
a2b08ee5 187 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long)size);
6d52618b 188 else
a2b08ee5 189 fprintf (mallstream, "< %p\n> %p %#lx\n", ptr, hdr, (unsigned long)size);
6d52618b
UD
190
191 if (hdr == mallwatch)
192 tr_break ();
193
194 return hdr;
195}
196
a5a0310d
UD
197
198#ifdef _LIBC
199extern void __libc_freeres (void);
200
201/* This function gets called to make sure all memory the library
202 allocates get freed and so does not irritate the user when studying
203 the mtrace output. */
204static void
205release_libc_mem (void)
206{
207 /* Only call the free function if we still are running in mtrace mode. */
208 if (mallstream != NULL)
209 __libc_freeres ();
210}
211#endif
212
213
6d52618b
UD
214/* We enable tracing if either the environment variable MALLOC_TRACE
215 is set, or if the variable mallwatch has been patched to an address
216 that the debugging user wants us to stop on. When patching mallwatch,
217 don't forget to set a breakpoint on tr_break! */
218
219void
220mtrace ()
221{
a5a0310d
UD
222#ifdef _LIBC
223 static int added_atexit_handler = 0;
224#endif
6d52618b
UD
225 char *mallfile;
226
227 /* Don't panic if we're called more than once. */
228 if (mallstream != NULL)
229 return;
230
231#ifdef _LIBC
232 /* When compiling the GNU libc we use the secure getenv function
233 which prevents the misuse in case of SUID or SGID enabled
234 programs. */
235 mallfile = __secure_getenv (mallenv);
236#else
237 mallfile = getenv (mallenv);
238#endif
239 if (mallfile != NULL || mallwatch != NULL)
240 {
241 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
242 if (mallstream != NULL)
243 {
244 /* Be sure it doesn't malloc its buffer! */
245 setbuf (mallstream, mallbuf);
246 fprintf (mallstream, "= Start\n");
247 tr_old_free_hook = __free_hook;
248 __free_hook = tr_freehook;
249 tr_old_malloc_hook = __malloc_hook;
250 __malloc_hook = tr_mallochook;
251 tr_old_realloc_hook = __realloc_hook;
252 __realloc_hook = tr_reallochook;
a5a0310d
UD
253#ifdef _LIBC
254 if (!added_atexit_handler)
255 {
256 added_atexit_handler = 1;
257 atexit (release_libc_mem);
258 }
259#endif
6d52618b
UD
260 }
261 }
262}
263
264void
265muntrace ()
266{
267 if (mallstream == NULL)
268 return;
269
270 fprintf (mallstream, "= End\n");
271 fclose (mallstream);
272 mallstream = NULL;
273 __free_hook = tr_old_free_hook;
274 __malloc_hook = tr_old_malloc_hook;
275 __realloc_hook = tr_old_realloc_hook;
276}