]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/malloc/table.c
bash-4.4 rc1 release
[thirdparty/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
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "imalloc.h"
29 #include "table.h"
30
31 #ifdef SHELL
32 extern int interrupt_immediately, running_trap;
33 extern int signal_is_trapped __P((int));
34 #endif
35
36 extern int malloc_register;
37
38 #ifdef MALLOC_REGISTER
39
40 extern FILE *_imalloc_fopen __P((char *, char *, char *, char *, size_t));
41
42 #define FIND_ALLOC 0x01 /* find slot for new allocation */
43 #define FIND_EXIST 0x02 /* find slot for existing entry for free() or search */
44
45 static int table_count = 0;
46 static int table_allocated = 0;
47 static int table_bucket_index = REG_TABLE_SIZE-1;
48 static mr_table_t mem_table[REG_TABLE_SIZE];
49 static mr_table_t mem_overflow;
50
51 #ifndef STREQ
52 #define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
53 #endif
54
55 static int location_table_index = 0;
56 static int location_table_count = 0;
57 static ma_table_t mlocation_table[REG_TABLE_SIZE];
58
59 /*
60 * NOTE: taken from dmalloc (http://dmalloc.com) and modified.
61 */
62 static unsigned int
63 mt_hash (key)
64 const PTR_T key;
65 {
66 unsigned int a, b, c;
67 unsigned long x;
68
69 /* set up the internal state */
70 a = 0x9e3779b9; /* the golden ratio; an arbitrary value */
71 x = (unsigned long)key; /* truncation is OK */
72 b = x >> 8;
73 c = x >> 3; /* XXX - was >> 4 */
74
75 HASH_MIX(a, b, c);
76 return c;
77 }
78
79 #if 0
80 static unsigned int
81 which_bucket (mem)
82 PTR_T mem;
83 {
84 return (mt_hash ((unsigned char *)mem) & (REG_TABLE_SIZE-1));
85 }
86
87 #else
88 #define which_bucket(mem) (mt_hash ((unsigned char *)(mem)) & (REG_TABLE_SIZE-1));
89
90 #define next_bucket() ((table_bucket_index + 1) & (REG_TABLE_SIZE-1))
91 #define next_entry(mem) ((mem == mem_table + REG_TABLE_SIZE - 1) ? mem_table : ++mem)
92
93 #define prev_bucket() (table_bucket_index == 0 ? REG_TABLE_SIZE-1 : table_bucket_index-1)
94 #define prev_entry(mem) ((mem == mem_table) ? mem_table + REG_TABLE_SIZE - 1 : mem - 1)
95 #endif
96
97 static mr_table_t *
98 find_entry (mem, flags)
99 PTR_T mem;
100 int flags;
101 {
102 unsigned int bucket;
103 register mr_table_t *tp;
104 mr_table_t *endp;
105
106 if (mem_overflow.mem == mem)
107 return (&mem_overflow);
108
109 /* If we want to insert an allocation entry just use the next slot */
110 if (flags & FIND_ALLOC)
111 {
112 table_bucket_index = next_bucket();
113 table_count++;
114 tp = mem_table + table_bucket_index;
115 memset(tp, 0, sizeof (mr_table_t)); /* overwrite next existing entry */
116 return tp;
117 }
118
119 tp = endp = mem_table + table_bucket_index;
120
121 /* search for last allocation corresponding to MEM, return entry pointer */
122 while (1)
123 {
124 if (tp->mem == mem)
125 return (tp);
126
127 tp = prev_entry (tp);
128
129 /* if we went all the way around and didn't find it, return NULL */
130 if (tp == endp)
131 return ((mr_table_t *)NULL);
132 }
133
134 return (mr_table_t *)NULL;
135 }
136
137 mr_table_t *
138 mr_table_entry (mem)
139 PTR_T mem;
140 {
141 return (find_entry (mem, FIND_EXIST));
142 }
143
144 void
145 mregister_describe_mem (mem, fp)
146 PTR_T mem;
147 FILE *fp;
148 {
149 mr_table_t *entry;
150
151 entry = find_entry (mem, FIND_EXIST);
152 if (entry == 0)
153 return;
154 fprintf (fp, "malloc: %p: %s: last %s from %s:%d\n",
155 mem,
156 (entry->flags & MT_ALLOC) ? "allocated" : "free",
157 (entry->flags & MT_ALLOC) ? "allocated" : "freed",
158 entry->file ? entry->file : "unknown",
159 entry->line);
160 }
161
162 void
163 mregister_alloc (tag, mem, size, file, line)
164 const char *tag;
165 PTR_T mem;
166 size_t size;
167 const char *file;
168 int line;
169 {
170 mr_table_t *tentry;
171 sigset_t set, oset;
172 int blocked_sigs;
173
174 /* Block all signals in case we are executed from a signal handler. */
175 blocked_sigs = 0;
176 #ifdef SHELL
177 if (interrupt_immediately || running_trap || signal_is_trapped (SIGINT) || signal_is_trapped (SIGCHLD))
178 #endif
179 {
180 _malloc_block_signals (&set, &oset);
181 blocked_sigs = 1;
182 }
183
184 mlocation_register_alloc (file, line);
185
186 tentry = find_entry (mem, FIND_ALLOC);
187
188 if (tentry == 0)
189 {
190 /* oops. table is full. punt. */
191 fprintf (stderr, _("register_alloc: alloc table is full with FIND_ALLOC?\n"));
192 if (blocked_sigs)
193 _malloc_unblock_signals (&set, &oset);
194 return;
195 }
196
197 if (tentry->flags & MT_ALLOC)
198 {
199 /* oops. bad bookkeeping. ignore for now */
200 fprintf (stderr, _("register_alloc: %p already in table as allocated?\n"), mem);
201 }
202
203 tentry->mem = mem;
204 tentry->size = size;
205 tentry->func = tag;
206 tentry->flags = MT_ALLOC;
207 tentry->file = file;
208 tentry->line = line;
209 tentry->nalloc++;
210
211 if (tentry != &mem_overflow)
212 table_allocated++;
213
214 if (blocked_sigs)
215 _malloc_unblock_signals (&set, &oset);
216 }
217
218 void
219 mregister_free (mem, size, file, line)
220 PTR_T mem;
221 int size;
222 const char *file;
223 int line;
224 {
225 mr_table_t *tentry;
226 sigset_t set, oset;
227 int blocked_sigs;
228
229 /* Block all signals in case we are executed from a signal handler. */
230 blocked_sigs = 0;
231 #ifdef SHELL
232 if (interrupt_immediately || running_trap || signal_is_trapped (SIGINT) || signal_is_trapped (SIGCHLD))
233 #endif
234 {
235 _malloc_block_signals (&set, &oset);
236 blocked_sigs = 1;
237 }
238
239 tentry = find_entry (mem, FIND_EXIST);
240 if (tentry == 0)
241 {
242 /* oops. not found. */
243 #if 0
244 fprintf (stderr, "register_free: %p not in allocation table?\n", mem);
245 #endif
246 if (blocked_sigs)
247 _malloc_unblock_signals (&set, &oset);
248 return;
249 }
250 if (tentry->flags & MT_FREE)
251 {
252 /* oops. bad bookkeeping. ignore for now */
253 fprintf (stderr, _("register_free: %p already in table as free?\n"), mem);
254 }
255
256 tentry->flags = MT_FREE;
257 tentry->func = "free";
258 tentry->file = file;
259 tentry->line = line;
260 tentry->nfree++;
261
262 if (tentry != &mem_overflow)
263 table_allocated--;
264
265 if (blocked_sigs)
266 _malloc_unblock_signals (&set, &oset);
267 }
268
269 /* If we ever add more flags, this will require changes. */
270 static char *
271 _entry_flags(x)
272 int x;
273 {
274 if (x & MT_FREE)
275 return "free";
276 else if (x & MT_ALLOC)
277 return "allocated";
278 else
279 return "undetermined?";
280 }
281
282 static void
283 _register_dump_table(fp)
284 FILE *fp;
285 {
286 register int i;
287 mr_table_t entry;
288
289 for (i = 0; i < REG_TABLE_SIZE; i++)
290 {
291 entry = mem_table[i];
292 if (entry.mem)
293 fprintf (fp, "%s[%d] %p:%zu:%s:%s:%s:%d:%d:%d\n",
294 (i == table_bucket_index) ? "*" : "",
295 i,
296 entry.mem, entry.size,
297 _entry_flags(entry.flags),
298 entry.func ? entry.func : "unknown",
299 entry.file ? entry.file : "unknown",
300 entry.line,
301 entry.nalloc, entry.nfree);
302 }
303 }
304
305 void
306 mregister_dump_table()
307 {
308 _register_dump_table (stderr);
309 }
310
311 void
312 mregister_table_init ()
313 {
314 memset (mem_table, 0, sizeof(mr_table_t) * REG_TABLE_SIZE);
315 memset (&mem_overflow, 0, sizeof (mr_table_t));
316 table_count = 0;
317 }
318
319 /* Simple for now */
320
321 static ma_table_t *
322 find_location_entry (file, line)
323 const char *file;
324 int line;
325 {
326 register ma_table_t *tp, *endp;
327
328 endp = mlocation_table + location_table_count;
329 for (tp = mlocation_table; tp <= endp; tp++)
330 {
331 if (tp->line == line && STREQ (file, tp->file))
332 return tp;
333 }
334 return (ma_table_t *)NULL;
335 }
336
337 void
338 mlocation_register_alloc (file, line)
339 const char *file;
340 int line;
341 {
342 ma_table_t *lentry;
343 const char *nfile;
344
345 if (file == 0)
346 {
347 mlocation_table[0].nalloc++;
348 return;
349 }
350
351 nfile = strrchr (file, '/');
352 if (nfile)
353 nfile++;
354 else
355 nfile = file;
356
357 lentry = find_location_entry (nfile, line);
358 if (lentry == 0)
359 {
360 location_table_index++;
361 if (location_table_index == REG_TABLE_SIZE)
362 location_table_index = 1; /* slot 0 reserved */
363 lentry = mlocation_table + location_table_index;
364 lentry->file = nfile;
365 lentry->line = line;
366 lentry->nalloc = 1;
367 if (location_table_count < REG_TABLE_SIZE)
368 location_table_count++; /* clamp at REG_TABLE_SIZE for now */
369 }
370 else
371 lentry->nalloc++;
372 }
373
374 static void
375 _location_dump_table (fp)
376 FILE *fp;
377 {
378 register ma_table_t *tp, *endp;
379
380 endp = mlocation_table + location_table_count;
381 for (tp = mlocation_table; tp < endp; tp++)
382 fprintf (fp, "%s:%d\t%d\n", tp->file ? tp->file : "unknown",
383 tp->line ? tp->line : 0,
384 tp->nalloc);
385 }
386
387 void
388 mlocation_dump_table ()
389 {
390 _location_dump_table (stderr);
391 }
392
393 #define LOCROOT "/var/tmp/maltrace/locations."
394
395 void
396 mlocation_write_table ()
397 {
398 FILE *fp;
399 char defname[sizeof (LOCROOT) + 64];
400
401 fp = _imalloc_fopen ((char *)NULL, (char *)NULL, LOCROOT, defname, sizeof (defname));
402 if (fp == 0)
403 return; /* XXX - no error message yet */
404 _location_dump_table (fp);
405 fclose (fp);
406 }
407
408 void
409 mlocation_table_init ()
410 {
411 memset (mlocation_table, 0, sizeof (ma_table_t) * REG_TABLE_SIZE);
412 mlocation_table[0].file = ""; /* reserve slot 0 for unknown locations */
413 mlocation_table[0].line = 0;
414 mlocation_table[0].nalloc = 0;
415 location_table_count = 1;
416 }
417
418 #endif /* MALLOC_REGISTER */
419
420 int
421 malloc_set_register(n)
422 int n;
423 {
424 int old;
425
426 old = malloc_register;
427 malloc_register = n;
428 return old;
429 }