]> git.ipfire.org Git - thirdparty/glibc.git/blame - malloc/mtrace.c
Mechanically remove _IO_ name aliases for types and constants.
[thirdparty/glibc.git] / malloc / mtrace.c
CommitLineData
6d52618b 1/* More debugging hooks for `malloc'.
688903eb 2 Copyright (C) 1991-2018 Free Software Foundation, Inc.
41bdb6e2 3 This file is part of the GNU C Library.
6c8dbf00
OB
4 Written April 2, 1991 by John Gilmore of Cygnus Support.
5 Based on mcheck.c by Mike Haertel.
6d52618b 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 17 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
18 License along with the GNU C Library; if not, see
19 <http://www.gnu.org/licenses/>. */
6d52618b 20
6c8dbf00
OB
21#ifndef _MALLOC_INTERNAL
22# define _MALLOC_INTERNAL
23# include <malloc.h>
24# include <mcheck.h>
ec999b8e 25# include <libc-lock.h>
6d52618b
UD
26#endif
27
b3fc5f84 28#include <dlfcn.h>
755104ed 29#include <fcntl.h>
6d52618b 30#include <stdio.h>
e03c3361 31#include <string.h>
6d52618b 32#include <stdlib.h>
6d52618b 33
eb96ffb0 34#include <_itoa.h>
d5cabaa4 35
72112b0c 36#include <libc-internal.h>
825adeee 37#include <dso_handle.h>
66539a73 38
72112b0c 39#include <libio/iolibio.h>
d18ea0c5 40#define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
72112b0c
UD
41#define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
42
43#include <kernel-features.h>
50304ef0 44
e7993f20
UD
45#define TRACE_BUFFER_SIZE 512
46
6d52618b 47static FILE *mallstream;
6c8dbf00 48static const char mallenv[] = "MALLOC_TRACE";
c877418f 49static char *malloc_trace_buffer;
6d52618b
UD
50
51__libc_lock_define_initialized (static, lock);
52
53/* Address to breakpoint on accesses to... */
f17a4233 54void *mallwatch;
6d52618b 55
6d52618b 56/* Old hook values. */
f17a4233
JM
57static void (*tr_old_free_hook) (void *ptr, const void *);
58static void *(*tr_old_malloc_hook) (size_t size, const void *);
59static void *(*tr_old_realloc_hook) (void *ptr, size_t size,
60 const void *);
61static void *(*tr_old_memalign_hook) (size_t __alignment, size_t __size,
62 const void *);
6d52618b
UD
63
64/* This function is called when the block being alloc'd, realloc'd, or
65 freed has an address matching the variable "mallwatch". In a debugger,
66 set "mallwatch" to the address of interest, then put a breakpoint on
67 tr_break. */
68
79937577 69extern void tr_break (void) __THROW;
ee2a5ae8 70libc_hidden_proto (tr_break)
6d52618b 71void
60d2f8f3 72tr_break (void)
6d52618b
UD
73{
74}
ee2a5ae8 75libc_hidden_def (tr_break)
6d52618b 76
0c71122c 77static void
f17a4233 78tr_where (const void *caller, Dl_info *info)
6d52618b 79{
6ce75379 80 if (caller != NULL)
a2b08ee5 81 {
56e5eb46 82 if (info != NULL)
6c8dbf00
OB
83 {
84 char *buf = (char *) "";
85 if (info->dli_sname != NULL)
86 {
87 size_t len = strlen (info->dli_sname);
88 buf = alloca (len + 6 + 2 * sizeof (void *));
89
90 buf[0] = '(';
f17a4233
JM
91 __stpcpy (_fitoa (caller >= (const void *) info->dli_saddr
92 ? caller - (const void *) info->dli_saddr
93 : (const void *) info->dli_saddr - caller,
6c8dbf00
OB
94 __stpcpy (__mempcpy (buf + 1, info->dli_sname,
95 len),
f17a4233 96 caller >= (void *) info->dli_saddr
6c8dbf00
OB
97 ? "+0x" : "-0x"),
98 16, 0),
99 ")");
100 }
101
102 fprintf (mallstream, "@ %s%s%s[%p] ",
103 info->dli_fname ? : "", info->dli_fname ? ":" : "",
104 buf, caller);
105 }
a2b08ee5 106 else
6c8dbf00 107 fprintf (mallstream, "@ [%p] ", caller);
a2b08ee5 108 }
6d52618b
UD
109}
110
56e5eb46 111static Dl_info *
f17a4233 112lock_and_info (const void *caller, Dl_info *mem)
56e5eb46
UD
113{
114 if (caller == NULL)
115 return NULL;
116
117 Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
118
119 __libc_lock_lock (lock);
120
121 return res;
122}
123
c13a72b7 124static void
f17a4233 125tr_freehook (void *ptr, const void *caller)
6d52618b 126{
55465bd9
UD
127 if (ptr == NULL)
128 return;
56e5eb46
UD
129
130 Dl_info mem;
131 Dl_info *info = lock_and_info (caller, &mem);
132 tr_where (caller, info);
a2b08ee5
UD
133 /* Be sure to print it first. */
134 fprintf (mallstream, "- %p\n", ptr);
6d52618b 135 if (ptr == mallwatch)
41043168
UD
136 {
137 __libc_lock_unlock (lock);
138 tr_break ();
139 __libc_lock_lock (lock);
140 }
6d52618b 141 __free_hook = tr_old_free_hook;
a2b08ee5 142 if (tr_old_free_hook != NULL)
6c8dbf00 143 (*tr_old_free_hook)(ptr, caller);
a2b08ee5 144 else
a334319f 145 free (ptr);
6d52618b
UD
146 __free_hook = tr_freehook;
147 __libc_lock_unlock (lock);
148}
149
f17a4233
JM
150static void *
151tr_mallochook (size_t size, const void *caller)
6d52618b 152{
f17a4233 153 void *hdr;
6d52618b 154
56e5eb46
UD
155 Dl_info mem;
156 Dl_info *info = lock_and_info (caller, &mem);
6d52618b
UD
157
158 __malloc_hook = tr_old_malloc_hook;
a2b08ee5 159 if (tr_old_malloc_hook != NULL)
f17a4233 160 hdr = (void *) (*tr_old_malloc_hook)(size, caller);
a2b08ee5 161 else
f17a4233 162 hdr = (void *) malloc (size);
6d52618b
UD
163 __malloc_hook = tr_mallochook;
164
56e5eb46 165 tr_where (caller, info);
6d52618b 166 /* We could be printing a NULL here; that's OK. */
c0fb8a56 167 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
6d52618b 168
92e4472f
UD
169 __libc_lock_unlock (lock);
170
6d52618b
UD
171 if (hdr == mallwatch)
172 tr_break ();
173
174 return hdr;
175}
176
f17a4233
JM
177static void *
178tr_reallochook (void *ptr, size_t size, const void *caller)
6d52618b 179{
f17a4233 180 void *hdr;
6d52618b
UD
181
182 if (ptr == mallwatch)
183 tr_break ();
184
56e5eb46
UD
185 Dl_info mem;
186 Dl_info *info = lock_and_info (caller, &mem);
6d52618b
UD
187
188 __free_hook = tr_old_free_hook;
189 __malloc_hook = tr_old_malloc_hook;
190 __realloc_hook = tr_old_realloc_hook;
a2b08ee5 191 if (tr_old_realloc_hook != NULL)
f17a4233 192 hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
a2b08ee5 193 else
f17a4233 194 hdr = (void *) realloc (ptr, size);
6d52618b
UD
195 __free_hook = tr_freehook;
196 __malloc_hook = tr_mallochook;
197 __realloc_hook = tr_reallochook;
198
56e5eb46 199 tr_where (caller, info);
6d52618b 200 if (hdr == NULL)
2f5f40f4
AS
201 {
202 if (size != 0)
6c8dbf00
OB
203 /* Failed realloc. */
204 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
2f5f40f4 205 else
6c8dbf00 206 fprintf (mallstream, "- %p\n", ptr);
2f5f40f4 207 }
6d52618b 208 else if (ptr == NULL)
c0fb8a56 209 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
6d52618b 210 else
8261bc4b
UD
211 {
212 fprintf (mallstream, "< %p\n", ptr);
56e5eb46 213 tr_where (caller, info);
8261bc4b
UD
214 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
215 }
6d52618b 216
92e4472f
UD
217 __libc_lock_unlock (lock);
218
6d52618b
UD
219 if (hdr == mallwatch)
220 tr_break ();
221
222 return hdr;
223}
224
f17a4233
JM
225static void *
226tr_memalignhook (size_t alignment, size_t size, const void *caller)
e796f92f 227{
f17a4233 228 void *hdr;
e796f92f 229
56e5eb46
UD
230 Dl_info mem;
231 Dl_info *info = lock_and_info (caller, &mem);
e796f92f
UD
232
233 __memalign_hook = tr_old_memalign_hook;
234 __malloc_hook = tr_old_malloc_hook;
235 if (tr_old_memalign_hook != NULL)
f17a4233 236 hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
e796f92f 237 else
f17a4233 238 hdr = (void *) memalign (alignment, size);
e796f92f
UD
239 __memalign_hook = tr_memalignhook;
240 __malloc_hook = tr_mallochook;
241
56e5eb46 242 tr_where (caller, info);
e796f92f
UD
243 /* We could be printing a NULL here; that's OK. */
244 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
245
246 __libc_lock_unlock (lock);
247
248 if (hdr == mallwatch)
249 tr_break ();
250
251 return hdr;
252}
253
254
a5a0310d 255#ifdef _LIBC
a5a0310d
UD
256
257/* This function gets called to make sure all memory the library
258 allocates get freed and so does not irritate the user when studying
259 the mtrace output. */
c877418f 260static void __libc_freeres_fn_section
a5a0310d
UD
261release_libc_mem (void)
262{
263 /* Only call the free function if we still are running in mtrace mode. */
264 if (mallstream != NULL)
265 __libc_freeres ();
266}
267#endif
268
269
6d52618b
UD
270/* We enable tracing if either the environment variable MALLOC_TRACE
271 is set, or if the variable mallwatch has been patched to an address
272 that the debugging user wants us to stop on. When patching mallwatch,
273 don't forget to set a breakpoint on tr_break! */
274
275void
60d2f8f3 276mtrace (void)
6d52618b 277{
a5a0310d 278#ifdef _LIBC
c4563d2d 279 static int added_atexit_handler;
a5a0310d 280#endif
6d52618b
UD
281 char *mallfile;
282
283 /* Don't panic if we're called more than once. */
284 if (mallstream != NULL)
285 return;
286
287#ifdef _LIBC
288 /* When compiling the GNU libc we use the secure getenv function
289 which prevents the misuse in case of SUID or SGID enabled
290 programs. */
84b3fd84 291 mallfile = __libc_secure_getenv (mallenv);
6d52618b
UD
292#else
293 mallfile = getenv (mallenv);
294#endif
295 if (mallfile != NULL || mallwatch != NULL)
296 {
c877418f
RM
297 char *mtb = malloc (TRACE_BUFFER_SIZE);
298 if (mtb == NULL)
6c8dbf00 299 return;
c877418f 300
72112b0c 301 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
6d52618b 302 if (mallstream != NULL)
6c8dbf00 303 {
6c8dbf00
OB
304 /* Be sure it doesn't malloc its buffer! */
305 malloc_trace_buffer = mtb;
306 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
307 fprintf (mallstream, "= Start\n");
308 tr_old_free_hook = __free_hook;
309 __free_hook = tr_freehook;
310 tr_old_malloc_hook = __malloc_hook;
311 __malloc_hook = tr_mallochook;
312 tr_old_realloc_hook = __realloc_hook;
313 __realloc_hook = tr_reallochook;
314 tr_old_memalign_hook = __memalign_hook;
315 __memalign_hook = tr_memalignhook;
a5a0310d 316#ifdef _LIBC
6c8dbf00
OB
317 if (!added_atexit_handler)
318 {
6c8dbf00
OB
319 added_atexit_handler = 1;
320 __cxa_atexit ((void (*)(void *))release_libc_mem, NULL,
825adeee 321 __dso_handle);
6c8dbf00 322 }
a5a0310d 323#endif
6c8dbf00 324 }
c877418f 325 else
6c8dbf00 326 free (mtb);
6d52618b
UD
327 }
328}
329
330void
60d2f8f3 331muntrace (void)
6d52618b
UD
332{
333 if (mallstream == NULL)
334 return;
335
e19af380
PT
336 /* Do the reverse of what done in mtrace: first reset the hooks and
337 MALLSTREAM, and only after that write the trailer and close the
338 file. */
339 FILE *f = mallstream;
6d52618b
UD
340 mallstream = NULL;
341 __free_hook = tr_old_free_hook;
342 __malloc_hook = tr_old_malloc_hook;
343 __realloc_hook = tr_old_realloc_hook;
e796f92f 344 __memalign_hook = tr_old_memalign_hook;
e19af380
PT
345
346 fprintf (f, "= End\n");
347 fclose (f);
6d52618b 348}