PowerPC: logb/logbf/logbl multilib for PowerPC32
[glibc.git] / malloc / mtrace.c
blobe9ccfa299d414dc0d3d91f1db77e0286bd86c6e8
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) (__malloc_size_t size, const __ptr_t);
62 static __ptr_t (*tr_old_realloc_hook) (__ptr_t ptr, __malloc_size_t size,
63 const __ptr_t);
64 static __ptr_t (*tr_old_memalign_hook) (__malloc_size_t __alignment,
65 __malloc_size_t __size,
66 const __ptr_t);
68 /* This function is called when the block being alloc'd, realloc'd, or
69 freed has an address matching the variable "mallwatch". In a debugger,
70 set "mallwatch" to the address of interest, then put a breakpoint on
71 tr_break. */
73 extern void tr_break (void) __THROW;
74 libc_hidden_proto (tr_break)
75 void
76 tr_break ()
79 libc_hidden_def (tr_break)
81 static void tr_where (const __ptr_t, Dl_info *) __THROW internal_function;
82 static void
83 internal_function
84 tr_where (caller, info)
85 const __ptr_t caller;
86 Dl_info *info;
88 if (caller != NULL)
90 if (info != NULL)
92 char *buf = (char *) "";
93 if (info->dli_sname != NULL)
95 size_t len = strlen (info->dli_sname);
96 buf = alloca (len + 6 + 2 * sizeof (void *));
98 buf[0] = '(';
99 __stpcpy (_fitoa (caller >= (const __ptr_t) info->dli_saddr
100 ? caller - (const __ptr_t) info->dli_saddr
101 : (const __ptr_t) info->dli_saddr - caller,
102 __stpcpy (__mempcpy (buf + 1, info->dli_sname,
103 len),
104 caller >= (__ptr_t) info->dli_saddr
105 ? "+0x" : "-0x"),
106 16, 0),
107 ")");
110 fprintf (mallstream, "@ %s%s%s[%p] ",
111 info->dli_fname ?: "", info->dli_fname ? ":" : "",
112 buf, caller);
114 else
115 fprintf (mallstream, "@ [%p] ", caller);
120 static Dl_info *
121 lock_and_info (const __ptr_t caller, Dl_info *mem)
123 if (caller == NULL)
124 return NULL;
126 Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
128 __libc_lock_lock (lock);
130 return res;
134 static void tr_freehook (__ptr_t, const __ptr_t) __THROW;
135 static void
136 tr_freehook (ptr, caller)
137 __ptr_t ptr;
138 const __ptr_t caller;
140 if (ptr == NULL)
141 return;
143 Dl_info mem;
144 Dl_info *info = lock_and_info (caller, &mem);
145 tr_where (caller, info);
146 /* Be sure to print it first. */
147 fprintf (mallstream, "- %p\n", ptr);
148 if (ptr == mallwatch)
150 __libc_lock_unlock (lock);
151 tr_break ();
152 __libc_lock_lock (lock);
154 __free_hook = tr_old_free_hook;
155 if (tr_old_free_hook != NULL)
156 (*tr_old_free_hook) (ptr, caller);
157 else
158 free (ptr);
159 __free_hook = tr_freehook;
160 __libc_lock_unlock (lock);
163 static __ptr_t tr_mallochook (__malloc_size_t, const __ptr_t) __THROW;
164 static __ptr_t
165 tr_mallochook (size, caller)
166 __malloc_size_t size;
167 const __ptr_t caller;
169 __ptr_t hdr;
171 Dl_info mem;
172 Dl_info *info = lock_and_info (caller, &mem);
174 __malloc_hook = tr_old_malloc_hook;
175 if (tr_old_malloc_hook != NULL)
176 hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
177 else
178 hdr = (__ptr_t) malloc (size);
179 __malloc_hook = tr_mallochook;
181 tr_where (caller, info);
182 /* We could be printing a NULL here; that's OK. */
183 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
185 __libc_lock_unlock (lock);
187 if (hdr == mallwatch)
188 tr_break ();
190 return hdr;
193 static __ptr_t tr_reallochook (__ptr_t, __malloc_size_t, const __ptr_t)
194 __THROW;
195 static __ptr_t
196 tr_reallochook (ptr, size, caller)
197 __ptr_t ptr;
198 __malloc_size_t size;
199 const __ptr_t caller;
201 __ptr_t hdr;
203 if (ptr == mallwatch)
204 tr_break ();
206 Dl_info mem;
207 Dl_info *info = lock_and_info (caller, &mem);
209 __free_hook = tr_old_free_hook;
210 __malloc_hook = tr_old_malloc_hook;
211 __realloc_hook = tr_old_realloc_hook;
212 if (tr_old_realloc_hook != NULL)
213 hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
214 else
215 hdr = (__ptr_t) realloc (ptr, size);
216 __free_hook = tr_freehook;
217 __malloc_hook = tr_mallochook;
218 __realloc_hook = tr_reallochook;
220 tr_where (caller, info);
221 if (hdr == NULL)
223 if (size != 0)
224 /* Failed realloc. */
225 fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
226 else
227 fprintf (mallstream, "- %p\n", ptr);
229 else if (ptr == NULL)
230 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
231 else
233 fprintf (mallstream, "< %p\n", ptr);
234 tr_where (caller, info);
235 fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
238 __libc_lock_unlock (lock);
240 if (hdr == mallwatch)
241 tr_break ();
243 return hdr;
246 static __ptr_t tr_memalignhook (__malloc_size_t, __malloc_size_t,
247 const __ptr_t) __THROW;
248 static __ptr_t
249 tr_memalignhook (alignment, size, caller)
250 __malloc_size_t alignment, size;
251 const __ptr_t caller;
253 __ptr_t hdr;
255 Dl_info mem;
256 Dl_info *info = lock_and_info (caller, &mem);
258 __memalign_hook = tr_old_memalign_hook;
259 __malloc_hook = tr_old_malloc_hook;
260 if (tr_old_memalign_hook != NULL)
261 hdr = (__ptr_t) (*tr_old_memalign_hook) (alignment, size, caller);
262 else
263 hdr = (__ptr_t) memalign (alignment, size);
264 __memalign_hook = tr_memalignhook;
265 __malloc_hook = tr_mallochook;
267 tr_where (caller, info);
268 /* We could be printing a NULL here; that's OK. */
269 fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
271 __libc_lock_unlock (lock);
273 if (hdr == mallwatch)
274 tr_break ();
276 return hdr;
281 #ifdef _LIBC
283 /* This function gets called to make sure all memory the library
284 allocates get freed and so does not irritate the user when studying
285 the mtrace output. */
286 static void __libc_freeres_fn_section
287 release_libc_mem (void)
289 /* Only call the free function if we still are running in mtrace mode. */
290 if (mallstream != NULL)
291 __libc_freeres ();
293 #endif
296 /* We enable tracing if either the environment variable MALLOC_TRACE
297 is set, or if the variable mallwatch has been patched to an address
298 that the debugging user wants us to stop on. When patching mallwatch,
299 don't forget to set a breakpoint on tr_break! */
301 void
302 mtrace ()
304 #ifdef _LIBC
305 static int added_atexit_handler;
306 #endif
307 char *mallfile;
309 /* Don't panic if we're called more than once. */
310 if (mallstream != NULL)
311 return;
313 #ifdef _LIBC
314 /* When compiling the GNU libc we use the secure getenv function
315 which prevents the misuse in case of SUID or SGID enabled
316 programs. */
317 mallfile = __libc_secure_getenv (mallenv);
318 #else
319 mallfile = getenv (mallenv);
320 #endif
321 if (mallfile != NULL || mallwatch != NULL)
323 char *mtb = malloc (TRACE_BUFFER_SIZE);
324 if (mtb == NULL)
325 return;
327 mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
328 if (mallstream != NULL)
330 #ifndef __ASSUME_O_CLOEXEC
331 /* Make sure we close the file descriptor on exec. */
332 int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
333 if (flags >= 0)
335 flags |= FD_CLOEXEC;
336 __fcntl (fileno (mallstream), F_SETFD, flags);
338 #endif
339 /* Be sure it doesn't malloc its buffer! */
340 malloc_trace_buffer = mtb;
341 setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
342 fprintf (mallstream, "= Start\n");
343 tr_old_free_hook = __free_hook;
344 __free_hook = tr_freehook;
345 tr_old_malloc_hook = __malloc_hook;
346 __malloc_hook = tr_mallochook;
347 tr_old_realloc_hook = __realloc_hook;
348 __realloc_hook = tr_reallochook;
349 tr_old_memalign_hook = __memalign_hook;
350 __memalign_hook = tr_memalignhook;
351 #ifdef _LIBC
352 if (!added_atexit_handler)
354 extern void *__dso_handle __attribute__ ((__weak__));
355 added_atexit_handler = 1;
356 __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
357 &__dso_handle ? __dso_handle : NULL);
359 #endif
361 else
362 free (mtb);
366 void
367 muntrace ()
369 if (mallstream == NULL)
370 return;
372 /* Do the reverse of what done in mtrace: first reset the hooks and
373 MALLSTREAM, and only after that write the trailer and close the
374 file. */
375 FILE *f = mallstream;
376 mallstream = NULL;
377 __free_hook = tr_old_free_hook;
378 __malloc_hook = tr_old_malloc_hook;
379 __realloc_hook = tr_old_realloc_hook;
380 __memalign_hook = tr_old_memalign_hook;
382 fprintf (f, "= End\n");
383 fclose (f);