| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | /* table.c - bookkeeping functions for allocated memory */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Copyright (C) 2001 Free Software Foundation, Inc.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    This file is part of GNU Bash, the Bourne Again SHell. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Bash is free software; you can redistribute it and/or modify it under | 
					
						
							|  |  |  |    the terms of the GNU General Public License as published by the Free | 
					
						
							|  |  |  |    Software Foundation; either version 2, or (at your option) any later | 
					
						
							|  |  |  |    version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Bash is distributed in the hope that it will be useful, but WITHOUT ANY | 
					
						
							|  |  |  |    WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
					
						
							|  |  |  |    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
					
						
							|  |  |  |    for more details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    You should have received a copy of the GNU General Public License along | 
					
						
							|  |  |  |    with Bash; see the file COPYING.  If not, write to the Free Software | 
					
						
							|  |  |  |    Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ | 
					
						
							|  |  |  | #ifdef HAVE_CONFIG_H
 | 
					
						
							|  |  |  | #  include <config.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "imalloc.h"
 | 
					
						
							|  |  |  | #include "table.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern int malloc_register; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef MALLOC_REGISTER
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define FIND_ALLOC	0x01	/* allocate new entry or find existing */
 | 
					
						
							|  |  |  | #define FIND_EXIST	0x02	/* find existing entry */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int table_count = 0; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | static int table_allocated = 0; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | static mr_table_t mem_table[REG_TABLE_SIZE]; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | static mr_table_t mem_overflow; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * NOTE: taken from dmalloc (http://dmalloc.com) and modified.
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static unsigned int | 
					
						
							|  |  |  | mt_hash (key) | 
					
						
							|  |  |  |      const PTR_T key; | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   unsigned int a, b, c; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   unsigned long x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* set up the internal state */ | 
					
						
							|  |  |  |   a = 0x9e3779b9;	/* the golden ratio; an arbitrary value */ | 
					
						
							|  |  |  |   x = (unsigned long)key;		/* truncation is OK */ | 
					
						
							|  |  |  |   b = x >> 8; | 
					
						
							|  |  |  |   c = x >> 3;				/* XXX - was >> 4 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   HASH_MIX(a, b, c); | 
					
						
							|  |  |  |   return c; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if 0
 | 
					
						
							|  |  |  | static unsigned int | 
					
						
							|  |  |  | which_bucket (mem) | 
					
						
							|  |  |  |      PTR_T mem; | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   return (mt_hash ((unsigned char *)mem) & (REG_TABLE_SIZE-1)); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | #define which_bucket(mem) (mt_hash ((unsigned char *)(mem)) & (REG_TABLE_SIZE-1));
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static mr_table_t * | 
					
						
							|  |  |  | find_entry (mem, flags) | 
					
						
							|  |  |  |      PTR_T mem; | 
					
						
							|  |  |  |      int flags; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   unsigned int bucket; | 
					
						
							|  |  |  |   register mr_table_t *tp; | 
					
						
							|  |  |  |   mr_table_t *endp, *lastp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   if (mem_overflow.mem == mem) | 
					
						
							|  |  |  |     return (&mem_overflow); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   bucket = which_bucket (mem);	/* get initial hash */ | 
					
						
							|  |  |  |   tp = endp = mem_table + bucket; | 
					
						
							|  |  |  |   lastp = mem_table + REG_TABLE_SIZE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (tp->mem == mem) | 
					
						
							|  |  |  | 	return (tp); | 
					
						
							|  |  |  |       if (tp->mem == 0 && (flags & FIND_ALLOC)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  table_count++; | 
					
						
							|  |  |  | 	  return (tp); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       tp++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (tp == lastp)		/* wrap around */ | 
					
						
							|  |  |  |         tp = mem_table; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (tp == endp && (flags & FIND_EXIST)) | 
					
						
							|  |  |  |         return ((mr_table_t *)NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (tp == endp && (flags & FIND_ALLOC)) | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* oops.  table is full.  replace an existing free entry. */ | 
					
						
							|  |  |  |   do | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |       /* If there are no free entries, punt right away without searching. */ | 
					
						
							|  |  |  |       if (table_allocated == REG_TABLE_SIZE) | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       if (tp->flags & MT_FREE) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  memset(tp, 0, sizeof (mr_table_t)); | 
					
						
							|  |  |  | 	  return (tp); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       tp++; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (tp == lastp) | 
					
						
							|  |  |  | 	tp = mem_table; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   while (tp != endp); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   /* wow. entirely full.  return mem_overflow dummy entry. */ | 
					
						
							|  |  |  |   tp = &mem_overflow; | 
					
						
							|  |  |  |   memset (tp, 0, sizeof (mr_table_t)); | 
					
						
							|  |  |  |   return tp; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | mr_table_t * | 
					
						
							|  |  |  | mr_table_entry (mem) | 
					
						
							|  |  |  |      PTR_T mem; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return (find_entry (mem, FIND_EXIST)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | mregister_describe_mem (mem, fp) | 
					
						
							|  |  |  |      PTR_T mem; | 
					
						
							|  |  |  |      FILE *fp; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   mr_table_t *entry; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   entry = find_entry (mem, FIND_EXIST); | 
					
						
							|  |  |  |   if (entry == 0) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   fprintf (fp, "malloc: %p: %s: last %s from %s:%d\n", | 
					
						
							|  |  |  |   		mem, | 
					
						
							|  |  |  | 		(entry->flags & MT_ALLOC) ? "allocated" : "free", | 
					
						
							|  |  |  | 		(entry->flags & MT_ALLOC) ? "allocated" : "freed", | 
					
						
							|  |  |  | 		entry->file ? entry->file : "unknown", | 
					
						
							|  |  |  | 		entry->line); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | mregister_alloc (tag, mem, size, file, line) | 
					
						
							|  |  |  |      const char *tag; | 
					
						
							|  |  |  |      PTR_T mem; | 
					
						
							|  |  |  |      size_t size; | 
					
						
							|  |  |  |      const char *file; | 
					
						
							|  |  |  |      int line; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   mr_table_t *tentry; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   tentry = find_entry (mem, FIND_ALLOC); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (tentry == 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       /* oops.  table is full.  punt. */ | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |       fprintf (stderr, "register_alloc: alloc table is full with FIND_ALLOC?\n"); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   if (tentry->flags & MT_ALLOC) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       /* oops.  bad bookkeeping. ignore for now */ | 
					
						
							|  |  |  |       fprintf (stderr, "register_alloc: %p already in table as allocated?\n", mem); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   tentry->mem = mem; | 
					
						
							|  |  |  |   tentry->size = size; | 
					
						
							|  |  |  |   tentry->func = tag; | 
					
						
							|  |  |  |   tentry->flags = MT_ALLOC; | 
					
						
							|  |  |  |   tentry->file = file; | 
					
						
							|  |  |  |   tentry->line = line; | 
					
						
							|  |  |  |   tentry->nalloc++; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (tentry != &mem_overflow) | 
					
						
							|  |  |  |     table_allocated++; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | mregister_free (mem, size, file, line) | 
					
						
							|  |  |  |      PTR_T mem; | 
					
						
							|  |  |  |      int size; | 
					
						
							|  |  |  |      const char *file; | 
					
						
							|  |  |  |      int line; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   mr_table_t *tentry; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   tentry = find_entry (mem, FIND_EXIST); | 
					
						
							|  |  |  |   if (tentry == 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       /* oops.  not found. */ | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       fprintf (stderr, "register_free: %p not in allocation table?\n", mem); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   if (tentry->flags & MT_FREE) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       /* oops.  bad bookkeeping. ignore for now */ | 
					
						
							|  |  |  |       fprintf (stderr, "register_free: %p already in table as free?\n", mem); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     	 | 
					
						
							|  |  |  |   tentry->flags = MT_FREE; | 
					
						
							|  |  |  |   tentry->func = "free"; | 
					
						
							|  |  |  |   tentry->file = file; | 
					
						
							|  |  |  |   tentry->line = line; | 
					
						
							|  |  |  |   tentry->nfree++; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (tentry != &mem_overflow) | 
					
						
							|  |  |  |     table_allocated--; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* If we ever add more flags, this will require changes. */ | 
					
						
							|  |  |  | static char * | 
					
						
							|  |  |  | _entry_flags(x) | 
					
						
							|  |  |  |      int x; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (x & MT_FREE) | 
					
						
							|  |  |  |     return "free"; | 
					
						
							|  |  |  |   else if (x & MT_ALLOC) | 
					
						
							|  |  |  |     return "allocated"; | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return "undetermined?"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | _register_dump_table(fp) | 
					
						
							|  |  |  |      FILE *fp; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   register int i; | 
					
						
							|  |  |  |   mr_table_t entry; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 0; i < REG_TABLE_SIZE; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       entry = mem_table[i]; | 
					
						
							|  |  |  |       if (entry.mem) | 
					
						
							|  |  |  | 	fprintf (fp, "[%d] %p:%d:%s:%s:%s:%d:%d:%d\n", i, | 
					
						
							|  |  |  | 						entry.mem, entry.size, | 
					
						
							|  |  |  | 						_entry_flags(entry.flags), | 
					
						
							|  |  |  | 						entry.func ? entry.func : "unknown", | 
					
						
							|  |  |  | 						entry.file ? entry.file : "unknown", | 
					
						
							|  |  |  | 						entry.line, | 
					
						
							|  |  |  | 						entry.nalloc, entry.nfree); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | mregister_dump_table() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   _register_dump_table (stderr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | mregister_table_init () | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   memset (mem_table, 0, sizeof(mr_table_t) * REG_TABLE_SIZE); | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   memset (&mem_overflow, 0, sizeof (mr_table_t)); | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   table_count = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* MALLOC_REGISTER */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | malloc_set_register(n) | 
					
						
							|  |  |  |      int n; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int old; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   old = malloc_register; | 
					
						
							|  |  |  |   malloc_register = n; | 
					
						
							|  |  |  |   return old; | 
					
						
							|  |  |  | } |