]> git.ipfire.org Git - thirdparty/glibc.git/blame - malloc/mtrace.c
hurd: Fix build
[thirdparty/glibc.git] / malloc / mtrace.c
CommitLineData
6d52618b 1/* More debugging hooks for `malloc'.
04277e02 2 Copyright (C) 1991-2019 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
e621246e
CD
124static void tr_freehook (void *, const void *);
125static void * tr_mallochook (size_t, const void *);
126static void * tr_reallochook (void *, size_t, const void *);
127static void * tr_memalignhook (size_t, size_t, const void *);
128
129/* Set all the default non-trace hooks. */
130static __always_inline void
131set_default_hooks (void)
132{
133 __free_hook = tr_old_free_hook;
134 __malloc_hook = tr_old_malloc_hook;
135 __realloc_hook = tr_old_realloc_hook;
136 __memalign_hook = tr_old_memalign_hook;
137}
138
139/* Set all of the tracing hooks used for mtrace. */
140static __always_inline void
141set_trace_hooks (void)
142{
143 __free_hook = tr_freehook;
144 __malloc_hook = tr_mallochook;
145 __realloc_hook = tr_reallochook;
146 __memalign_hook = tr_memalignhook;
147}
148
149/* Save the current set of hooks as the default hooks. */
150static __always_inline void
151save_default_hooks (void)
152{
153 tr_old_free_hook = __free_hook;
154 tr_old_malloc_hook = __malloc_hook;
155 tr_old_realloc_hook = __realloc_hook;
156 tr_old_memalign_hook = __memalign_hook;
157}
158
c13a72b7 159static void
f17a4233 160tr_freehook (void *ptr, const void *caller)
6d52618b 161{
55465bd9
UD
162 if (ptr == NULL)
163 return;
56e5eb46
UD
164
165 Dl_info mem;
166 Dl_info *info = lock_and_info (caller, &mem);
167 tr_where (caller, info);
a2b08ee5
UD
168 /* Be sure to print it first. */
169 fprintf (mallstream, "- %p\n", ptr);
6d52618b 170 if (ptr == mallwatch)
41043168
UD
171 {
172 __libc_lock_unlock (lock);
173 tr_break ();
174 __libc_lock_lock (lock);
175 }
e621246e 176 set_default_hooks ();
a2b08ee5 177 if (tr_old_free_hook != NULL)
6c8dbf00 178 (*tr_old_free_hook)(ptr, caller);
a2b08ee5 179 else
a334319f 180 free (ptr);
e621246e 181 set_trace_hooks ();
6d52618b
UD
182 __libc_lock_unlock (lock);
183}
184
f17a4233
JM
185static void *
186tr_mallochook (size_t size, const void *caller)
6d52618b 187{
f17a4233 188 void *hdr;
6d52618b 189
56e5eb46
UD
190 Dl_info mem;
191 Dl_info *info = lock_and_info (caller, &mem);
6d52618b 192
e621246e 193 set_default_hooks ();
a2b08ee5 194 if (tr_old_malloc_hook != NULL)
f17a4233 195 hdr = (void *) (*tr_old_malloc_hook)(size, caller);
a2b08ee5 196 else
f17a4233 197 hdr = (void *) malloc (size);
e621246e 198 set_trace_hooks ();
6d52618b 199
56e5eb46 200 tr_where (caller, info);
6d52618b 201 /* We could be printing a NULL here; that's OK. */
c0fb8a56 202 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
6d52618b 203
92e4472f
UD
204 __libc_lock_unlock (lock);
205
6d52618b
UD
206 if (hdr == mallwatch)
207 tr_break ();
208
209 return hdr;
210}
211
f17a4233
JM
212static void *
213tr_reallochook (void *ptr, size_t size, const void *caller)
6d52618b 214{
f17a4233 215 void *hdr;
6d52618b
UD
216
217 if (ptr == mallwatch)
218 tr_break ();
219
56e5eb46
UD
220 Dl_info mem;
221 Dl_info *info = lock_and_info (caller, &mem);
6d52618b 222
e621246e 223 set_default_hooks ();
a2b08ee5 224 if (tr_old_realloc_hook != NULL)
f17a4233 225 hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
a2b08ee5 226 else
f17a4233 227 hdr = (void *) realloc (ptr, size);
e621246e 228 set_trace_hooks ();
6d52618b 229
56e5eb46 230 tr_where (caller, info);
6d52618b 231 if (hdr == NULL)
2f5f40f4
AS
232 {
233 if (size != 0)
6c8dbf00
OB
234 /* Failed realloc. */
235 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
2f5f40f4 236 else
6c8dbf00 237 fprintf (mallstream, "- %p\n", ptr);
2f5f40f4 238 }
6d52618b 239 else if (ptr == NULL)
c0fb8a56 240 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
6d52618b 241 else
8261bc4b
UD
242 {
243 fprintf (mallstream, "< %p\n", ptr);
56e5eb46 244 tr_where (caller, info);
8261bc4b
UD
245 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
246 }
6d52618b 247
92e4472f
UD
248 __libc_lock_unlock (lock);
249
6d52618b
UD
250 if (hdr == mallwatch)
251 tr_break ();
252
253 return hdr;
254}
255
f17a4233
JM
256static void *
257tr_memalignhook (size_t alignment, size_t size, const void *caller)
e796f92f 258{
f17a4233 259 void *hdr;
e796f92f 260
56e5eb46
UD
261 Dl_info mem;
262 Dl_info *info = lock_and_info (caller, &mem);
e796f92f 263
e621246e 264 set_default_hooks ();
e796f92f 265 if (tr_old_memalign_hook != NULL)
f17a4233 266 hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
e796f92f 267 else
f17a4233 268 hdr = (void *) memalign (alignment, size);
e621246e 269 set_trace_hooks ();
e796f92f 270
56e5eb46 271 tr_where (caller, info);
e796f92f
UD
272 /* We could be printing a NULL here; that's OK. */
273 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
274
275 __libc_lock_unlock (lock);
276
277 if (hdr == mallwatch)
278 tr_break ();
279
280 return hdr;
281}
282
283
a5a0310d 284#ifdef _LIBC
a5a0310d
UD
285
286/* This function gets called to make sure all memory the library
287 allocates get freed and so does not irritate the user when studying
288 the mtrace output. */
c877418f 289static void __libc_freeres_fn_section
a5a0310d
UD
290release_libc_mem (void)
291{
292 /* Only call the free function if we still are running in mtrace mode. */
293 if (mallstream != NULL)
294 __libc_freeres ();
295}
296#endif
297
298
6d52618b
UD
299/* We enable tracing if either the environment variable MALLOC_TRACE
300 is set, or if the variable mallwatch has been patched to an address
301 that the debugging user wants us to stop on. When patching mallwatch,
302 don't forget to set a breakpoint on tr_break! */
303
304void
60d2f8f3 305mtrace (void)
6d52618b 306{
a5a0310d 307#ifdef _LIBC
c4563d2d 308 static int added_atexit_handler;
a5a0310d 309#endif
6d52618b
UD
310 char *mallfile;
311
312 /* Don't panic if we're called more than once. */
313 if (mallstream != NULL)
314 return;
315
316#ifdef _LIBC
317 /* When compiling the GNU libc we use the secure getenv function
318 which prevents the misuse in case of SUID or SGID enabled
319 programs. */
84b3fd84 320 mallfile = __libc_secure_getenv (mallenv);
6d52618b
UD
321#else
322 mallfile = getenv (mallenv);
323#endif
324 if (mallfile != NULL || mallwatch != NULL)
325 {
c877418f
RM
326 char *mtb = malloc (TRACE_BUFFER_SIZE);
327 if (mtb == NULL)
6c8dbf00 328 return;
c877418f 329
72112b0c 330 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
6d52618b 331 if (mallstream != NULL)
6c8dbf00 332 {
6c8dbf00
OB
333 /* Be sure it doesn't malloc its buffer! */
334 malloc_trace_buffer = mtb;
335 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
336 fprintf (mallstream, "= Start\n");
e621246e
CD
337 save_default_hooks ();
338 set_trace_hooks ();
a5a0310d 339#ifdef _LIBC
6c8dbf00
OB
340 if (!added_atexit_handler)
341 {
6c8dbf00
OB
342 added_atexit_handler = 1;
343 __cxa_atexit ((void (*)(void *))release_libc_mem, NULL,
825adeee 344 __dso_handle);
6c8dbf00 345 }
a5a0310d 346#endif
6c8dbf00 347 }
c877418f 348 else
6c8dbf00 349 free (mtb);
6d52618b
UD
350 }
351}
352
353void
60d2f8f3 354muntrace (void)
6d52618b
UD
355{
356 if (mallstream == NULL)
357 return;
358
e19af380
PT
359 /* Do the reverse of what done in mtrace: first reset the hooks and
360 MALLSTREAM, and only after that write the trailer and close the
361 file. */
362 FILE *f = mallstream;
6d52618b 363 mallstream = NULL;
e621246e 364 set_default_hooks ();
e19af380
PT
365
366 fprintf (f, "= End\n");
367 fclose (f);
6d52618b 368}