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