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@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