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