S390: Optimize wmemset.
[glibc.git] / malloc / mtrace.c
blobdf10128b872b4adc4086cf74e5d965c1c11d35d2
1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-2015 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Written April 2, 1991 by John Gilmore of Cygnus Support.
5 Based on mcheck.c by Mike Haertel.
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.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library; if not, see
19 <http://www.gnu.org/licenses/>. */
21 #ifndef _MALLOC_INTERNAL
22 # define _MALLOC_INTERNAL
23 # include <malloc.h>
24 # include <mcheck.h>
25 # include <bits/libc-lock.h>
26 #endif
28 #include <dlfcn.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
34 #include <_itoa.h>
36 #include <libc-internal.h>
38 #include <libio/iolibio.h>
39 #define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
40 #define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
42 #include <kernel-features.h>
44 #define TRACE_BUFFER_SIZE 512
46 static FILE *mallstream;
47 static const char mallenv[] = "MALLOC_TRACE";
48 static char *malloc_trace_buffer;
50 __libc_lock_define_initialized (static, lock);
52 /* Address to breakpoint on accesses to... */
53 __ptr_t mallwatch;
55 /* Old hook values. */
56 static void (*tr_old_free_hook) (__ptr_t ptr, const __ptr_t);
57 static __ptr_t (*tr_old_malloc_hook) (size_t size, const __ptr_t);
58 static __ptr_t (*tr_old_realloc_hook) (__ptr_t ptr, size_t size,
59 const __ptr_t);
60 static __ptr_t (*tr_old_memalign_hook) (size_t __alignment, size_t __size,
61 const __ptr_t);
63 /* This function is called when the block being alloc'd, realloc'd, or
64 freed has an address matching the variable "mallwatch". In a debugger,
65 set "mallwatch" to the address of interest, then put a breakpoint on
66 tr_break. */
68 extern void tr_break (void) __THROW;
69 libc_hidden_proto (tr_break)
70 void
71 tr_break (void)
74 libc_hidden_def (tr_break)
76 static void internal_function
77 tr_where (const __ptr_t caller, Dl_info *info)
79 if (caller != NULL)
81 if (info != NULL)
83 char *buf = (char *) "";
84 if (info->dli_sname != NULL)
86 size_t len = strlen (info->dli_sname);
87 buf = alloca (len + 6 + 2 * sizeof (void *));
89 buf[0] = '(';
90 __stpcpy (_fitoa (caller >= (const __ptr_t) info->dli_saddr
91 ? caller - (const __ptr_t) info->dli_saddr
92 : (const __ptr_t) info->dli_saddr - caller,
93 __stpcpy (__mempcpy (buf + 1, info->dli_sname,
94 len),
95 caller >= (__ptr_t) info->dli_saddr
96 ? "+0x" : "-0x"),
97 16, 0),
98 ")");
101 fprintf (mallstream, "@ %s%s%s[%p] ",
102 info->dli_fname ? : "", info->dli_fname ? ":" : "",
103 buf, caller);
105 else
106 fprintf (mallstream, "@ [%p] ", caller);
110 static Dl_info *
111 lock_and_info (const __ptr_t caller, Dl_info *mem)
113 if (caller == NULL)
114 return NULL;
116 Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
118 __libc_lock_lock (lock);
120 return res;
123 static void
124 tr_freehook (__ptr_t ptr, const __ptr_t caller)
126 if (ptr == NULL)
127 return;
129 Dl_info mem;
130 Dl_info *info = lock_and_info (caller, &mem);
131 tr_where (caller, info);
132 /* Be sure to print it first. */
133 fprintf (mallstream, "- %p\n", ptr);
134 if (ptr == mallwatch)
136 __libc_lock_unlock (lock);
137 tr_break ();
138 __libc_lock_lock (lock);
140 __free_hook = tr_old_free_hook;
141 if (tr_old_free_hook != NULL)
142 (*tr_old_free_hook)(ptr, caller);
143 else
144 free (ptr);
145 __free_hook = tr_freehook;
146 __libc_lock_unlock (lock);
149 static __ptr_t
150 tr_mallochook (size_t size, const __ptr_t caller)
152 __ptr_t hdr;
154 Dl_info mem;
155 Dl_info *info = lock_and_info (caller, &mem);
157 __malloc_hook = tr_old_malloc_hook;
158 if (tr_old_malloc_hook != NULL)
159 hdr = (__ptr_t) (*tr_old_malloc_hook)(size, caller);
160 else
161 hdr = (__ptr_t) malloc (size);
162 __malloc_hook = tr_mallochook;
164 tr_where (caller, info);
165 /* We could be printing a NULL here; that's OK. */
166 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
168 __libc_lock_unlock (lock);
170 if (hdr == mallwatch)
171 tr_break ();
173 return hdr;
176 static __ptr_t
177 tr_reallochook (__ptr_t ptr, size_t size, const __ptr_t caller)
179 __ptr_t hdr;
181 if (ptr == mallwatch)
182 tr_break ();
184 Dl_info mem;
185 Dl_info *info = lock_and_info (caller, &mem);
187 __free_hook = tr_old_free_hook;
188 __malloc_hook = tr_old_malloc_hook;
189 __realloc_hook = tr_old_realloc_hook;
190 if (tr_old_realloc_hook != NULL)
191 hdr = (__ptr_t) (*tr_old_realloc_hook)(ptr, size, caller);
192 else
193 hdr = (__ptr_t) realloc (ptr, size);
194 __free_hook = tr_freehook;
195 __malloc_hook = tr_mallochook;
196 __realloc_hook = tr_reallochook;
198 tr_where (caller, info);
199 if (hdr == NULL)
201 if (size != 0)
202 /* Failed realloc. */
203 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
204 else
205 fprintf (mallstream, "- %p\n", ptr);
207 else if (ptr == NULL)
208 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
209 else
211 fprintf (mallstream, "< %p\n", ptr);
212 tr_where (caller, info);
213 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
216 __libc_lock_unlock (lock);
218 if (hdr == mallwatch)
219 tr_break ();
221 return hdr;
224 static __ptr_t
225 tr_memalignhook (size_t alignment, size_t size, const __ptr_t caller)
227 __ptr_t hdr;
229 Dl_info mem;
230 Dl_info *info = lock_and_info (caller, &mem);
232 __memalign_hook = tr_old_memalign_hook;
233 __malloc_hook = tr_old_malloc_hook;
234 if (tr_old_memalign_hook != NULL)
235 hdr = (__ptr_t) (*tr_old_memalign_hook)(alignment, size, caller);
236 else
237 hdr = (__ptr_t) memalign (alignment, size);
238 __memalign_hook = tr_memalignhook;
239 __malloc_hook = tr_mallochook;
241 tr_where (caller, info);
242 /* We could be printing a NULL here; that's OK. */
243 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
245 __libc_lock_unlock (lock);
247 if (hdr == mallwatch)
248 tr_break ();
250 return hdr;
254 #ifdef _LIBC
256 /* This function gets called to make sure all memory the library
257 allocates get freed and so does not irritate the user when studying
258 the mtrace output. */
259 static void __libc_freeres_fn_section
260 release_libc_mem (void)
262 /* Only call the free function if we still are running in mtrace mode. */
263 if (mallstream != NULL)
264 __libc_freeres ();
266 #endif
269 /* We enable tracing if either the environment variable MALLOC_TRACE
270 is set, or if the variable mallwatch has been patched to an address
271 that the debugging user wants us to stop on. When patching mallwatch,
272 don't forget to set a breakpoint on tr_break! */
274 void
275 mtrace (void)
277 #ifdef _LIBC
278 static int added_atexit_handler;
279 #endif
280 char *mallfile;
282 /* Don't panic if we're called more than once. */
283 if (mallstream != NULL)
284 return;
286 #ifdef _LIBC
287 /* When compiling the GNU libc we use the secure getenv function
288 which prevents the misuse in case of SUID or SGID enabled
289 programs. */
290 mallfile = __libc_secure_getenv (mallenv);
291 #else
292 mallfile = getenv (mallenv);
293 #endif
294 if (mallfile != NULL || mallwatch != NULL)
296 char *mtb = malloc (TRACE_BUFFER_SIZE);
297 if (mtb == NULL)
298 return;
300 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
301 if (mallstream != NULL)
303 #ifndef __ASSUME_O_CLOEXEC
304 /* Make sure we close the file descriptor on exec. */
305 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
306 if (flags >= 0)
308 flags |= FD_CLOEXEC;
309 __fcntl (fileno (mallstream), F_SETFD, flags);
311 #endif
312 /* Be sure it doesn't malloc its buffer! */
313 malloc_trace_buffer = mtb;
314 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
315 fprintf (mallstream, "= Start\n");
316 tr_old_free_hook = __free_hook;
317 __free_hook = tr_freehook;
318 tr_old_malloc_hook = __malloc_hook;
319 __malloc_hook = tr_mallochook;
320 tr_old_realloc_hook = __realloc_hook;
321 __realloc_hook = tr_reallochook;
322 tr_old_memalign_hook = __memalign_hook;
323 __memalign_hook = tr_memalignhook;
324 #ifdef _LIBC
325 if (!added_atexit_handler)
327 extern void *__dso_handle __attribute__ ((__weak__));
328 added_atexit_handler = 1;
329 __cxa_atexit ((void (*)(void *))release_libc_mem, NULL,
330 &__dso_handle ? __dso_handle : NULL);
332 #endif
334 else
335 free (mtb);
339 void
340 muntrace (void)
342 if (mallstream == NULL)
343 return;
345 /* Do the reverse of what done in mtrace: first reset the hooks and
346 MALLSTREAM, and only after that write the trailer and close the
347 file. */
348 FILE *f = mallstream;
349 mallstream = NULL;
350 __free_hook = tr_old_free_hook;
351 __malloc_hook = tr_old_malloc_hook;
352 __realloc_hook = tr_old_realloc_hook;
353 __memalign_hook = tr_old_memalign_hook;
355 fprintf (f, "= End\n");
356 fclose (f);