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