1 /* $NetBSD: rf_debugMem.c,v 1.22 2019/02/09 03:34:00 christos 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 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: rf_debugMem.c,v 1.22 2019/02/09 03:34:00 christos Exp $"); 36 37 #include <dev/raidframe/raidframevar.h> 38 39 #include "rf_threadstuff.h" 40 #include "rf_options.h" 41 #include "rf_debugMem.h" 42 #include "rf_general.h" 43 #include "rf_shutdown.h" 44 45 #if RF_DEBUG_MEM 46 47 static size_t tot_mem_in_use = 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 size_t size; 55 const char *file; 56 uint32_t line; 57 char allocated; 58 struct mh_struct *next; 59 }; 60 static struct mh_struct *mh_table[RF_MH_TABLESIZE]; 61 static rf_declare_mutex2(rf_debug_mem_mutex); 62 static int mh_table_initialized = 0; 63 64 static void memory_hash_insert(void *, size_t, const char *, uint32_t); 65 static int memory_hash_remove(void *, size_t); 66 67 void 68 rf_record_malloc(void *p, size_t size, const char *file, uint32_t line) 69 { 70 RF_ASSERT(size != 0); 71 72 /* rf_lock_mutex2(rf_debug_mem_mutex); */ 73 memory_hash_insert(p, size, file, line); 74 tot_mem_in_use += size; 75 /* rf_unlock_mutex2(rf_debug_mem_mutex); */ 76 if ((intptr_t)p == rf_memDebugAddress) { 77 printf("%s,%d: %s: Debug address allocated\n", file, line, 78 __func__); 79 } 80 } 81 82 void 83 rf_unrecord_malloc(void *p, size_t sz) 84 { 85 size_t size; 86 87 /* rf_lock_mutex2(rf_debug_mem_mutex); */ 88 size = memory_hash_remove(p, sz); 89 tot_mem_in_use -= size; 90 /* rf_unlock_mutex2(rf_debug_mem_mutex); */ 91 if ((intptr_t) p == rf_memDebugAddress) { 92 /* this is really only a flag line for gdb */ 93 printf("%s: Found debug address\n", __func__); 94 } 95 } 96 97 void 98 rf_print_unfreed(void) 99 { 100 size_t i; 101 int foundone = 0; 102 struct mh_struct *p; 103 104 for (i = 0; i < RF_MH_TABLESIZE; i++) { 105 for (p = mh_table[i]; p; p = p->next) { 106 if (!p->allocated) 107 continue; 108 if (foundone) { 109 printf("\n\n:%s: There are unfreed memory" 110 " locations at program shutdown:\n", 111 __func__); 112 } 113 foundone = 1; 114 printf("%s: @%s,%d: addr %p size %zu\n", __func__, 115 p->file, p->line, p->address, p->size); 116 } 117 } 118 if (tot_mem_in_use) { 119 printf("%s: %zu total bytes in use\n", 120 __func__, tot_mem_in_use); 121 } 122 } 123 #endif /* RF_DEBUG_MEM */ 124 125 #if RF_DEBUG_MEM 126 static void 127 rf_ShutdownDebugMem(void *unused) 128 { 129 rf_destroy_mutex2(rf_debug_mem_mutex); 130 } 131 #endif 132 133 int 134 rf_ConfigureDebugMem(RF_ShutdownList_t **listp) 135 { 136 #if RF_DEBUG_MEM 137 size_t i; 138 139 rf_init_mutex2(rf_debug_mem_mutex, IPL_VM); 140 if (rf_memDebug) { 141 for (i = 0; i < RF_MH_TABLESIZE; i++) 142 mh_table[i] = NULL; 143 mh_table_initialized = 1; 144 } 145 rf_ShutdownCreate(listp, rf_ShutdownDebugMem, NULL); 146 #endif 147 return (0); 148 } 149 150 #if RF_DEBUG_MEM 151 152 #define HASHADDR(a) ((size_t)((((uintptr_t)a) >> 3) % RF_MH_TABLESIZE)) 153 154 static void 155 memory_hash_insert(void *addr, size_t size, const char *file, uint32_t line) 156 { 157 size_t bucket = (size_t)HASHADDR(addr); 158 struct mh_struct *p; 159 160 RF_ASSERT(mh_table_initialized); 161 162 /* search for this address in the hash table */ 163 for (p = mh_table[bucket]; p && (p->address != addr); p = p->next) 164 continue; 165 if (!p) { 166 p = RF_Malloc(sizeof(*p)); 167 RF_ASSERT(p); 168 p->next = mh_table[bucket]; 169 mh_table[bucket] = p; 170 p->address = addr; 171 p->allocated = 0; 172 } 173 if (p->allocated) { 174 printf("%s: @%s,%u: ERROR: Reallocated addr %p without free\n", 175 __func__, file, line, addr); 176 printf("%s: last allocated @%s,%u\n", 177 __func__, p->file, p->line); 178 RF_ASSERT(0); 179 } 180 p->size = size; 181 p->line = line; 182 p->file = file; 183 p->allocated = 1; 184 } 185 186 static int 187 memory_hash_remove(void *addr, size_t sz) 188 { 189 size_t bucket = HASHADDR(addr); 190 struct mh_struct *p; 191 192 RF_ASSERT(mh_table_initialized); 193 for (p = mh_table[bucket]; p && (p->address != addr); p = p->next) 194 continue; 195 if (!p) { 196 printf("%s: ERROR: Freeing never-allocated address %p\n", 197 __func__, addr); 198 RF_PANIC(); 199 } 200 if (!p->allocated) { 201 printf("%s: ERROR: Freeing unallocated address %p." 202 " Last allocation @%s,%u\n", 203 __func__, addr, p->file, p->line); 204 RF_PANIC(); 205 } 206 if (sz > 0 && p->size != sz) { /* you can suppress this error by 207 * using a negative value as the size 208 * to free */ 209 printf("%s: ERROR: Incorrect size (%zu should be %zu) at" 210 " free for address %p. Allocated @%s,%u\n", __func__, 211 sz, p->size, addr, p->file, p->line); 212 RF_PANIC(); 213 } 214 p->allocated = 0; 215 return p->size; 216 } 217 #endif /* RF_DEBUG_MEM */ 218 219 220