d7c48c5c8616f4a1240a8e8448b87b7c0a51a9d5
[platform/upstream/bash.git] / lib / malloc / table.c
1 /* table.c - bookkeeping functions for allocated memory */
2
3 /* Copyright (C) 2001 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 #include "table.h"
28
29 extern int malloc_register;
30
31 #ifdef MALLOC_REGISTER
32
33 #define FIND_ALLOC      0x01    /* allocate new entry or find existing */
34 #define FIND_EXIST      0x02    /* find existing entry */
35
36 static int table_count = 0;
37 static mr_table_t mem_table[REG_TABLE_SIZE];
38
39 /*
40  * NOTE: taken from dmalloc (http://dmalloc.com) and modified.
41  */
42 static unsigned int
43 mt_hash (key)
44      const PTR_T key;
45 {
46   unsigned int a, b, c, len;
47   unsigned long x;
48
49   /* set up the internal state */
50   a = 0x9e3779b9;       /* the golden ratio; an arbitrary value */
51   x = (unsigned long)key;               /* truncation is OK */
52   b = x >> 8;
53   c = x >> 3;                           /* XXX - was >> 4 */
54
55   HASH_MIX(a, b, c);
56   return c;
57 }
58
59 #if 0
60 static unsigned int
61 which_bucket (mem)
62      PTR_T mem;
63 {
64   return (mt_hash ((unsigned char *)mem) % REG_TABLE_SIZE);
65 }
66 #else
67 #define which_bucket(mem) (mt_hash ((unsigned char *)(mem)) % REG_TABLE_SIZE);
68 #endif
69
70 static mr_table_t *
71 find_entry (mem, flags)
72      PTR_T mem;
73      int flags;
74 {
75   unsigned int bucket;
76   register mr_table_t *tp;
77   mr_table_t *endp, *lastp;
78
79   bucket = which_bucket (mem);  /* get initial hash */
80   tp = endp = mem_table + bucket;
81   lastp = mem_table + REG_TABLE_SIZE;
82
83   while (1)
84     {
85       if (tp->mem == mem)
86         return (tp);
87       if (tp->mem == 0 && (flags & FIND_ALLOC))
88         {
89           table_count++;
90           return (tp);
91         }
92
93       tp++;
94
95       if (tp == lastp)          /* wrap around */
96         tp = mem_table;
97
98       if (tp == endp && (flags & FIND_EXIST))
99         return ((mr_table_t *)NULL);
100
101       if (tp == endp && (flags & FIND_ALLOC))
102         break;
103     }
104
105   /* oops.  table is full.  replace an existing free entry. */
106   do
107     {
108       if (tp->flags & MT_FREE)
109         {
110           memset(tp, 0, sizeof (mr_table_t));
111           return (tp);
112         }
113       tp++;
114     }
115   while (tp != endp);
116
117   /* wow. entirely full.  return NULL. */
118   return ((mr_table_t *)NULL);
119 }
120
121 mr_table_t *
122 mr_table_entry (mem)
123      PTR_T mem;
124 {
125   return (find_entry (mem, FIND_EXIST));
126 }
127
128 void
129 mregister_describe_mem (mem, fp)
130      PTR_T mem;
131      FILE *fp;
132 {
133   mr_table_t *entry;
134
135   entry = find_entry (mem, FIND_EXIST);
136   if (entry == 0)
137     return;
138   fprintf (fp, "malloc: %p: %s: last %s from %s:%d\n",
139                 mem,
140                 (entry->flags & MT_ALLOC) ? "allocated" : "free",
141                 (entry->flags & MT_ALLOC) ? "allocated" : "freed",
142                 entry->file ? entry->file : "unknown",
143                 entry->line);
144 }
145
146 void
147 mregister_alloc (tag, mem, size, file, line)
148      const char *tag;
149      PTR_T mem;
150      size_t size;
151      const char *file;
152      int line;
153 {
154   mr_table_t *tentry;
155
156   tentry = find_entry (mem, FIND_ALLOC);
157
158   if (tentry == 0)
159     {
160       /* oops.  table is full.  punt. */
161       fprintf (stderr, "register_alloc: alloc table is full?\n");
162       return;
163     }
164   
165   if (tentry->flags & MT_ALLOC)
166     {
167       /* oops.  bad bookkeeping. ignore for now */
168       fprintf (stderr, "register_alloc: %p already in table as allocated?\n", mem);
169     }
170
171   tentry->mem = mem;
172   tentry->size = size;
173   tentry->func = tag;
174   tentry->flags = MT_ALLOC;
175   tentry->file = file;
176   tentry->line = line;
177   tentry->nalloc++;
178 }
179
180 void
181 mregister_free (mem, size, file, line)
182      PTR_T mem;
183      int size;
184      const char *file;
185      int line;
186 {
187   mr_table_t *tentry;
188
189   tentry = find_entry (mem, FIND_EXIST);
190   if (tentry == 0)
191     {
192       /* oops.  not found. */
193       fprintf (stderr, "register_free: %p not in allocation table?\n", mem);
194       return;
195     }
196   if (tentry->flags & MT_FREE)
197     {
198       /* oops.  bad bookkeeping. ignore for now */
199       fprintf (stderr, "register_free: %p already in table as free?\n", mem);
200     }
201         
202   tentry->flags = MT_FREE;
203   tentry->func = "free";
204   tentry->file = file;
205   tentry->line = line;
206   tentry->nfree++;
207 }
208
209 /* If we ever add more flags, this will require changes. */
210 static char *
211 _entry_flags(x)
212      int x;
213 {
214   if (x & MT_FREE)
215     return "free";
216   else if (x & MT_ALLOC)
217     return "allocated";
218   else
219     return "undetermined?";
220 }
221
222 static void
223 _register_dump_table(fp)
224      FILE *fp;
225 {
226   register int i;
227   mr_table_t entry;
228
229   for (i = 0; i < REG_TABLE_SIZE; i++)
230     {
231       entry = mem_table[i];
232       if (entry.mem)
233         fprintf (fp, "[%d] %p:%d:%s:%s:%s:%d:%d:%d\n", i,
234                                                 entry.mem, entry.size,
235                                                 _entry_flags(entry.flags),
236                                                 entry.func ? entry.func : "unknown",
237                                                 entry.file ? entry.file : "unknown",
238                                                 entry.line,
239                                                 entry.nalloc, entry.nfree);
240     }
241 }
242  
243 void
244 mregister_dump_table()
245 {
246   _register_dump_table (stderr);
247 }
248
249 void
250 mregister_table_init ()
251 {
252   memset (mem_table, 0, sizeof(mr_table_t) * REG_TABLE_SIZE);
253   table_count = 0;
254 }
255
256 #endif /* MALLOC_REGISTER */
257
258 int
259 malloc_set_register(n)
260      int n;
261 {
262   int old;
263
264   old = malloc_register;
265   malloc_register = n;
266   return old;
267 }