Unify names of used global functions.
[kopensolaris-gnu/glibc.git] / malloc / mtrace.c
1 /* More debugging hooks for `malloc'.
2    Copyright (C) 1991, 92, 93, 94, 96, 97, 98 Free Software Foundation, Inc.
3                  Written April 2, 1991 by John Gilmore of Cygnus Support.
4                  Based on mcheck.c by Mike Haertel.
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with this library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.
20
21    The author may be reached (Email) at the address mike@ai.mit.edu,
22    or (US mail) as Mike Haertel c/o Free Software Foundation.  */
23
24 #ifndef _MALLOC_INTERNAL
25 #define _MALLOC_INTERNAL
26 #include <malloc.h>
27 #include <mcheck.h>
28 #include <bits/libc-lock.h>
29 #endif
30
31 #ifdef HAVE_ELF
32 #include <elf/ldsodefs.h>
33 #endif
34
35 #include <stdio.h>
36
37 #ifndef __GNU_LIBRARY__
38 extern char *getenv ();
39 #else
40 #include <stdlib.h>
41 #endif
42
43 #if defined _LIBC && defined USE_IN_LIBIO
44 # define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
45 #endif
46
47 #define TRACE_BUFFER_SIZE 512
48
49 static FILE *mallstream;
50 static const char mallenv[]= "MALLOC_TRACE";
51 static char malloc_trace_buffer[TRACE_BUFFER_SIZE];
52
53 __libc_lock_define_initialized (static, lock);
54
55 /* Address to breakpoint on accesses to... */
56 __ptr_t mallwatch;
57
58 /* File name and line number information, for callers that had
59    the foresight to call through a macro.  */
60 char *_mtrace_file;
61 int _mtrace_line;
62
63 /* Old hook values.  */
64 static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
65 static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size,
66                                            const __ptr_t));
67 static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
68                                             __malloc_size_t size,
69                                             const __ptr_t));
70
71 /* This function is called when the block being alloc'd, realloc'd, or
72    freed has an address matching the variable "mallwatch".  In a debugger,
73    set "mallwatch" to the address of interest, then put a breakpoint on
74    tr_break.  */
75
76 void tr_break __P ((void));
77 void
78 tr_break ()
79 {
80 }
81
82 static void tr_where __P ((const __ptr_t)) internal_function;
83 static void
84 internal_function
85 tr_where (caller)
86      const __ptr_t caller;
87 {
88   if (_mtrace_file)
89     {
90       fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
91       _mtrace_file = NULL;
92     }
93   else if (caller != NULL)
94     {
95 #ifdef HAVE_ELF
96       Dl_info info;
97       if (_dl_addr (caller, &info))
98         {
99           fprintf (mallstream, "@ %s%s%s%s%s[%p]",
100                    info.dli_fname ?: "", info.dli_fname ? ":" : "",
101                    info.dli_sname ? "(" : "",
102                    info.dli_sname ?: "", info.dli_sname ? ") " : " ",
103                    caller);
104         }
105       else
106 #endif
107         fprintf (mallstream, "@ [%p] ", caller);
108     }
109 }
110
111 static void tr_freehook __P ((__ptr_t, const __ptr_t));
112 static void
113 tr_freehook (ptr, caller)
114      __ptr_t ptr;
115      const __ptr_t caller;
116 {
117   tr_where (caller);
118   /* Be sure to print it first.  */
119   fprintf (mallstream, "- %p\n", ptr);
120   if (ptr == mallwatch)
121     tr_break ();
122   __libc_lock_lock (lock);
123   __free_hook = tr_old_free_hook;
124   if (tr_old_free_hook != NULL)
125     (*tr_old_free_hook) (ptr, caller);
126   else
127     free (ptr);
128   __free_hook = tr_freehook;
129   __libc_lock_unlock (lock);
130 }
131
132 static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
133 static __ptr_t
134 tr_mallochook (size, caller)
135      __malloc_size_t size;
136      const __ptr_t caller;
137 {
138   __ptr_t hdr;
139
140   __libc_lock_lock (lock);
141
142   __malloc_hook = tr_old_malloc_hook;
143   if (tr_old_malloc_hook != NULL)
144     hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
145   else
146     hdr = (__ptr_t) malloc (size);
147   __malloc_hook = tr_mallochook;
148
149   __libc_lock_unlock (lock);
150
151   tr_where (caller);
152   /* We could be printing a NULL here; that's OK.  */
153   fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
154
155   if (hdr == mallwatch)
156     tr_break ();
157
158   return hdr;
159 }
160
161 static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
162 static __ptr_t
163 tr_reallochook (ptr, size, caller)
164      __ptr_t ptr;
165      __malloc_size_t size;
166      const __ptr_t caller;
167 {
168   __ptr_t hdr;
169
170   if (ptr == mallwatch)
171     tr_break ();
172
173   __libc_lock_lock (lock);
174
175   __free_hook = tr_old_free_hook;
176   __malloc_hook = tr_old_malloc_hook;
177   __realloc_hook = tr_old_realloc_hook;
178   if (tr_old_realloc_hook != NULL)
179     hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
180   else
181     hdr = (__ptr_t) realloc (ptr, size);
182   __free_hook = tr_freehook;
183   __malloc_hook = tr_mallochook;
184   __realloc_hook = tr_reallochook;
185
186   __libc_lock_unlock (lock);
187
188   tr_where (caller);
189   if (hdr == NULL)
190     /* Failed realloc.  */
191     fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
192   else if (ptr == NULL)
193     fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
194   else
195     fprintf (mallstream, "< %p\n> %p %#lx\n", ptr, hdr,
196              (unsigned long int) size);
197
198   if (hdr == mallwatch)
199     tr_break ();
200
201   return hdr;
202 }
203
204
205 #ifdef _LIBC
206 extern void __libc_freeres (void);
207
208 /* This function gets called to make sure all memory the library
209    allocates get freed and so does not irritate the user when studying
210    the mtrace output.  */
211 static void
212 release_libc_mem (void)
213 {
214   /* Only call the free function if we still are running in mtrace mode.  */
215   if (mallstream != NULL)
216     __libc_freeres ();
217 }
218 #endif
219
220
221 /* We enable tracing if either the environment variable MALLOC_TRACE
222    is set, or if the variable mallwatch has been patched to an address
223    that the debugging user wants us to stop on.  When patching mallwatch,
224    don't forget to set a breakpoint on tr_break!  */
225
226 void
227 mtrace ()
228 {
229 #ifdef _LIBC
230   static int added_atexit_handler = 0;
231 #endif
232   char *mallfile;
233
234   /* Don't panic if we're called more than once.  */
235   if (mallstream != NULL)
236     return;
237
238 #ifdef _LIBC
239   /* When compiling the GNU libc we use the secure getenv function
240      which prevents the misuse in case of SUID or SGID enabled
241      programs.  */
242   mallfile = __secure_getenv (mallenv);
243 #else
244   mallfile = getenv (mallenv);
245 #endif
246   if (mallfile != NULL || mallwatch != NULL)
247     {
248       mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
249       if (mallstream != NULL)
250         {
251           /* Be sure it doesn't malloc its buffer!  */
252           setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
253           fprintf (mallstream, "= Start\n");
254           tr_old_free_hook = __free_hook;
255           __free_hook = tr_freehook;
256           tr_old_malloc_hook = __malloc_hook;
257           __malloc_hook = tr_mallochook;
258           tr_old_realloc_hook = __realloc_hook;
259           __realloc_hook = tr_reallochook;
260 #ifdef _LIBC
261           if (!added_atexit_handler)
262             {
263               added_atexit_handler = 1;
264               atexit (release_libc_mem);
265             }
266 #endif
267         }
268     }
269 }
270
271 void
272 muntrace ()
273 {
274   if (mallstream == NULL)
275     return;
276
277   fprintf (mallstream, "= End\n");
278   fclose (mallstream);
279   mallstream = NULL;
280   __free_hook = tr_old_free_hook;
281   __malloc_hook = tr_old_malloc_hook;
282   __realloc_hook = tr_old_realloc_hook;
283 }