Home | History | Annotate | Line # | Download | only in raidframe
rf_debugMem.c revision 1.3
      1 /*	$NetBSD: rf_debugMem.c,v 1.3 1999/02/05 00:06:08 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 #include "rf_sys.h"
     41 
     42 #if RF_UTILITY == 0
     43 #include "rf_threadstuff.h"
     44 #include "rf_threadid.h"
     45 #include "rf_options.h"
     46 #else				/* RF_UTILITY == 0 */
     47 #include "rf_utility.h"
     48 #endif				/* RF_UTILITY == 0 */
     49 
     50 #include "rf_debugMem.h"
     51 #include "rf_general.h"
     52 
     53 static long tot_mem_in_use = 0, max_mem = 0;
     54 
     55 /* Hash table of information about memory allocations */
     56 #define RF_MH_TABLESIZE 1000
     57 
     58 struct mh_struct {
     59 	void   *address;
     60 	int     size;
     61 	int     line;
     62 	char   *filen;
     63 	char    allocated;
     64 	struct mh_struct *next;
     65 };
     66 static struct mh_struct *mh_table[RF_MH_TABLESIZE];
     67 RF_DECLARE_MUTEX(rf_debug_mem_mutex)
     68 	static int mh_table_initialized = 0;
     69 
     70 	static void memory_hash_insert(void *addr, int size, int line, char *filen);
     71 	static int memory_hash_remove(void *addr, int sz);
     72 
     73 #ifndef _KERNEL			/* no redzones or "real_" routines in the
     74 				 * kernel */
     75 
     76 	static void rf_redzone_free_failed(void *ptr, int size, int line, char *file);
     77 
     78 	void   *rf_real_redzone_malloc(_size_)
     79 	int     _size_;
     80 {
     81 	char   *p;
     82 
     83 	rf_validate_mh_table();
     84 	p = malloc((_size_) + 16);
     85 	if (p == NULL)
     86 		return (p);
     87 	RF_ASSERT(p);
     88 	*((long *) p) = (_size_);
     89 	((char *) p)[(_size_) + 8] = '!';
     90 	((char *) p)[(_size_) + 15] = '!';
     91 	p += 8;
     92 	return (p);
     93 }
     94 
     95 void   *
     96 rf_real_redzone_calloc(_n_, _size_)
     97 	int     _n_, _size_;
     98 {
     99 	char   *p;
    100 	int     _sz_;
    101 
    102 	rf_validate_mh_table();
    103 	_sz_ = (_n_) * (_size_);
    104 	p = malloc((_sz_) + 16);
    105 	if (p == NULL)
    106 		return (p);
    107 	bzero(p, (_sz_) + 16);
    108 	*((long *) p) = (_sz_);
    109 	((char *) p)[(_sz_) + 8] = '!';
    110 	((char *) p)[(_sz_) + 15] = '!';
    111 	p += 8;
    112 	return (p);
    113 }
    114 
    115 void
    116 rf_real_redzone_free(p, line, filen)
    117 	char   *p;
    118 	int     line;
    119 	char   *filen;
    120 {
    121 	unsigned long _size_;
    122 
    123 	rf_validate_mh_table();
    124 	p -= 8;
    125 	_size_ = *((long *) p);
    126 	if ((((char *) p)[(_size_) + 8] != '!') || (((char *) p)[(_size_) + 15] != '!'))
    127 		rf_redzone_free_failed(p, (_size_), line, filen);
    128 	free(p);
    129 }
    130 
    131 unsigned long rf_mem_alloc = 0;
    132 
    133 char   *
    134 rf_real_Malloc(size, line, file)
    135 	int     size;
    136 	int     line;
    137 	char   *file;
    138 {
    139 	void   *pp;
    140 	char   *p;
    141 	int     tid;
    142 
    143 	RF_LOCK_MUTEX(rf_debug_mem_mutex);
    144 	rf_redzone_malloc(pp, size);
    145 	p = pp;
    146 	if (p == NULL) {
    147 		RF_ERRORMSG3("Unable to malloc %d bytes at line %d file %s\n", size,
    148 		    line, file);
    149 	}
    150 	if (rf_memAmtDebug) {
    151 		rf_mem_alloc += size;
    152 		printf("%lu    size %d %s:%d\n", rf_mem_alloc, size, file, line);
    153 	}
    154 #if RF_UTILITY == 0
    155 	if (rf_memDebug > 1) {
    156 		rf_get_threadid(tid);
    157 		printf("[%d] malloc 0x%lx - 0x%lx (%d) %s %d\n", tid, p, p + size, size,
    158 		    file, line);
    159 	}
    160 #endif				/* RF_UTILITY == 0 */
    161 	if (rf_memDebug)
    162 		rf_record_malloc(p, size, line, file);
    163 	RF_UNLOCK_MUTEX(rf_debug_mem_mutex);
    164 	return (p);
    165 }
    166 #if RF_UTILITY == 0
    167 char   *
    168 rf_real_MallocAndAdd(size, alist, line, file)
    169 	int     size;
    170 	RF_AllocListElem_t *alist;
    171 	int     line;
    172 	char   *file;
    173 {
    174 	void   *pp;
    175 	char   *p;
    176 	int     tid;
    177 
    178 	RF_LOCK_MUTEX(rf_debug_mem_mutex);
    179 	rf_redzone_malloc(pp, size);
    180 	p = pp;
    181 	if (p == NULL) {
    182 		RF_ERRORMSG3("Unable to malloc %d bytes at line %d file %s\n", size,
    183 		    line, file);
    184 	}
    185 	if (rf_memAmtDebug) {
    186 		rf_mem_alloc += size;
    187 		printf("%lu    size %d %s:%d\n", rf_mem_alloc, size, file, line);
    188 	}
    189 	if (rf_memDebug > 1) {
    190 		rf_get_threadid(tid);
    191 		printf("[%d] malloc+add 0x%lx - 0x%lx (%d) %s %d\n", tid, p, p + size,
    192 		    size, file, line);
    193 	}
    194 	if (alist) {
    195 		rf_real_AddToAllocList(alist, pp, size, 0);
    196 	}
    197 	if (rf_memDebug)
    198 		rf_record_malloc(p, size, line, file);
    199 	RF_UNLOCK_MUTEX(rf_debug_mem_mutex);
    200 	return (p);
    201 }
    202 #endif				/* RF_UTILITY == 0 */
    203 
    204 char   *
    205 rf_real_Calloc(nel, elsz, line, file)
    206 	int     nel;
    207 	int     elsz;
    208 	int     line;
    209 	char   *file;
    210 {
    211 	int     tid, size;
    212 	void   *pp;
    213 	char   *p;
    214 
    215 	size = nel * elsz;
    216 	RF_LOCK_MUTEX(rf_debug_mem_mutex);
    217 	rf_redzone_calloc(pp, nel, elsz);
    218 	p = pp;
    219 	if (p == NULL) {
    220 		RF_ERRORMSG4("Unable to calloc %d objects of size %d at line %d file %s\n",
    221 		    nel, elsz, line, file);
    222 		return (NULL);
    223 	}
    224 	if (rf_memAmtDebug) {
    225 		rf_mem_alloc += size;
    226 		printf("%lu    size %d %s:%d\n", rf_mem_alloc, size, file, line);
    227 	}
    228 #if RF_UTILITY == 0
    229 	if (rf_memDebug > 1) {
    230 		rf_get_threadid(tid);
    231 		printf("[%d] calloc 0x%lx - 0x%lx (%d,%d) %s %d\n", tid, p, p + size, nel,
    232 		    elsz, file, line);
    233 	}
    234 #endif				/* RF_UTILITY == 0 */
    235 	if (rf_memDebug) {
    236 		rf_record_malloc(p, size, line, file);
    237 	}
    238 	RF_UNLOCK_MUTEX(rf_debug_mem_mutex);
    239 	return (p);
    240 }
    241 #if RF_UTILITY == 0
    242 char   *
    243 rf_real_CallocAndAdd(nel, elsz, alist, line, file)
    244 	int     nel;
    245 	int     elsz;
    246 	RF_AllocListElem_t *alist;
    247 	int     line;
    248 	char   *file;
    249 {
    250 	int     tid, size;
    251 	void   *pp;
    252 	char   *p;
    253 
    254 	size = nel * elsz;
    255 	RF_LOCK_MUTEX(rf_debug_mem_mutex);
    256 	rf_redzone_calloc(pp, nel, elsz);
    257 	p = pp;
    258 	if (p == NULL) {
    259 		RF_ERRORMSG4("Unable to calloc %d objs of size %d at line %d file %s\n",
    260 		    nel, elsz, line, file);
    261 		return (NULL);
    262 	}
    263 	if (rf_memAmtDebug) {
    264 		rf_mem_alloc += size;
    265 		printf("%lu    size %d %s:%d\n", rf_mem_alloc, size, file, line);
    266 	}
    267 	if (rf_memDebug > 1) {
    268 		rf_get_threadid(tid);
    269 		printf("[%d] calloc+add 0x%lx - 0x%lx (%d,%d) %s %d\n", tid, p,
    270 		    p + size, nel, elsz, file, line);
    271 	}
    272 	if (alist) {
    273 		rf_real_AddToAllocList(alist, pp, size, 0);
    274 	}
    275 	if (rf_memDebug)
    276 		rf_record_malloc(p, size, line, file);
    277 	RF_UNLOCK_MUTEX(rf_debug_mem_mutex);
    278 	return (p);
    279 }
    280 #endif				/* RF_UTILITY == 0 */
    281 
    282 void
    283 rf_real_Free(p, sz, line, file)
    284 	void   *p;
    285 	int     sz;
    286 	int     line;
    287 	char   *file;
    288 {
    289 	int     tid;
    290 
    291 #if RF_UTILITY == 0
    292 	if (rf_memDebug > 1) {
    293 		rf_get_threadid(tid);
    294 		printf("[%d] free 0x%lx - 0x%lx (%d) %s %d\n", tid, p, ((char *) p) + sz, sz,
    295 		    file, line);
    296 	}
    297 #endif				/* RF_UTILITY == 0 */
    298 	RF_LOCK_MUTEX(rf_debug_mem_mutex);
    299 	if (rf_memAmtDebug) {
    300 		rf_mem_alloc -= sz;
    301 		printf("%lu  - size %d %s:%d\n", rf_mem_alloc, sz, file, line);
    302 	}
    303 	if (rf_memDebug) {
    304 		rf_unrecord_malloc(p, sz);
    305 	}
    306 	rf_redzone_free(p);
    307 	RF_UNLOCK_MUTEX(rf_debug_mem_mutex);
    308 }
    309 
    310 void
    311 rf_validate_mh_table()
    312 {
    313 	int     i, size;
    314 	struct mh_struct *p;
    315 	char   *cp;
    316 
    317 	return;
    318 	for (i = 0; i < RF_MH_TABLESIZE; i++) {
    319 		for (p = mh_table[i]; p; p = p->next)
    320 			if (p->allocated) {
    321 				cp = ((char *) p->address) - 8;
    322 				size = *((long *) cp);
    323 				if ((((char *) cp)[(size) + 8] != '!') || (((char *) cp)[(size) + 15] != '!')) {
    324 					rf_redzone_free_failed(cp, (size), __LINE__, __FILE__);
    325 				}
    326 			}
    327 	}
    328 }
    329 
    330 static void
    331 rf_redzone_free_failed(ptr, size, line, file)
    332 	void   *ptr;
    333 	int     size;
    334 	int     line;
    335 	char   *file;
    336 {
    337 	RF_ERRORMSG4("Free of 0x%lx (recorded size %d) at %d of %s detected redzone overrun\n", ptr, size, line, file);
    338 	RF_ASSERT(0);
    339 }
    340 #endif				/* !_KERNEL */
    341 
    342 void
    343 rf_record_malloc(p, size, line, filen)
    344 	void   *p;
    345 	int     size, line;
    346 	char   *filen;
    347 {
    348 	RF_ASSERT(size != 0);
    349 
    350 	/* RF_LOCK_MUTEX(rf_debug_mem_mutex); */
    351 	memory_hash_insert(p, size, line, filen);
    352 	tot_mem_in_use += size;
    353 	/* RF_UNLOCK_MUTEX(rf_debug_mem_mutex); */
    354 	if ((long) p == rf_memDebugAddress) {
    355 		printf("Allocate: debug address allocated from line %d file %s\n", line, filen);
    356 	}
    357 }
    358 
    359 void
    360 rf_unrecord_malloc(p, sz)
    361 	void   *p;
    362 	int     sz;
    363 {
    364 	int     size;
    365 
    366 	/* RF_LOCK_MUTEX(rf_debug_mem_mutex); */
    367 	size = memory_hash_remove(p, sz);
    368 	tot_mem_in_use -= size;
    369 	/* RF_UNLOCK_MUTEX(rf_debug_mem_mutex); */
    370 	if ((long) p == rf_memDebugAddress) {
    371 		printf("Free: Found debug address\n");	/* this is really only a
    372 							 * flag line for gdb */
    373 	}
    374 }
    375 
    376 void
    377 rf_print_unfreed()
    378 {
    379 	int     i, foundone = 0;
    380 	struct mh_struct *p;
    381 
    382 	for (i = 0; i < RF_MH_TABLESIZE; i++) {
    383 		for (p = mh_table[i]; p; p = p->next)
    384 			if (p->allocated) {
    385 				if (!foundone)
    386 					printf("\n\nThere are unfreed memory locations at program shutdown:\n");
    387 				foundone = 1;
    388 				printf("Addr 0x%lx Size %d line %d file %s\n",
    389 				    (long) p->address, p->size, p->line, p->filen);
    390 			}
    391 	}
    392 	if (tot_mem_in_use) {
    393 		printf("%ld total bytes in use\n", tot_mem_in_use);
    394 	}
    395 }
    396 
    397 int
    398 rf_ConfigureDebugMem(listp)
    399 	RF_ShutdownList_t **listp;
    400 {
    401 	int     i, rc;
    402 
    403 	rc = rf_create_managed_mutex(listp, &rf_debug_mem_mutex);
    404 	if (rc) {
    405 		RF_ERRORMSG3("Unable to init mutex file %s line %d rc=%d\n", __FILE__,
    406 		    __LINE__, rc);
    407 		return (rc);
    408 	}
    409 	if (rf_memDebug) {
    410 		for (i = 0; i < RF_MH_TABLESIZE; i++)
    411 			mh_table[i] = NULL;
    412 		mh_table_initialized = 1;
    413 	}
    414 	return (0);
    415 }
    416 #define HASHADDR(_a_)      ( (((unsigned long) _a_)>>3) % RF_MH_TABLESIZE )
    417 
    418 static void
    419 memory_hash_insert(addr, size, line, filen)
    420 	void   *addr;
    421 	int     size, line;
    422 	char   *filen;
    423 {
    424 	unsigned long bucket = HASHADDR(addr);
    425 	struct mh_struct *p;
    426 
    427 	RF_ASSERT(mh_table_initialized);
    428 
    429 	/* search for this address in the hash table */
    430 	for (p = mh_table[bucket]; p && (p->address != addr); p = p->next);
    431 	if (!p) {
    432 		RF_Malloc(p, sizeof(struct mh_struct), (struct mh_struct *));
    433 		RF_ASSERT(p);
    434 		p->next = mh_table[bucket];
    435 		mh_table[bucket] = p;
    436 		p->address = addr;
    437 		p->allocated = 0;
    438 	}
    439 	if (p->allocated) {
    440 		printf("ERROR:  reallocated address 0x%lx from line %d, file %s without intervening free\n", (long) addr, line, filen);
    441 		printf("        last allocated from line %d file %s\n", p->line, p->filen);
    442 		RF_ASSERT(0);
    443 	}
    444 	p->size = size;
    445 	p->line = line;
    446 	p->filen = filen;
    447 	p->allocated = 1;
    448 }
    449 
    450 static int
    451 memory_hash_remove(addr, sz)
    452 	void   *addr;
    453 	int     sz;
    454 {
    455 	unsigned long bucket = HASHADDR(addr);
    456 	struct mh_struct *p;
    457 
    458 	RF_ASSERT(mh_table_initialized);
    459 	for (p = mh_table[bucket]; p && (p->address != addr); p = p->next);
    460 	if (!p) {
    461 		printf("ERROR:  freeing never-allocated address 0x%lx\n", (long) addr);
    462 		RF_PANIC();
    463 	}
    464 	if (!p->allocated) {
    465 		printf("ERROR:  freeing unallocated address 0x%lx.  Last allocation line %d file %s\n", (long) addr, p->line, p->filen);
    466 		RF_PANIC();
    467 	}
    468 	if (sz > 0 && p->size != sz) {	/* you can suppress this error by
    469 					 * using a negative value as the size
    470 					 * to free */
    471 		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);
    472 		RF_PANIC();
    473 	}
    474 	p->allocated = 0;
    475 	return (p->size);
    476 }
    477 
    478 void
    479 rf_ReportMaxMem()
    480 {
    481 	printf("Max memory used:  %d bytes\n", (int) max_mem);
    482 }
    483