1 /* $OpenBSD: rf_debugMem.c,v 1.5 2002/12/16 07:01:03 tdeval Exp $ */
2 /* $NetBSD: rf_debugMem.c,v 1.7 2000/01/07 03:40:59 oster Exp $ */
3
4 /*
5 * Copyright (c) 1995 Carnegie-Mellon University.
6 * All rights reserved.
7 *
8 * Author: Daniel Stodolsky, Mark Holland, Jim Zelenka
9 *
10 * Permission to use, copy, modify and distribute this software and
11 * its documentation is hereby granted, provided that both the copyright
12 * notice and this permission notice appear in all copies of the
13 * software, derivative works or modified versions, and any portions
14 * thereof, and that both notices appear in supporting documentation.
15 *
16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
18 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 *
20 * Carnegie Mellon requests users of this software to return to
21 *
22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
23 * School of Computer Science
24 * Carnegie Mellon University
25 * Pittsburgh PA 15213-3890
26 *
27 * any improvements or extensions that they make and grant Carnegie the
28 * rights to redistribute these changes.
29 */
30
31 /*
32 * debugMem.c: Memory usage debugging stuff.
33 *
34 * Malloc, Calloc, and Free are #defined everywhere
35 * to do_malloc, do_calloc, and do_free.
36 *
37 * If RF_UTILITY is nonzero, it means we are compiling one of the
38 * RAIDframe utility programs, such as rfctrl or smd. In this
39 * case, we eliminate all references to the threads package
40 * and to the allocation list stuff.
41 */
42
43 #include "rf_types.h"
44 #include "rf_threadstuff.h"
45 #include "rf_options.h"
46 #include "rf_debugMem.h"
47 #include "rf_general.h"
48
49 static long tot_mem_in_use = 0;
50
51 /* Hash table of information about memory allocations. */
52 #define RF_MH_TABLESIZE 1000
53
54 struct mh_struct {
55 void *address;
56 int size;
57 int line;
58 char *filen;
59 char allocated;
60 struct mh_struct *next;
61 };
62
63 static struct mh_struct *mh_table[RF_MH_TABLESIZE];
64
65 RF_DECLARE_MUTEX(rf_debug_mem_mutex);
66 static int mh_table_initialized = 0;
67
68 void rf_memory_hash_insert(void *, int, int, char *);
69 int rf_memory_hash_remove(void *, int);
70
71 void
rf_record_malloc(void * p,int size,int line,char * filen)72 rf_record_malloc(void *p, int size, int line, char *filen)
73 {
74 RF_ASSERT(size != 0);
75
76 /*RF_LOCK_MUTEX(rf_debug_mem_mutex);*/
77 rf_memory_hash_insert(p, size, line, filen);
78 tot_mem_in_use += size;
79 /*RF_UNLOCK_MUTEX(rf_debug_mem_mutex);*/
80
81 if ((long) p == rf_memDebugAddress) {
82 printf("Allocate: debug address allocated from line %d file"
83 " %s\n", line, filen);
84 }
85 }
86
87 void
rf_unrecord_malloc(void * p,int sz)88 rf_unrecord_malloc(void *p, int sz)
89 {
90 int size;
91
92 /*RF_LOCK_MUTEX(rf_debug_mem_mutex);*/
93 size = rf_memory_hash_remove(p, sz);
94 tot_mem_in_use -= size;
95 /*RF_UNLOCK_MUTEX(rf_debug_mem_mutex);*/
96 if ((long) p == rf_memDebugAddress) {
97 /* This is really only a flag line for gdb. */
98 printf("Free: Found debug address\n");
99 }
100 }
101
102 void
rf_print_unfreed(void)103 rf_print_unfreed(void)
104 {
105 int i, foundone = 0;
106 struct mh_struct *p;
107
108 for (i = 0; i < RF_MH_TABLESIZE; i++) {
109 for (p = mh_table[i]; p; p = p->next)
110 if (p->allocated) {
111 if (!foundone)
112 printf("\n\nThere are unfreed"
113 " memory locations at"
114 " program shutdown:\n");
115 foundone = 1;
116 printf("Addr 0x%lx Size %d line %d file %s\n",
117 (long) p->address, p->size, p->line,
118 p->filen);
119 }
120 }
121 if (tot_mem_in_use) {
122 printf("%ld total bytes in use\n", tot_mem_in_use);
123 }
124 }
125
126 int
rf_ConfigureDebugMem(RF_ShutdownList_t ** listp)127 rf_ConfigureDebugMem(RF_ShutdownList_t **listp)
128 {
129 int i, rc;
130
131 rc = rf_create_managed_mutex(listp, &rf_debug_mem_mutex);
132 if (rc) {
133 RF_ERRORMSG3("Unable to init mutex file %s line %d rc=%d\n",
134 __FILE__, __LINE__, rc);
135 return (rc);
136 }
137 if (rf_memDebug) {
138 for (i = 0; i < RF_MH_TABLESIZE; i++)
139 mh_table[i] = NULL;
140 mh_table_initialized = 1;
141 }
142 return (0);
143 }
144
145 #define HASHADDR(_a_) ( (((unsigned long) _a_)>>3) % RF_MH_TABLESIZE )
146
147 void
rf_memory_hash_insert(void * addr,int size,int line,char * filen)148 rf_memory_hash_insert(void *addr, int size, int line, char *filen)
149 {
150 unsigned long bucket = HASHADDR(addr);
151 struct mh_struct *p;
152
153 RF_ASSERT(mh_table_initialized);
154
155 /* Search for this address in the hash table. */
156 for (p = mh_table[bucket]; p && (p->address != addr); p = p->next);
157 if (!p) {
158 RF_Malloc(p, sizeof(struct mh_struct), (struct mh_struct *));
159 RF_ASSERT(p);
160 p->next = mh_table[bucket];
161 mh_table[bucket] = p;
162 p->address = addr;
163 p->allocated = 0;
164 }
165 if (p->allocated) {
166 printf("ERROR: Reallocated address 0x%lx from line %d,"
167 " file %s without intervening free\n", (long) addr,
168 line, filen);
169 printf(" Last allocated from line %d file %s\n",
170 p->line, p->filen);
171 RF_ASSERT(0);
172 }
173 p->size = size;
174 p->line = line;
175 p->filen = filen;
176 p->allocated = 1;
177 }
178
179 int
rf_memory_hash_remove(void * addr,int sz)180 rf_memory_hash_remove(void *addr, int sz)
181 {
182 unsigned long bucket = HASHADDR(addr);
183 struct mh_struct *p;
184
185 RF_ASSERT(mh_table_initialized);
186 for (p = mh_table[bucket]; p && (p->address != addr); p = p->next);
187 if (!p) {
188 printf("ERROR: Freeing never-allocated address 0x%lx\n",
189 (long) addr);
190 RF_PANIC();
191 }
192 if (!p->allocated) {
193 printf("ERROR: Freeing unallocated address 0x%lx."
194 " Last allocation line %d file %s\n", (long) addr,
195 p->line, p->filen);
196 RF_PANIC();
197 }
198 if (sz > 0 && p->size != sz) {
199 /*
200 * This error can be suppressed by using a negative value
201 * as the size to free.
202 */
203 printf("ERROR: Incorrect size at free for address 0x%lx:"
204 " is %d should be %d. Alloc at line %d of file %s\n",
205 (unsigned long) addr, sz, p->size, p->line, p->filen);
206 RF_PANIC();
207 }
208 p->allocated = 0;
209 return (p->size);
210 }
211