Home | History | Annotate | Line # | Download | only in raidframe
rf_debugMem.c revision 1.5
      1 /*	$NetBSD: rf_debugMem.c,v 1.5 1999/09/04 16:26:30 oster Exp $	*/
      2 /*
      3  * Copyright (c) 1995 Carnegie-Mellon University.
      4  * All rights reserved.
      5  *
      6  * Author: Daniel Stodolsky, Mark Holland, Jim Zelenka
      7  *
      8  * Permission to use, copy, modify and distribute this software and
      9  * its documentation is hereby granted, provided that both the copyright
     10  * notice and this permission notice appear in all copies of the
     11  * software, derivative works or modified versions, and any portions
     12  * thereof, and that both notices appear in supporting documentation.
     13  *
     14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     16  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17  *
     18  * Carnegie Mellon requests users of this software to return to
     19  *
     20  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21  *  School of Computer Science
     22  *  Carnegie Mellon University
     23  *  Pittsburgh PA 15213-3890
     24  *
     25  * any improvements or extensions that they make and grant Carnegie the
     26  * rights to redistribute these changes.
     27  */
     28 
     29 /* debugMem.c:  memory usage debugging stuff.
     30  * Malloc, Calloc, and Free are #defined everywhere
     31  * to do_malloc, do_calloc, and do_free.
     32  *
     33  * if RF_UTILITY is nonzero, it means were compiling one of the
     34  * raidframe utility programs, such as rfctrl or smd.  In this
     35  * case, we eliminate all references to the threads package
     36  * and to the allocation list stuff.
     37  */
     38 
     39 #include "rf_types.h"
     40 
     41 #include "rf_threadstuff.h"
     42 #include "rf_threadid.h"
     43 #include "rf_options.h"
     44 #include "rf_debugMem.h"
     45 #include "rf_general.h"
     46 
     47 static long tot_mem_in_use = 0, max_mem = 0;
     48 
     49 /* Hash table of information about memory allocations */
     50 #define RF_MH_TABLESIZE 1000
     51 
     52 struct mh_struct {
     53 	void   *address;
     54 	int     size;
     55 	int     line;
     56 	char   *filen;
     57 	char    allocated;
     58 	struct mh_struct *next;
     59 };
     60 static struct mh_struct *mh_table[RF_MH_TABLESIZE];
     61 RF_DECLARE_MUTEX(rf_debug_mem_mutex)
     62 	static int mh_table_initialized = 0;
     63 
     64 	static void memory_hash_insert(void *addr, int size, int line, char *filen);
     65 	static int memory_hash_remove(void *addr, int sz);
     66 
     67 #ifndef _KERNEL			/* no redzones or "real_" routines in the
     68 				 * kernel */
     69 
     70 	static void rf_redzone_free_failed(void *ptr, int size, int line, char *file);
     71 
     72 	void   *rf_real_redzone_malloc(_size_)
     73 	int     _size_;
     74 {
     75 	char   *p;
     76 
     77 	rf_validate_mh_table();
     78 	p = malloc((_size_) + 16);
     79 	if (p == NULL)
     80 		return (p);
     81 	RF_ASSERT(p);
     82 	*((long *) p) = (_size_);
     83 	((char *) p)[(_size_) + 8] = '!';
     84 	((char *) p)[(_size_) + 15] = '!';
     85 	p += 8;
     86 	return (p);
     87 }
     88 
     89 void   *
     90 rf_real_redzone_calloc(_n_, _size_)
     91 	int     _n_, _size_;
     92 {
     93 	char   *p;
     94 	int     _sz_;
     95 
     96 	rf_validate_mh_table();
     97 	_sz_ = (_n_) * (_size_);
     98 	p = malloc((_sz_) + 16);
     99 	if (p == NULL)
    100 		return (p);
    101 	bzero(p, (_sz_) + 16);
    102 	*((long *) p) = (_sz_);
    103 	((char *) p)[(_sz_) + 8] = '!';
    104 	((char *) p)[(_sz_) + 15] = '!';
    105 	p += 8;
    106 	return (p);
    107 }
    108 
    109 void
    110 rf_real_redzone_free(p, line, filen)
    111 	char   *p;
    112 	int     line;
    113 	char   *filen;
    114 {
    115 	unsigned long _size_;
    116 
    117 	rf_validate_mh_table();
    118 	p -= 8;
    119 	_size_ = *((long *) p);
    120 	if ((((char *) p)[(_size_) + 8] != '!') || (((char *) p)[(_size_) + 15] != '!'))
    121 		rf_redzone_free_failed(p, (_size_), line, filen);
    122 	free(p);
    123 }
    124 
    125 unsigned long rf_mem_alloc = 0;
    126 
    127 char   *
    128 rf_real_Malloc(size, line, file)
    129 	int     size;
    130 	int     line;
    131 	char   *file;
    132 {
    133 	void   *pp;
    134 	char   *p;
    135 	int     tid;
    136 
    137 	RF_LOCK_MUTEX(rf_debug_mem_mutex);
    138 	rf_redzone_malloc(pp, size);
    139 	p = pp;
    140 	if (p == NULL) {
    141 		RF_ERRORMSG3("Unable to malloc %d bytes at line %d file %s\n", size,
    142 		    line, file);
    143 	}
    144 	if (rf_memAmtDebug) {
    145 		rf_mem_alloc += size;
    146 		printf("%lu    size %d %s:%d\n", rf_mem_alloc, size, file, line);
    147 	}
    148 	if (rf_memDebug > 1) {
    149 		rf_get_threadid(tid);
    150 		printf("[%d] malloc 0x%lx - 0x%lx (%d) %s %d\n", tid, p, p + size, size,
    151 		    file, line);
    152 	}
    153 	if (rf_memDebug)
    154 		rf_record_malloc(p, size, line, file);
    155 	RF_UNLOCK_MUTEX(rf_debug_mem_mutex);
    156 	return (p);
    157 }
    158 
    159 char   *
    160 rf_real_MallocAndAdd(size, alist, line, file)
    161 	int     size;
    162 	RF_AllocListElem_t *alist;
    163 	int     line;
    164 	char   *file;
    165 {
    166 	void   *pp;
    167 	char   *p;
    168 	int     tid;
    169 
    170 	RF_LOCK_MUTEX(rf_debug_mem_mutex);
    171 	rf_redzone_malloc(pp, size);
    172 	p = pp;
    173 	if (p == NULL) {
    174 		RF_ERRORMSG3("Unable to malloc %d bytes at line %d file %s\n", size,
    175 		    line, file);
    176 	}
    177 	if (rf_memAmtDebug) {
    178 		rf_mem_alloc += size;
    179 		printf("%lu    size %d %s:%d\n", rf_mem_alloc, size, file, line);
    180 	}
    181 	if (rf_memDebug > 1) {
    182 		rf_get_threadid(tid);
    183 		printf("[%d] malloc+add 0x%lx - 0x%lx (%d) %s %d\n", tid, p, p + size,
    184 		    size, file, line);
    185 	}
    186 	if (alist) {
    187 		rf_real_AddToAllocList(alist, pp, size, 0);
    188 	}
    189 	if (rf_memDebug)
    190 		rf_record_malloc(p, size, line, file);
    191 	RF_UNLOCK_MUTEX(rf_debug_mem_mutex);
    192 	return (p);
    193 }
    194 
    195 char   *
    196 rf_real_Calloc(nel, elsz, line, file)
    197 	int     nel;
    198 	int     elsz;
    199 	int     line;
    200 	char   *file;
    201 {
    202 	int     tid, size;
    203 	void   *pp;
    204 	char   *p;
    205 
    206 	size = nel * elsz;
    207 	RF_LOCK_MUTEX(rf_debug_mem_mutex);
    208 	rf_redzone_calloc(pp, nel, elsz);
    209 	p = pp;
    210 	if (p == NULL) {
    211 		RF_ERRORMSG4("Unable to calloc %d objects of size %d at line %d file %s\n",
    212 		    nel, elsz, line, file);
    213 		return (NULL);
    214 	}
    215 	if (rf_memAmtDebug) {
    216 		rf_mem_alloc += size;
    217 		printf("%lu    size %d %s:%d\n", rf_mem_alloc, size, file, line);
    218 	}
    219 	if (rf_memDebug > 1) {
    220 		rf_get_threadid(tid);
    221 		printf("[%d] calloc 0x%lx - 0x%lx (%d,%d) %s %d\n", tid, p, p + size, nel,
    222 		    elsz, file, line);
    223 	}
    224 	if (rf_memDebug) {
    225 		rf_record_malloc(p, size, line, file);
    226 	}
    227 	RF_UNLOCK_MUTEX(rf_debug_mem_mutex);
    228 	return (p);
    229 }
    230 
    231 char   *
    232 rf_real_CallocAndAdd(nel, elsz, alist, line, file)
    233 	int     nel;
    234 	int     elsz;
    235 	RF_AllocListElem_t *alist;
    236 	int     line;
    237 	char   *file;
    238 {
    239 	int     tid, size;
    240 	void   *pp;
    241 	char   *p;
    242 
    243 	size = nel * elsz;
    244 	RF_LOCK_MUTEX(rf_debug_mem_mutex);
    245 	rf_redzone_calloc(pp, nel, elsz);
    246 	p = pp;
    247 	if (p == NULL) {
    248 		RF_ERRORMSG4("Unable to calloc %d objs of size %d at line %d file %s\n",
    249 		    nel, elsz, line, file);
    250 		return (NULL);
    251 	}
    252 	if (rf_memAmtDebug) {
    253 		rf_mem_alloc += size;
    254 		printf("%lu    size %d %s:%d\n", rf_mem_alloc, size, file, line);
    255 	}
    256 	if (rf_memDebug > 1) {
    257 		rf_get_threadid(tid);
    258 		printf("[%d] calloc+add 0x%lx - 0x%lx (%d,%d) %s %d\n", tid, p,
    259 		    p + size, nel, elsz, file, line);
    260 	}
    261 	if (alist) {
    262 		rf_real_AddToAllocList(alist, pp, size, 0);
    263 	}
    264 	if (rf_memDebug)
    265 		rf_record_malloc(p, size, line, file);
    266 	RF_UNLOCK_MUTEX(rf_debug_mem_mutex);
    267 	return (p);
    268 }
    269 
    270 void
    271 rf_real_Free(p, sz, line, file)
    272 	void   *p;
    273 	int     sz;
    274 	int     line;
    275 	char   *file;
    276 {
    277 	int     tid;
    278 
    279 	if (rf_memDebug > 1) {
    280 		rf_get_threadid(tid);
    281 		printf("[%d] free 0x%lx - 0x%lx (%d) %s %d\n", tid, p, ((char *) p) + sz, sz,
    282 		    file, line);
    283 	}
    284 	RF_LOCK_MUTEX(rf_debug_mem_mutex);
    285 	if (rf_memAmtDebug) {
    286 		rf_mem_alloc -= sz;
    287 		printf("%lu  - size %d %s:%d\n", rf_mem_alloc, sz, file, line);
    288 	}
    289 	if (rf_memDebug) {
    290 		rf_unrecord_malloc(p, sz);
    291 	}
    292 	rf_redzone_free(p);
    293 	RF_UNLOCK_MUTEX(rf_debug_mem_mutex);
    294 }
    295 
    296 void
    297 rf_validate_mh_table()
    298 {
    299 	int     i, size;
    300 	struct mh_struct *p;
    301 	char   *cp;
    302 
    303 	return;
    304 	for (i = 0; i < RF_MH_TABLESIZE; i++) {
    305 		for (p = mh_table[i]; p; p = p->next)
    306 			if (p->allocated) {
    307 				cp = ((char *) p->address) - 8;
    308 				size = *((long *) cp);
    309 				if ((((char *) cp)[(size) + 8] != '!') || (((char *) cp)[(size) + 15] != '!')) {
    310 					rf_redzone_free_failed(cp, (size), __LINE__, __FILE__);
    311 				}
    312 			}
    313 	}
    314 }
    315 
    316 static void
    317 rf_redzone_free_failed(ptr, size, line, file)
    318 	void   *ptr;
    319 	int     size;
    320 	int     line;
    321 	char   *file;
    322 {
    323 	RF_ERRORMSG4("Free of 0x%lx (recorded size %d) at %d of %s detected redzone overrun\n", ptr, size, line, file);
    324 	RF_ASSERT(0);
    325 }
    326 #endif				/* !_KERNEL */
    327 
    328 void
    329 rf_record_malloc(p, size, line, filen)
    330 	void   *p;
    331 	int     size, line;
    332 	char   *filen;
    333 {
    334 	RF_ASSERT(size != 0);
    335 
    336 	/* RF_LOCK_MUTEX(rf_debug_mem_mutex); */
    337 	memory_hash_insert(p, size, line, filen);
    338 	tot_mem_in_use += size;
    339 	/* RF_UNLOCK_MUTEX(rf_debug_mem_mutex); */
    340 	if ((long) p == rf_memDebugAddress) {
    341 		printf("Allocate: debug address allocated from line %d file %s\n", line, filen);
    342 	}
    343 }
    344 
    345 void
    346 rf_unrecord_malloc(p, sz)
    347 	void   *p;
    348 	int     sz;
    349 {
    350 	int     size;
    351 
    352 	/* RF_LOCK_MUTEX(rf_debug_mem_mutex); */
    353 	size = memory_hash_remove(p, sz);
    354 	tot_mem_in_use -= size;
    355 	/* RF_UNLOCK_MUTEX(rf_debug_mem_mutex); */
    356 	if ((long) p == rf_memDebugAddress) {
    357 		printf("Free: Found debug address\n");	/* this is really only a
    358 							 * flag line for gdb */
    359 	}
    360 }
    361 
    362 void
    363 rf_print_unfreed()
    364 {
    365 	int     i, foundone = 0;
    366 	struct mh_struct *p;
    367 
    368 	for (i = 0; i < RF_MH_TABLESIZE; i++) {
    369 		for (p = mh_table[i]; p; p = p->next)
    370 			if (p->allocated) {
    371 				if (!foundone)
    372 					printf("\n\nThere are unfreed memory locations at program shutdown:\n");
    373 				foundone = 1;
    374 				printf("Addr 0x%lx Size %d line %d file %s\n",
    375 				    (long) p->address, p->size, p->line, p->filen);
    376 			}
    377 	}
    378 	if (tot_mem_in_use) {
    379 		printf("%ld total bytes in use\n", tot_mem_in_use);
    380 	}
    381 }
    382 
    383 int
    384 rf_ConfigureDebugMem(listp)
    385 	RF_ShutdownList_t **listp;
    386 {
    387 	int     i, rc;
    388 
    389 	rc = rf_create_managed_mutex(listp, &rf_debug_mem_mutex);
    390 	if (rc) {
    391 		RF_ERRORMSG3("Unable to init mutex file %s line %d rc=%d\n", __FILE__,
    392 		    __LINE__, rc);
    393 		return (rc);
    394 	}
    395 	if (rf_memDebug) {
    396 		for (i = 0; i < RF_MH_TABLESIZE; i++)
    397 			mh_table[i] = NULL;
    398 		mh_table_initialized = 1;
    399 	}
    400 	return (0);
    401 }
    402 #define HASHADDR(_a_)      ( (((unsigned long) _a_)>>3) % RF_MH_TABLESIZE )
    403 
    404 static void
    405 memory_hash_insert(addr, size, line, filen)
    406 	void   *addr;
    407 	int     size, line;
    408 	char   *filen;
    409 {
    410 	unsigned long bucket = HASHADDR(addr);
    411 	struct mh_struct *p;
    412 
    413 	RF_ASSERT(mh_table_initialized);
    414 
    415 	/* search for this address in the hash table */
    416 	for (p = mh_table[bucket]; p && (p->address != addr); p = p->next);
    417 	if (!p) {
    418 		RF_Malloc(p, sizeof(struct mh_struct), (struct mh_struct *));
    419 		RF_ASSERT(p);
    420 		p->next = mh_table[bucket];
    421 		mh_table[bucket] = p;
    422 		p->address = addr;
    423 		p->allocated = 0;
    424 	}
    425 	if (p->allocated) {
    426 		printf("ERROR:  reallocated address 0x%lx from line %d, file %s without intervening free\n", (long) addr, line, filen);
    427 		printf("        last allocated from line %d file %s\n", p->line, p->filen);
    428 		RF_ASSERT(0);
    429 	}
    430 	p->size = size;
    431 	p->line = line;
    432 	p->filen = filen;
    433 	p->allocated = 1;
    434 }
    435 
    436 static int
    437 memory_hash_remove(addr, sz)
    438 	void   *addr;
    439 	int     sz;
    440 {
    441 	unsigned long bucket = HASHADDR(addr);
    442 	struct mh_struct *p;
    443 
    444 	RF_ASSERT(mh_table_initialized);
    445 	for (p = mh_table[bucket]; p && (p->address != addr); p = p->next);
    446 	if (!p) {
    447 		printf("ERROR:  freeing never-allocated address 0x%lx\n", (long) addr);
    448 		RF_PANIC();
    449 	}
    450 	if (!p->allocated) {
    451 		printf("ERROR:  freeing unallocated address 0x%lx.  Last allocation line %d file %s\n", (long) addr, p->line, p->filen);
    452 		RF_PANIC();
    453 	}
    454 	if (sz > 0 && p->size != sz) {	/* you can suppress this error by
    455 					 * using a negative value as the size
    456 					 * to free */
    457 		printf("ERROR:  incorrect size at free for address 0x%lx: is %d should be %d.  Alloc at line %d of file %s\n", (unsigned long) addr, sz, p->size, p->line, p->filen);
    458 		RF_PANIC();
    459 	}
    460 	p->allocated = 0;
    461 	return (p->size);
    462 }
    463 
    464 void
    465 rf_ReportMaxMem()
    466 {
    467 	printf("Max memory used:  %d bytes\n", (int) max_mem);
    468 }
    469