Remove 17581 from NEWS
[platform/upstream/glibc.git] / malloc / mtrace.c
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.
6
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.
11
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.
16
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/>.  */
20
21 #ifndef _MALLOC_INTERNAL
22 # define _MALLOC_INTERNAL
23 # include <malloc.h>
24 # include <mcheck.h>
25 # include <bits/libc-lock.h>
26 #endif
27
28 #include <dlfcn.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33
34 #include <_itoa.h>
35
36 #include <libc-internal.h>
37
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)
41
42 #include <kernel-features.h>
43
44 #define TRACE_BUFFER_SIZE 512
45
46 static FILE *mallstream;
47 static const char mallenv[] = "MALLOC_TRACE";
48 static char *malloc_trace_buffer;
49
50 __libc_lock_define_initialized (static, lock);
51
52 /* Address to breakpoint on accesses to... */
53 __ptr_t mallwatch;
54
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);
62
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.  */
67
68 extern void tr_break (void) __THROW;
69 libc_hidden_proto (tr_break)
70 void
71 tr_break (void)
72 {
73 }
74 libc_hidden_def (tr_break)
75
76 static void internal_function
77 tr_where (const __ptr_t caller, Dl_info *info)
78 {
79   if (caller != NULL)
80     {
81       if (info != NULL)
82         {
83           char *buf = (char *) "";
84           if (info->dli_sname != NULL)
85             {
86               size_t len = strlen (info->dli_sname);
87               buf = alloca (len + 6 + 2 * sizeof (void *));
88
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                         ")");
99             }
100
101           fprintf (mallstream, "@ %s%s%s[%p] ",
102                    info->dli_fname ? : "", info->dli_fname ? ":" : "",
103                    buf, caller);
104         }
105       else
106         fprintf (mallstream, "@ [%p] ", caller);
107     }
108 }
109
110 static Dl_info *
111 lock_and_info (const __ptr_t caller, Dl_info *mem)
112 {
113   if (caller == NULL)
114     return NULL;
115
116   Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
117
118   __libc_lock_lock (lock);
119
120   return res;
121 }
122
123 static void
124 tr_freehook (__ptr_t ptr, const __ptr_t caller)
125 {
126   if (ptr == NULL)
127     return;
128
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)
135     {
136       __libc_lock_unlock (lock);
137       tr_break ();
138       __libc_lock_lock (lock);
139     }
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);
147 }
148
149 static __ptr_t
150 tr_mallochook (size_t size, const __ptr_t caller)
151 {
152   __ptr_t hdr;
153
154   Dl_info mem;
155   Dl_info *info = lock_and_info (caller, &mem);
156
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;
163
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);
167
168   __libc_lock_unlock (lock);
169
170   if (hdr == mallwatch)
171     tr_break ();
172
173   return hdr;
174 }
175
176 static __ptr_t
177 tr_reallochook (__ptr_t ptr, size_t size, const __ptr_t caller)
178 {
179   __ptr_t hdr;
180
181   if (ptr == mallwatch)
182     tr_break ();
183
184   Dl_info mem;
185   Dl_info *info = lock_and_info (caller, &mem);
186
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;
197
198   tr_where (caller, info);
199   if (hdr == NULL)
200     {
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);
206     }
207   else if (ptr == NULL)
208     fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
209   else
210     {
211       fprintf (mallstream, "< %p\n", ptr);
212       tr_where (caller, info);
213       fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
214     }
215
216   __libc_lock_unlock (lock);
217
218   if (hdr == mallwatch)
219     tr_break ();
220
221   return hdr;
222 }
223
224 static __ptr_t
225 tr_memalignhook (size_t alignment, size_t size, const __ptr_t caller)
226 {
227   __ptr_t hdr;
228
229   Dl_info mem;
230   Dl_info *info = lock_and_info (caller, &mem);
231
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;
240
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);
244
245   __libc_lock_unlock (lock);
246
247   if (hdr == mallwatch)
248     tr_break ();
249
250   return hdr;
251 }
252
253
254 #ifdef _LIBC
255
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)
261 {
262   /* Only call the free function if we still are running in mtrace mode.  */
263   if (mallstream != NULL)
264     __libc_freeres ();
265 }
266 #endif
267
268
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!  */
273
274 void
275 mtrace (void)
276 {
277 #ifdef _LIBC
278   static int added_atexit_handler;
279 #endif
280   char *mallfile;
281
282   /* Don't panic if we're called more than once.  */
283   if (mallstream != NULL)
284     return;
285
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)
295     {
296       char *mtb = malloc (TRACE_BUFFER_SIZE);
297       if (mtb == NULL)
298         return;
299
300       mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
301       if (mallstream != NULL)
302         {
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)
307             {
308               flags |= FD_CLOEXEC;
309               __fcntl (fileno (mallstream), F_SETFD, flags);
310             }
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)
326             {
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);
331             }
332 #endif
333         }
334       else
335         free (mtb);
336     }
337 }
338
339 void
340 muntrace (void)
341 {
342   if (mallstream == NULL)
343     return;
344
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;
354
355   fprintf (f, "= End\n");
356   fclose (f);
357 }