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