mtrace.c revision 1.1
1/*	$NetBSD: mtrace.c,v 1.1 2016/01/13 21:42:18 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 (size)
95     __malloc_size_t size;
96{
97  __ptr_t hdr;
98
99  __malloc_hook = tr_old_malloc_hook;
100  hdr = (__ptr_t) malloc (size);
101  __malloc_hook = tr_mallochook;
102
103  tr_where ();
104  /* We could be printing a NULL here; that's OK.  */
105  fprintf (mallstream, "+ %p %lx\n", hdr, (unsigned long)size);
106
107  if (hdr == mallwatch)
108    tr_break ();
109
110  return hdr;
111}
112
113static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t));
114static __ptr_t
115tr_reallochook (ptr, size)
116     __ptr_t ptr;
117     __malloc_size_t size;
118{
119  __ptr_t hdr;
120
121  if (ptr == mallwatch)
122    tr_break ();
123
124  __free_hook = tr_old_free_hook;
125  __malloc_hook = tr_old_malloc_hook;
126  __realloc_hook = tr_old_realloc_hook;
127  hdr = (__ptr_t) realloc (ptr, size);
128  __free_hook = tr_freehook;
129  __malloc_hook = tr_mallochook;
130  __realloc_hook = tr_reallochook;
131  tr_where ();
132  if (hdr == NULL)
133    /* Failed realloc.  */
134    fprintf (mallstream, "! %p %lx\n", ptr, (unsigned long)size);
135  else
136    fprintf (mallstream, "< %p\n> %p %lx\n", ptr, hdr, (unsigned long)size);
137
138  if (hdr == mallwatch)
139    tr_break ();
140
141  return hdr;
142}
143
144/* We enable tracing if either the environment variable MALLOC_TRACE
145   is set, or if the variable mallwatch has been patched to an address
146   that the debugging user wants us to stop on.  When patching mallwatch,
147   don't forget to set a breakpoint on tr_break!  */
148
149void
150mtrace ()
151{
152  char *mallfile;
153
154  /* Don't panic if we're called more than once.  */
155  if (mallstream != NULL)
156    return;
157
158  mallfile = getenv (mallenv);
159  if (mallfile != NULL || mallwatch != NULL)
160    {
161      mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
162      if (mallstream != NULL)
163	{
164	  /* Be sure it doesn't malloc its buffer!  */
165	  setbuf (mallstream, mallbuf);
166	  fprintf (mallstream, "= Start\n");
167	  tr_old_free_hook = __free_hook;
168	  __free_hook = tr_freehook;
169	  tr_old_malloc_hook = __malloc_hook;
170	  __malloc_hook = tr_mallochook;
171	  tr_old_realloc_hook = __realloc_hook;
172	  __realloc_hook = tr_reallochook;
173	}
174    }
175}
176
177void
178muntrace ()
179{
180  if (mallstream == NULL)
181    return;
182
183  fprintf (mallstream, "= End\n");
184  fclose (mallstream);
185  mallstream = NULL;
186  __free_hook = tr_old_free_hook;
187  __malloc_hook = tr_old_malloc_hook;
188  __realloc_hook = tr_old_realloc_hook;
189}
190