xref: /netbsd-src/external/gpl2/libmalloc/dist/mtrace.c (revision 49e111a21fcf8e0b21cd6328dbe39715707aff2b)
1 /*	$NetBSD: mtrace.c,v 1.2 2016/01/13 21:56:38 christos Exp $	*/
2 
3 /* More debugging hooks for `malloc'.
4    Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
5 		 Written April 2, 1991 by John Gilmore of Cygnus Support.
6 		 Based on mcheck.c by Mike Haertel.
7 
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12 
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 Library General Public License for more details.
17 
18 You should have received a copy of the GNU Library General Public
19 License along with this library; see the file COPYING.LIB.  If
20 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
21 Cambridge, MA 02139, USA.
22 
23    The author may be reached (Email) at the address mike@ai.mit.edu,
24    or (US mail) as Mike Haertel c/o Free Software Foundation.  */
25 
26 #ifndef	_MALLOC_INTERNAL
27 #define	_MALLOC_INTERNAL
28 #include <malloc.h>
29 #endif
30 
31 #include <stdio.h>
32 
33 #ifndef	__GNU_LIBRARY__
34 extern char *getenv ();
35 #else
36 #include <stdlib.h>
37 #endif
38 
39 static FILE *mallstream;
40 static char mallenv[]= "MALLOC_TRACE";
41 static char mallbuf[BUFSIZ];	/* Buffer for the output.  */
42 
43 /* Address to breakpoint on accesses to... */
44 __ptr_t mallwatch;
45 
46 /* File name and line number information, for callers that had
47    the foresight to call through a macro.  */
48 char *_mtrace_file;
49 int _mtrace_line;
50 
51 /* Old hook values.  */
52 static void (*tr_old_free_hook) __P ((__ptr_t ptr));
53 static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size));
54 static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size));
55 
56 /* This function is called when the block being alloc'd, realloc'd, or
57    freed has an address matching the variable "mallwatch".  In a debugger,
58    set "mallwatch" to the address of interest, then put a breakpoint on
59    tr_break.  */
60 
61 void tr_break __P ((void));
62 void
tr_break()63 tr_break ()
64 {
65 }
66 
67 static void tr_where __P ((void));
68 static void
tr_where()69 tr_where ()
70 {
71   if (_mtrace_file)
72     {
73       fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
74       _mtrace_file = NULL;
75     }
76 }
77 
78 static void tr_freehook __P ((__ptr_t));
79 static void
tr_freehook(ptr)80 tr_freehook (ptr)
81      __ptr_t ptr;
82 {
83   tr_where ();
84   fprintf (mallstream, "- %p\n", ptr);	/* Be sure to print it first.  */
85   if (ptr == mallwatch)
86     tr_break ();
87   __free_hook = tr_old_free_hook;
88   free (ptr);
89   __free_hook = tr_freehook;
90 }
91 
92 static __ptr_t tr_mallochook __P ((__malloc_size_t));
93 static __ptr_t
tr_mallochook(__malloc_size_t size)94 tr_mallochook (__malloc_size_t size)
95 {
96   __ptr_t hdr;
97 
98   __malloc_hook = tr_old_malloc_hook;
99   hdr = (__ptr_t) malloc (size);
100   __malloc_hook = tr_mallochook;
101 
102   tr_where ();
103   /* We could be printing a NULL here; that's OK.  */
104   fprintf (mallstream, "+ %p %lx\n", hdr, (unsigned long)size);
105 
106   if (hdr == mallwatch)
107     tr_break ();
108 
109   return hdr;
110 }
111 
112 static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t));
113 static __ptr_t
tr_reallochook(__ptr_t ptr,__malloc_size_t size)114 tr_reallochook (__ptr_t ptr, __malloc_size_t size)
115 {
116   __ptr_t hdr;
117 
118   if (ptr == mallwatch)
119     tr_break ();
120 
121   __free_hook = tr_old_free_hook;
122   __malloc_hook = tr_old_malloc_hook;
123   __realloc_hook = tr_old_realloc_hook;
124   hdr = (__ptr_t) realloc (ptr, size);
125   __free_hook = tr_freehook;
126   __malloc_hook = tr_mallochook;
127   __realloc_hook = tr_reallochook;
128   tr_where ();
129   if (hdr == NULL)
130     /* Failed realloc.  */
131     fprintf (mallstream, "! %p %lx\n", ptr, (unsigned long)size);
132   else
133     fprintf (mallstream, "< %p\n> %p %lx\n", ptr, hdr, (unsigned long)size);
134 
135   if (hdr == mallwatch)
136     tr_break ();
137 
138   return hdr;
139 }
140 
141 /* We enable tracing if either the environment variable MALLOC_TRACE
142    is set, or if the variable mallwatch has been patched to an address
143    that the debugging user wants us to stop on.  When patching mallwatch,
144    don't forget to set a breakpoint on tr_break!  */
145 
146 void
mtrace()147 mtrace ()
148 {
149   char *mallfile;
150 
151   /* Don't panic if we're called more than once.  */
152   if (mallstream != NULL)
153     return;
154 
155   mallfile = getenv (mallenv);
156   if (mallfile != NULL || mallwatch != NULL)
157     {
158       mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
159       if (mallstream != NULL)
160 	{
161 	  /* Be sure it doesn't malloc its buffer!  */
162 	  setbuf (mallstream, mallbuf);
163 	  fprintf (mallstream, "= Start\n");
164 	  tr_old_free_hook = __free_hook;
165 	  __free_hook = tr_freehook;
166 	  tr_old_malloc_hook = __malloc_hook;
167 	  __malloc_hook = tr_mallochook;
168 	  tr_old_realloc_hook = __realloc_hook;
169 	  __realloc_hook = tr_reallochook;
170 	}
171     }
172 }
173 
174 void
muntrace()175 muntrace ()
176 {
177   if (mallstream == NULL)
178     return;
179 
180   fprintf (mallstream, "= End\n");
181   fclose (mallstream);
182   mallstream = NULL;
183   __free_hook = tr_old_free_hook;
184   __malloc_hook = tr_old_malloc_hook;
185   __realloc_hook = tr_old_realloc_hook;
186 }
187