1/* watch.c - watchpoint functions for malloc */
2
3/* Copyright (C) 2001-2003 Free Software Foundation, Inc.
4
5   This file is part of GNU Bash, the Bourne Again SHell.
6
7   Bash is free software; you can redistribute it and/or modify it under
8   the terms of the GNU General Public License as published by the Free
9   Software Foundation; either version 2, or (at your option) any later
10   version.
11
12   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or
14   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15   for more details.
16
17   You should have received a copy of the GNU General Public License along
18   with Bash; see the file COPYING.  If not, write to the Free Software
19   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20#ifdef HAVE_CONFIG_H
21#  include <config.h>
22#endif
23
24#include <stdio.h>
25
26#include "imalloc.h"
27
28#ifdef MALLOC_WATCH
29#include "watch.h"
30
31#define WATCH_MAX	32
32
33int		_malloc_nwatch;
34static PTR_T	_malloc_watch_list[WATCH_MAX];
35
36static void
37watch_warn (addr, file, line, type, data)
38     PTR_T addr;
39     const char *file;
40     int line, type;
41     unsigned long data;
42{
43  char *tag;
44
45  if (type == W_ALLOC)
46    tag = _("allocated");
47  else if (type == W_FREE)
48    tag = _("freed");
49  else if (type == W_REALLOC)
50    tag = _("requesting resize");
51  else if (type == W_RESIZED)
52    tag = _("just resized");
53  else
54    tag = _("bug: unknown operation");
55
56  fprintf (stderr, _("malloc: watch alert: %p %s "), addr, tag);
57  if (data != (unsigned long)-1)
58    fprintf (stderr, "(size %lu) ", data);
59  fprintf (stderr, "from '%s:%d'\n", file ? file : "unknown", line);
60}
61
62void
63_malloc_ckwatch (addr, file, line, type, data)
64     PTR_T addr;
65     const char *file;
66     int line, type;
67     unsigned long data;
68{
69  register int i;
70
71  for (i = _malloc_nwatch - 1; i >= 0; i--)
72    {
73      if (_malloc_watch_list[i] == addr)
74	{
75	  watch_warn (addr, file, line, type, data);
76	  return;
77	}
78    }
79}
80#endif /* MALLOC_WATCH */
81
82PTR_T
83malloc_watch (addr)
84     PTR_T addr;
85{
86  register int i;
87  PTR_T ret;
88
89  if (addr == 0)
90    return addr;
91  ret = (PTR_T)0;
92
93#ifdef MALLOC_WATCH
94  for (i = _malloc_nwatch - 1; i >= 0; i--)
95    {
96      if (_malloc_watch_list[i] == addr)
97        break;
98    }
99  if (i < 0)
100    {
101      if (_malloc_nwatch == WATCH_MAX)	/* full, take out first */
102	{
103	  ret = _malloc_watch_list[0];
104	  _malloc_nwatch--;
105	  for (i = 0; i < _malloc_nwatch; i++)
106	    _malloc_watch_list[i] = _malloc_watch_list[i+1];
107	}
108      _malloc_watch_list[_malloc_nwatch++] = addr;
109    }
110#endif
111
112  return ret;
113}
114
115/* Remove a watchpoint set on ADDR.  If ADDR is NULL, remove all
116   watchpoints.  Returns ADDR if everything went OK, NULL if ADDR was
117   not being watched. */
118PTR_T
119malloc_unwatch (addr)
120     PTR_T addr;
121{
122#ifdef MALLOC_WATCH
123  register int i;
124
125  if (addr == 0)
126    {
127      for (i = 0; i < _malloc_nwatch; i++)
128        _malloc_watch_list[i] = (PTR_T)0;
129      _malloc_nwatch = 0;
130      return ((PTR_T)0);
131    }
132  else
133    {
134      for (i = 0; i < _malloc_nwatch; i++)
135	{
136	  if (_malloc_watch_list[i] == addr)
137	    break;
138	}
139      if (i == _malloc_nwatch)
140        return ((PTR_T)0);		/* not found */
141      /* shuffle everything from i+1 to end down 1 */
142      _malloc_nwatch--;
143      for ( ; i < _malloc_nwatch; i++)
144        _malloc_watch_list[i] = _malloc_watch_list[i+1];
145      return addr;
146    }
147#else
148  return ((PTR_T)0);
149#endif
150}
151