Include ldsodefs.h, not elf/ldsodefs.h.
[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 #include <ldsodefs.h>
32
33 #include <stdio.h>
34
35 #ifndef __GNU_LIBRARY__
36 extern char *getenv ();
37 #else
38 #include <stdlib.h>
39 #endif
40
41 #if defined _LIBC && defined USE_IN_LIBIO
42 # include <libio/iolibio.h>
43 # define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
44 #endif
45
46 #define TRACE_BUFFER_SIZE 512
47
48 static FILE *mallstream;
49 static const char mallenv[]= "MALLOC_TRACE";
50 static char malloc_trace_buffer[TRACE_BUFFER_SIZE];
51
52 __libc_lock_define_initialized (static, lock);
53
54 /* Address to breakpoint on accesses to... */
55 __ptr_t mallwatch;
56
57 /* File name and line number information, for callers that had
58    the foresight to call through a macro.  */
59 char *_mtrace_file;
60 int _mtrace_line;
61
62 /* Old hook values.  */
63 static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t));
64 static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size,
65                                            const __ptr_t));
66 static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr,
67                                             __malloc_size_t size,
68                                             const __ptr_t));
69
70 /* This function is called when the block being alloc'd, realloc'd, or
71    freed has an address matching the variable "mallwatch".  In a debugger,
72    set "mallwatch" to the address of interest, then put a breakpoint on
73    tr_break.  */
74
75 void tr_break __P ((void));
76 void
77 tr_break ()
78 {
79 }
80
81 static void tr_where __P ((const __ptr_t)) internal_function;
82 static void
83 internal_function
84 tr_where (caller)
85      const __ptr_t caller;
86 {
87   if (_mtrace_file)
88     {
89       fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
90       _mtrace_file = NULL;
91     }
92   else if (caller != NULL)
93     {
94 #ifdef HAVE_ELF
95       Dl_info info;
96       if (_dl_addr (caller, &info))
97         {
98           char *buf = (char *) "";
99           if (info.dli_sname && info.dli_sname[0])
100             {
101               size_t len = strlen (info.dli_sname) + 22;
102               buf = alloca (len);
103               if (caller >= (const __ptr_t) info.dli_saddr)
104                 snprintf (buf, len, "(%s+0x%x)", info.dli_sname,
105                           caller - (const __ptr_t) info.dli_saddr);
106               else
107                 snprintf (buf, len, "(%s-0x%x)", info.dli_sname,
108                           (const __ptr_t) info.dli_saddr - caller);
109             }
110
111           fprintf (mallstream, "@ %s%s%s[%p] ",
112                    info.dli_fname ?: "", info.dli_fname ? ":" : "",
113                    buf, caller);
114         }
115       else
116 #endif
117         fprintf (mallstream, "@ [%p] ", caller);
118     }
119 }
120
121 static void tr_freehook __P ((__ptr_t, const __ptr_t));
122 static void
123 tr_freehook (ptr, caller)
124      __ptr_t ptr;
125      const __ptr_t caller;
126 {
127   tr_where (caller);
128   /* Be sure to print it first.  */
129   fprintf (mallstream, "- %p\n", ptr);
130   if (ptr == mallwatch)
131     tr_break ();
132   __libc_lock_lock (lock);
133   __free_hook = tr_old_free_hook;
134   if (tr_old_free_hook != NULL)
135     (*tr_old_free_hook) (ptr, caller);
136   else
137     free (ptr);
138   __free_hook = tr_freehook;
139   __libc_lock_unlock (lock);
140 }
141
142 static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t));
143 static __ptr_t
144 tr_mallochook (size, caller)
145      __malloc_size_t size;
146      const __ptr_t caller;
147 {
148   __ptr_t hdr;
149
150   __libc_lock_lock (lock);
151
152   __malloc_hook = tr_old_malloc_hook;
153   if (tr_old_malloc_hook != NULL)
154     hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller);
155   else
156     hdr = (__ptr_t) malloc (size);
157   __malloc_hook = tr_mallochook;
158
159   __libc_lock_unlock (lock);
160
161   tr_where (caller);
162   /* We could be printing a NULL here; that's OK.  */
163   fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
164
165   if (hdr == mallwatch)
166     tr_break ();
167
168   return hdr;
169 }
170
171 static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
172 static __ptr_t
173 tr_reallochook (ptr, size, caller)
174      __ptr_t ptr;
175      __malloc_size_t size;
176      const __ptr_t caller;
177 {
178   __ptr_t hdr;
179
180   if (ptr == mallwatch)
181     tr_break ();
182
183   __libc_lock_lock (lock);
184
185   __free_hook = tr_old_free_hook;
186   __malloc_hook = tr_old_malloc_hook;
187   __realloc_hook = tr_old_realloc_hook;
188   if (tr_old_realloc_hook != NULL)
189     hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller);
190   else
191     hdr = (__ptr_t) realloc (ptr, size);
192   __free_hook = tr_freehook;
193   __malloc_hook = tr_mallochook;
194   __realloc_hook = tr_reallochook;
195
196   __libc_lock_unlock (lock);
197
198   tr_where (caller);
199   if (hdr == NULL)
200     /* Failed realloc.  */
201     fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
202   else if (ptr == NULL)
203     fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
204   else
205     {
206       fprintf (mallstream, "< %p\n", ptr);
207       tr_where (caller);
208       fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
209     }
210
211   if (hdr == mallwatch)
212     tr_break ();
213
214   return hdr;
215 }
216
217
218 #ifdef _LIBC
219 extern void __libc_freeres (void);
220
221 /* This function gets called to make sure all memory the library
222    allocates get freed and so does not irritate the user when studying
223    the mtrace output.  */
224 static void
225 release_libc_mem (void)
226 {
227   /* Only call the free function if we still are running in mtrace mode.  */
228   if (mallstream != NULL)
229     __libc_freeres ();
230 }
231 #endif
232
233
234 /* We enable tracing if either the environment variable MALLOC_TRACE
235    is set, or if the variable mallwatch has been patched to an address
236    that the debugging user wants us to stop on.  When patching mallwatch,
237    don't forget to set a breakpoint on tr_break!  */
238
239 void
240 mtrace ()
241 {
242 #ifdef _LIBC
243   static int added_atexit_handler = 0;
244 #endif
245   char *mallfile;
246
247   /* Don't panic if we're called more than once.  */
248   if (mallstream != NULL)
249     return;
250
251 #ifdef _LIBC
252   /* When compiling the GNU libc we use the secure getenv function
253      which prevents the misuse in case of SUID or SGID enabled
254      programs.  */
255   mallfile = __secure_getenv (mallenv);
256 #else
257   mallfile = getenv (mallenv);
258 #endif
259   if (mallfile != NULL || mallwatch != NULL)
260     {
261       mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
262       if (mallstream != NULL)
263         {
264           /* Be sure it doesn't malloc its buffer!  */
265           setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
266           fprintf (mallstream, "= Start\n");
267           tr_old_free_hook = __free_hook;
268           __free_hook = tr_freehook;
269           tr_old_malloc_hook = __malloc_hook;
270           __malloc_hook = tr_mallochook;
271           tr_old_realloc_hook = __realloc_hook;
272           __realloc_hook = tr_reallochook;
273 #ifdef _LIBC
274           if (!added_atexit_handler)
275             {
276               added_atexit_handler = 1;
277               atexit (release_libc_mem);
278             }
279 #endif
280         }
281     }
282 }
283
284 void
285 muntrace ()
286 {
287   if (mallstream == NULL)
288     return;
289
290   fprintf (mallstream, "= End\n");
291   fclose (mallstream);
292   mallstream = NULL;
293   __free_hook = tr_old_free_hook;
294   __malloc_hook = tr_old_malloc_hook;
295   __realloc_hook = tr_old_realloc_hook;
296 }