1 /* table.c - bookkeeping functions for allocated memory */
3 /* Copyright (C) 2001-2003 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
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.
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.
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/>.
32 extern int interrupt_immediately
, running_trap
;
33 extern int signal_is_trapped
__P((int));
36 extern int malloc_register
;
38 #ifdef MALLOC_REGISTER
40 extern FILE *_imalloc_fopen
__P((char *, char *, char *, char *, size_t));
42 #define FIND_ALLOC 0x01 /* find slot for new allocation */
43 #define FIND_EXIST 0x02 /* find slot for existing entry for free() or search */
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
;
52 #define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
55 static int location_table_index
= 0;
56 static int location_table_count
= 0;
57 static ma_table_t mlocation_table
[REG_TABLE_SIZE
];
60 * NOTE: taken from dmalloc (http://dmalloc.com) and modified.
69 /* set up the internal state */
70 a
= 0x9e3779b9; /* the golden ratio; an arbitrary value */
71 x
= (unsigned long)key
; /* truncation is OK */
73 c
= x
>> 3; /* XXX - was >> 4 */
84 return (mt_hash ((unsigned char *)mem
) & (REG_TABLE_SIZE
-1));
88 #define which_bucket(mem) (mt_hash ((unsigned char *)(mem)) & (REG_TABLE_SIZE-1));
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)
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)
98 find_entry (mem
, flags
)
103 register mr_table_t
*tp
;
106 if (mem_overflow
.mem
== mem
)
107 return (&mem_overflow
);
109 /* If we want to insert an allocation entry just use the next slot */
110 if (flags
& FIND_ALLOC
)
112 table_bucket_index
= next_bucket();
114 tp
= mem_table
+ table_bucket_index
;
115 memset(tp
, 0, sizeof (mr_table_t
)); /* overwrite next existing entry */
119 tp
= endp
= mem_table
+ table_bucket_index
;
121 /* search for last allocation corresponding to MEM, return entry pointer */
127 tp
= prev_entry (tp
);
129 /* if we went all the way around and didn't find it, return NULL */
131 return ((mr_table_t
*)NULL
);
134 return (mr_table_t
*)NULL
;
141 return (find_entry (mem
, FIND_EXIST
));
145 mregister_describe_mem (mem
, fp
)
151 entry
= find_entry (mem
, FIND_EXIST
);
154 fprintf (fp
, "malloc: %p: %s: last %s from %s:%d\n",
156 (entry
->flags
& MT_ALLOC
) ? "allocated" : "free",
157 (entry
->flags
& MT_ALLOC
) ? "allocated" : "freed",
158 entry
->file
? entry
->file
: "unknown",
163 mregister_alloc (tag
, mem
, size
, file
, line
)
174 /* Block all signals in case we are executed from a signal handler. */
177 if (interrupt_immediately
|| running_trap
|| signal_is_trapped (SIGINT
) || signal_is_trapped (SIGCHLD
))
180 _malloc_block_signals (&set
, &oset
);
184 mlocation_register_alloc (file
, line
);
186 tentry
= find_entry (mem
, FIND_ALLOC
);
190 /* oops. table is full. punt. */
191 fprintf (stderr
, _("register_alloc: alloc table is full with FIND_ALLOC?\n"));
193 _malloc_unblock_signals (&set
, &oset
);
197 if (tentry
->flags
& MT_ALLOC
)
199 /* oops. bad bookkeeping. ignore for now */
200 fprintf (stderr
, _("register_alloc: %p already in table as allocated?\n"), mem
);
206 tentry
->flags
= MT_ALLOC
;
211 if (tentry
!= &mem_overflow
)
215 _malloc_unblock_signals (&set
, &oset
);
219 mregister_free (mem
, size
, file
, line
)
229 /* Block all signals in case we are executed from a signal handler. */
232 if (interrupt_immediately
|| running_trap
|| signal_is_trapped (SIGINT
) || signal_is_trapped (SIGCHLD
))
235 _malloc_block_signals (&set
, &oset
);
239 tentry
= find_entry (mem
, FIND_EXIST
);
242 /* oops. not found. */
244 fprintf (stderr
, "register_free: %p not in allocation table?\n", mem
);
247 _malloc_unblock_signals (&set
, &oset
);
250 if (tentry
->flags
& MT_FREE
)
252 /* oops. bad bookkeeping. ignore for now */
253 fprintf (stderr
, _("register_free: %p already in table as free?\n"), mem
);
256 tentry
->flags
= MT_FREE
;
257 tentry
->func
= "free";
262 if (tentry
!= &mem_overflow
)
266 _malloc_unblock_signals (&set
, &oset
);
269 /* If we ever add more flags, this will require changes. */
276 else if (x
& MT_ALLOC
)
279 return "undetermined?";
283 _register_dump_table(fp
)
289 for (i
= 0; i
< REG_TABLE_SIZE
; i
++)
291 entry
= mem_table
[i
];
293 fprintf (fp
, "%s[%d] %p:%zu:%s:%s:%s:%d:%d:%d\n",
294 (i
== table_bucket_index
) ? "*" : "",
296 entry
.mem
, entry
.size
,
297 _entry_flags(entry
.flags
),
298 entry
.func
? entry
.func
: "unknown",
299 entry
.file
? entry
.file
: "unknown",
301 entry
.nalloc
, entry
.nfree
);
306 mregister_dump_table()
308 _register_dump_table (stderr
);
312 mregister_table_init ()
314 memset (mem_table
, 0, sizeof(mr_table_t
) * REG_TABLE_SIZE
);
315 memset (&mem_overflow
, 0, sizeof (mr_table_t
));
322 find_location_entry (file
, line
)
326 register ma_table_t
*tp
, *endp
;
328 endp
= mlocation_table
+ location_table_count
;
329 for (tp
= mlocation_table
; tp
<= endp
; tp
++)
331 if (tp
->line
== line
&& STREQ (file
, tp
->file
))
334 return (ma_table_t
*)NULL
;
338 mlocation_register_alloc (file
, line
)
347 mlocation_table
[0].nalloc
++;
351 nfile
= strrchr (file
, '/');
357 lentry
= find_location_entry (nfile
, line
);
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
;
367 if (location_table_count
< REG_TABLE_SIZE
)
368 location_table_count
++; /* clamp at REG_TABLE_SIZE for now */
375 _location_dump_table (fp
)
378 register ma_table_t
*tp
, *endp
;
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,
388 mlocation_dump_table ()
390 _location_dump_table (stderr
);
393 #define LOCROOT "/var/tmp/maltrace/locations."
396 mlocation_write_table ()
399 char defname
[sizeof (LOCROOT
) + 64];
401 fp
= _imalloc_fopen ((char *)NULL
, (char *)NULL
, LOCROOT
, defname
, sizeof (defname
));
403 return; /* XXX - no error message yet */
404 _location_dump_table (fp
);
409 mlocation_table_init ()
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;
418 #endif /* MALLOC_REGISTER */
421 malloc_set_register(n
)
426 old
= malloc_register
;