Begin porting string performance tests to benchtests
[glibc.git] / malloc / mtrace.c
blobee941333a8799a202a9f126911519f6f00c58904
1 /* More debugging hooks for `malloc'.
2 Copyright (C) 1991-2013 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 #ifndef attribute_hidden
45 # define attribute_hidden
46 #endif
48 #define TRACE_BUFFER_SIZE 512
50 static FILE *mallstream;
51 static const char mallenv[]= "MALLOC_TRACE";
52 static char *malloc_trace_buffer;
54 __libc_lock_define_initialized (static, lock);
56 /* Address to breakpoint on accesses to... */
57 __ptr_t mallwatch;
59 /* Old hook values. */
60 static void (*tr_old_free_hook) (__ptr_t ptr, const __ptr_t);
61 static __ptr_t (*tr_old_malloc_hook) (size_t size, const __ptr_t);
62 static __ptr_t (*tr_old_realloc_hook) (__ptr_t ptr, size_t size,
63 const __ptr_t);
64 static __ptr_t (*tr_old_memalign_hook) (size_t __alignment, size_t __size,
65 const __ptr_t);
67 /* This function is called when the block being alloc'd, realloc'd, or
68 freed has an address matching the variable "mallwatch". In a debugger,
69 set "mallwatch" to the address of interest, then put a breakpoint on
70 tr_break. */
72 extern void tr_break (void) __THROW;
73 libc_hidden_proto (tr_break)
74 void
75 tr_break (void)
78 libc_hidden_def (tr_break)
80 static void tr_where (const __ptr_t, Dl_info *) __THROW internal_function;
81 static void
82 internal_function
83 tr_where (caller, info)
84 const __ptr_t caller;
85 Dl_info *info;
87 if (caller != NULL)
89 if (info != NULL)
91 char *buf = (char *) "";
92 if (info->dli_sname != NULL)
94 size_t len = strlen (info->dli_sname);
95 buf = alloca (len + 6 + 2 * sizeof (void *));
97 buf[0] = '(';
98 __stpcpy (_fitoa (caller >= (const __ptr_t) info->dli_saddr
99 ? caller - (const __ptr_t) info->dli_saddr
100 : (const __ptr_t) info->dli_saddr - caller,
101 __stpcpy (__mempcpy (buf + 1, info->dli_sname,
102 len),
103 caller >= (__ptr_t) info->dli_saddr
104 ? "+0x" : "-0x"),
105 16, 0),
106 ")");
109 fprintf (mallstream, "@ %s%s%s[%p] ",
110 info->dli_fname ?: "", info->dli_fname ? ":" : "",
111 buf, caller);
113 else
114 fprintf (mallstream, "@ [%p] ", caller);
119 static Dl_info *
120 lock_and_info (const __ptr_t caller, Dl_info *mem)
122 if (caller == NULL)
123 return NULL;
125 Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
127 __libc_lock_lock (lock);
129 return res;
133 static void tr_freehook (__ptr_t, const __ptr_t) __THROW;
134 static void
135 tr_freehook (ptr, caller)
136 __ptr_t ptr;
137 const __ptr_t caller;
139 if (ptr == NULL)
140 return;
142 Dl_info mem;
143 Dl_info *info = lock_and_info (caller, &mem);
144 tr_where (caller, info);
145 /* Be sure to print it first. */
146 fprintf (mallstream, "- %p\n", ptr);
147 if (ptr == mallwatch)
149 __libc_lock_unlock (lock);
150 tr_break ();
151 __libc_lock_lock (lock);
153 __free_hook = tr_old_free_hook;
154 if (tr_old_free_hook != NULL)
155 (*tr_old_free_hook) (ptr, caller);
156 else
157 free (ptr);
158 __free_hook = tr_freehook;
159 __libc_lock_unlock (lock);
162 static __ptr_t tr_mallochook (size_t, const __ptr_t) __THROW;
163 static __ptr_t
164 tr_mallochook (size, caller)
165 size_t size;
166 const __ptr_t caller;
168 __ptr_t hdr;
170 Dl_info mem;
171 Dl_info *info = lock_and_info (caller, &mem);
173 __malloc_hook = tr_old_malloc_hook;
174 if (tr_old_malloc_hook != NULL)
175 hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
176 else
177 hdr = (__ptr_t) malloc (size);
178 __malloc_hook = tr_mallochook;
180 tr_where (caller, info);
181 /* We could be printing a NULL here; that's OK. */
182 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
184 __libc_lock_unlock (lock);
186 if (hdr == mallwatch)
187 tr_break ();
189 return hdr;
192 static __ptr_t tr_reallochook (__ptr_t, size_t, const __ptr_t)
193 __THROW;
194 static __ptr_t
195 tr_reallochook (ptr, size, caller)
196 __ptr_t ptr;
197 size_t size;
198 const __ptr_t caller;
200 __ptr_t hdr;
202 if (ptr == mallwatch)
203 tr_break ();
205 Dl_info mem;
206 Dl_info *info = lock_and_info (caller, &mem);
208 __free_hook = tr_old_free_hook;
209 __malloc_hook = tr_old_malloc_hook;
210 __realloc_hook = tr_old_realloc_hook;
211 if (tr_old_realloc_hook != NULL)
212 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
213 else
214 hdr = (__ptr_t) realloc (ptr, size);
215 __free_hook = tr_freehook;
216 __malloc_hook = tr_mallochook;
217 __realloc_hook = tr_reallochook;
219 tr_where (caller, info);
220 if (hdr == NULL)
222 if (size != 0)
223 /* Failed realloc. */
224 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
225 else
226 fprintf (mallstream, "- %p\n", ptr);
228 else if (ptr == NULL)
229 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
230 else
232 fprintf (mallstream, "< %p\n", ptr);
233 tr_where (caller, info);
234 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
237 __libc_lock_unlock (lock);
239 if (hdr == mallwatch)
240 tr_break ();
242 return hdr;
245 static __ptr_t tr_memalignhook (size_t, size_t,
246 const __ptr_t) __THROW;
247 static __ptr_t
248 tr_memalignhook (alignment, size, caller)
249 size_t alignment, size;
250 const __ptr_t caller;
252 __ptr_t hdr;
254 Dl_info mem;
255 Dl_info *info = lock_and_info (caller, &mem);
257 __memalign_hook = tr_old_memalign_hook;
258 __malloc_hook = tr_old_malloc_hook;
259 if (tr_old_memalign_hook != NULL)
260 hdr = (__ptr_t) (*tr_old_memalign_hook) (alignment, size, caller);
261 else
262 hdr = (__ptr_t) memalign (alignment, size);
263 __memalign_hook = tr_memalignhook;
264 __malloc_hook = tr_mallochook;
266 tr_where (caller, info);
267 /* We could be printing a NULL here; that's OK. */
268 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
270 __libc_lock_unlock (lock);
272 if (hdr == mallwatch)
273 tr_break ();
275 return hdr;
280 #ifdef _LIBC
282 /* This function gets called to make sure all memory the library
283 allocates get freed and so does not irritate the user when studying
284 the mtrace output. */
285 static void __libc_freeres_fn_section
286 release_libc_mem (void)
288 /* Only call the free function if we still are running in mtrace mode. */
289 if (mallstream != NULL)
290 __libc_freeres ();
292 #endif
295 /* We enable tracing if either the environment variable MALLOC_TRACE
296 is set, or if the variable mallwatch has been patched to an address
297 that the debugging user wants us to stop on. When patching mallwatch,
298 don't forget to set a breakpoint on tr_break! */
300 void
301 mtrace (void)
303 #ifdef _LIBC
304 static int added_atexit_handler;
305 #endif
306 char *mallfile;
308 /* Don't panic if we're called more than once. */
309 if (mallstream != NULL)
310 return;
312 #ifdef _LIBC
313 /* When compiling the GNU libc we use the secure getenv function
314 which prevents the misuse in case of SUID or SGID enabled
315 programs. */
316 mallfile = __libc_secure_getenv (mallenv);
317 #else
318 mallfile = getenv (mallenv);
319 #endif
320 if (mallfile != NULL || mallwatch != NULL)
322 char *mtb = malloc (TRACE_BUFFER_SIZE);
323 if (mtb == NULL)
324 return;
326 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
327 if (mallstream != NULL)
329 #ifndef __ASSUME_O_CLOEXEC
330 /* Make sure we close the file descriptor on exec. */
331 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
332 if (flags >= 0)
334 flags |= FD_CLOEXEC;
335 __fcntl (fileno (mallstream), F_SETFD, flags);
337 #endif
338 /* Be sure it doesn't malloc its buffer! */
339 malloc_trace_buffer = mtb;
340 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
341 fprintf (mallstream, "= Start\n");
342 tr_old_free_hook = __free_hook;
343 __free_hook = tr_freehook;
344 tr_old_malloc_hook = __malloc_hook;
345 __malloc_hook = tr_mallochook;
346 tr_old_realloc_hook = __realloc_hook;
347 __realloc_hook = tr_reallochook;
348 tr_old_memalign_hook = __memalign_hook;
349 __memalign_hook = tr_memalignhook;
350 #ifdef _LIBC
351 if (!added_atexit_handler)
353 extern void *__dso_handle __attribute__ ((__weak__));
354 added_atexit_handler = 1;
355 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
356 &__dso_handle ? __dso_handle : NULL);
358 #endif
360 else
361 free (mtb);
365 void
366 muntrace (void)
368 if (mallstream == NULL)
369 return;
371 /* Do the reverse of what done in mtrace: first reset the hooks and
372 MALLSTREAM, and only after that write the trailer and close the
373 file. */
374 FILE *f = mallstream;
375 mallstream = NULL;
376 __free_hook = tr_old_free_hook;
377 __malloc_hook = tr_old_malloc_hook;
378 __realloc_hook = tr_old_realloc_hook;
379 __memalign_hook = tr_old_memalign_hook;
381 fprintf (f, "= End\n");
382 fclose (f);