Bash  5.0-beta2
Bash - Bourne Again shell
table.c
Go to the documentation of this file.
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
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
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
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
307 {
308  _register_dump_table (stderr);
309 }
310 
311 void
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
422  int n;
423 {
424  int old;
425 
426  old = malloc_register;
427  malloc_register = n;
428  return old;
429 }
int signal_is_trapped(int)
Definition: trap.c:1337
unsigned long int n
Definition: eval-plural.h:35
register GCHAR c
Definition: glob_loop.c:26
#define PTR_T
Definition: hashlib.h:30
char * strrchr()
#define __P(protos)
Definition: stdc.h:35
static nls_uint32 nls_uint32 i
Definition: gettextP.h:74
void _malloc_block_signals()
int malloc_register
Definition: malloc.c:311
int running_trap
Definition: trap.c:113
void xs_init _((void))
void mregister_table_init()
#define NULL
Definition: general.h:53
int flags
Definition: gm_loop.c:47
char * memset(char *str, int c, unsigned int len)
Definition: memset.c:22
#define STREQ(a, b)
Definition: general.h:166
void mregister_dump_table()
void _malloc_unblock_signals()
static char * tp
Definition: expr.c:168
int interrupt_immediately
Definition: sig.c:86
int malloc_set_register(int n)
Definition: table.c:421