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