Correctly handle missing initgroups database
[platform/upstream/glibc.git] / malloc / mtrace.c
1 /* More debugging hooks for `malloc'.
2    Copyright (C) 1991-1994,1996-2004, 2008, 2011 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, write to the Free
19    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20    02111-1307 USA.  */
21
22 #ifndef _MALLOC_INTERNAL
23 #define _MALLOC_INTERNAL
24 #include <malloc.h>
25 #include <mcheck.h>
26 #include <bits/libc-lock.h>
27 #endif
28
29 #include <dlfcn.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34
35 #include <stdio-common/_itoa.h>
36
37 #include <libc-internal.h>
38
39 #include <libio/iolibio.h>
40 #define setvbuf(s, b, f, l) INTUSE(_IO_setvbuf) (s, b, f, l)
41 #define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
42
43 #include <kernel-features.h>
44
45 #ifndef attribute_hidden
46 # define attribute_hidden
47 #endif
48
49 #define TRACE_BUFFER_SIZE 512
50
51 static FILE *mallstream;
52 static const char mallenv[]= "MALLOC_TRACE";
53 static char *malloc_trace_buffer;
54
55 __libc_lock_define_initialized (static, lock);
56
57 /* Address to breakpoint on accesses to... */
58 __ptr_t mallwatch;
59
60 /* Old hook values.  */
61 static void (*tr_old_free_hook) (__ptr_t ptr, const __ptr_t);
62 static __ptr_t (*tr_old_malloc_hook) (__malloc_size_t size, const __ptr_t);
63 static __ptr_t (*tr_old_realloc_hook) (__ptr_t ptr, __malloc_size_t size,
64                                        const __ptr_t);
65 static __ptr_t (*tr_old_memalign_hook) (__malloc_size_t __alignment,
66                                         __malloc_size_t __size,
67                                         __const __ptr_t);
68
69 /* This function is called when the block being alloc'd, realloc'd, or
70    freed has an address matching the variable "mallwatch".  In a debugger,
71    set "mallwatch" to the address of interest, then put a breakpoint on
72    tr_break.  */
73
74 extern void tr_break (void) __THROW;
75 libc_hidden_proto (tr_break)
76 void
77 tr_break ()
78 {
79 }
80 libc_hidden_def (tr_break)
81
82 static void tr_where (const __ptr_t, Dl_info *) __THROW internal_function;
83 static void
84 internal_function
85 tr_where (caller, info)
86      const __ptr_t caller;
87      Dl_info *info;
88 {
89   if (caller != NULL)
90     {
91       if (info != NULL)
92         {
93           char *buf = (char *) "";
94           if (info->dli_sname != NULL)
95             {
96               size_t len = strlen (info->dli_sname);
97               buf = alloca (len + 6 + 2 * sizeof (void *));
98
99               buf[0] = '(';
100               __stpcpy (_fitoa (caller >= (const __ptr_t) info->dli_saddr
101                                 ? caller - (const __ptr_t) info->dli_saddr
102                                 : (const __ptr_t) info->dli_saddr - caller,
103                                 __stpcpy (__mempcpy (buf + 1, info->dli_sname,
104                                                      len),
105                                           caller >= (__ptr_t) info->dli_saddr
106                                           ? "+0x" : "-0x"),
107                                 16, 0),
108                         ")");
109             }
110
111           fprintf (mallstream, "@ %s%s%s[%p] ",
112                    info->dli_fname ?: "", info->dli_fname ? ":" : "",
113                    buf, caller);
114         }
115       else
116         fprintf (mallstream, "@ [%p] ", caller);
117     }
118 }
119
120
121 static Dl_info *
122 lock_and_info (const __ptr_t caller, Dl_info *mem)
123 {
124   if (caller == NULL)
125     return NULL;
126
127   Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
128
129   __libc_lock_lock (lock);
130
131   return res;
132 }
133
134
135 static void tr_freehook (__ptr_t, const __ptr_t) __THROW;
136 static void
137 tr_freehook (ptr, caller)
138      __ptr_t ptr;
139      const __ptr_t caller;
140 {
141   if (ptr == NULL)
142     return;
143
144   Dl_info mem;
145   Dl_info *info = lock_and_info (caller, &mem);
146   tr_where (caller, info);
147   /* Be sure to print it first.  */
148   fprintf (mallstream, "- %p\n", ptr);
149   __libc_lock_unlock (lock);
150   if (ptr == mallwatch)
151     tr_break ();
152   __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);
160 }
161
162 static __ptr_t tr_mallochook (__malloc_size_t, const __ptr_t) __THROW;
163 static __ptr_t
164 tr_mallochook (size, caller)
165      __malloc_size_t size;
166      const __ptr_t caller;
167 {
168   __ptr_t hdr;
169
170   Dl_info mem;
171   Dl_info *info = lock_and_info (caller, &mem);
172
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;
179
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);
183
184   __libc_lock_unlock (lock);
185
186   if (hdr == mallwatch)
187     tr_break ();
188
189   return hdr;
190 }
191
192 static __ptr_t tr_reallochook (__ptr_t, __malloc_size_t, const __ptr_t)
193      __THROW;
194 static __ptr_t
195 tr_reallochook (ptr, size, caller)
196      __ptr_t ptr;
197      __malloc_size_t size;
198      const __ptr_t caller;
199 {
200   __ptr_t hdr;
201
202   if (ptr == mallwatch)
203     tr_break ();
204
205   Dl_info mem;
206   Dl_info *info = lock_and_info (caller, &mem);
207
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;
218
219   tr_where (caller, info);
220   if (hdr == NULL)
221     /* Failed realloc.  */
222     fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
223   else if (ptr == NULL)
224     fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
225   else
226     {
227       fprintf (mallstream, "< %p\n", ptr);
228       tr_where (caller, info);
229       fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
230     }
231
232   __libc_lock_unlock (lock);
233
234   if (hdr == mallwatch)
235     tr_break ();
236
237   return hdr;
238 }
239
240 static __ptr_t tr_memalignhook (__malloc_size_t, __malloc_size_t,
241                                 const __ptr_t) __THROW;
242 static __ptr_t
243 tr_memalignhook (alignment, size, caller)
244      __malloc_size_t alignment, size;
245      const __ptr_t caller;
246 {
247   __ptr_t hdr;
248
249   Dl_info mem;
250   Dl_info *info = lock_and_info (caller, &mem);
251
252   __memalign_hook = tr_old_memalign_hook;
253   __malloc_hook = tr_old_malloc_hook;
254   if (tr_old_memalign_hook != NULL)
255     hdr = (__ptr_t) (*tr_old_memalign_hook) (alignment, size, caller);
256   else
257     hdr = (__ptr_t) memalign (alignment, size);
258   __memalign_hook = tr_memalignhook;
259   __malloc_hook = tr_mallochook;
260
261   tr_where (caller, info);
262   /* We could be printing a NULL here; that's OK.  */
263   fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
264
265   __libc_lock_unlock (lock);
266
267   if (hdr == mallwatch)
268     tr_break ();
269
270   return hdr;
271 }
272
273
274
275 #ifdef _LIBC
276
277 /* This function gets called to make sure all memory the library
278    allocates get freed and so does not irritate the user when studying
279    the mtrace output.  */
280 static void __libc_freeres_fn_section
281 release_libc_mem (void)
282 {
283   /* Only call the free function if we still are running in mtrace mode.  */
284   if (mallstream != NULL)
285     __libc_freeres ();
286 }
287 #endif
288
289
290 /* We enable tracing if either the environment variable MALLOC_TRACE
291    is set, or if the variable mallwatch has been patched to an address
292    that the debugging user wants us to stop on.  When patching mallwatch,
293    don't forget to set a breakpoint on tr_break!  */
294
295 void
296 mtrace ()
297 {
298 #ifdef _LIBC
299   static int added_atexit_handler;
300 #endif
301   char *mallfile;
302
303   /* Don't panic if we're called more than once.  */
304   if (mallstream != NULL)
305     return;
306
307 #ifdef _LIBC
308   /* When compiling the GNU libc we use the secure getenv function
309      which prevents the misuse in case of SUID or SGID enabled
310      programs.  */
311   mallfile = __secure_getenv (mallenv);
312 #else
313   mallfile = getenv (mallenv);
314 #endif
315   if (mallfile != NULL || mallwatch != NULL)
316     {
317       char *mtb = malloc (TRACE_BUFFER_SIZE);
318       if (mtb == NULL)
319         return;
320
321       mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
322       if (mallstream != NULL)
323         {
324 #ifndef __ASSUME_O_CLOEXEC
325           /* Make sure we close the file descriptor on exec.  */
326           int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
327           if (flags >= 0)
328             {
329               flags |= FD_CLOEXEC;
330               __fcntl (fileno (mallstream), F_SETFD, flags);
331             }
332 #endif
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");
337           tr_old_free_hook = __free_hook;
338           __free_hook = tr_freehook;
339           tr_old_malloc_hook = __malloc_hook;
340           __malloc_hook = tr_mallochook;
341           tr_old_realloc_hook = __realloc_hook;
342           __realloc_hook = tr_reallochook;
343           tr_old_memalign_hook = __memalign_hook;
344           __memalign_hook = tr_memalignhook;
345 #ifdef _LIBC
346           if (!added_atexit_handler)
347             {
348               extern void *__dso_handle __attribute__ ((__weak__));
349               added_atexit_handler = 1;
350               __cxa_atexit ((void (*) (void *)) release_libc_mem, NULL,
351                              &__dso_handle ? __dso_handle : NULL);
352             }
353 #endif
354         }
355       else
356         free (mtb);
357     }
358 }
359
360 void
361 muntrace ()
362 {
363   if (mallstream == NULL)
364     return;
365
366   fprintf (mallstream, "= End\n");
367   fclose (mallstream);
368   mallstream = NULL;
369   __free_hook = tr_old_free_hook;
370   __malloc_hook = tr_old_malloc_hook;
371   __realloc_hook = tr_old_realloc_hook;
372   __memalign_hook = tr_old_memalign_hook;
373 }