mtrace.c revision 1.2
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
8This library is free software; you can redistribute it and/or
9modify it under the terms of the GNU Library General Public License as
10published by the Free Software Foundation; either version 2 of the
11License, or (at your option) any later version.
12
13This library is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16Library General Public License for more details.
17
18You should have received a copy of the GNU Library General Public
19License along with this library; see the file COPYING.LIB.  If
20not, write to the Free Software Foundation, Inc., 675 Mass Ave,
21Cambridge, 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__
34extern char *getenv ();
35#else
36#include <stdlib.h>
37#endif
38
39static FILE *mallstream;
40static char mallenv[]= "MALLOC_TRACE";
41static 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.  */
48char *_mtrace_file;
49int _mtrace_line;
50
51/* Old hook values.  */
52static void (*tr_old_free_hook) __P ((__ptr_t ptr));
53static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size));
54static __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
61void tr_break __P ((void));
62void
63tr_break ()
64{
65}
66
67static void tr_where __P ((void));
68static void
69tr_where ()
70{
71  if (_mtrace_file)
72    {
73      fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
74      _mtrace_file = NULL;
75    }
76}
77
78static void tr_freehook __P ((__ptr_t));
79static void
80tr_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
92static __ptr_t tr_mallochook __P ((__malloc_size_t));
93static __ptr_t
94tr_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
112static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t));
113static __ptr_t
114tr_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
146void
147mtrace ()
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
174void
175muntrace ()
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