uma_dbg.c revision 116226
1/*
2 * Copyright (c) 2002, Jeffrey Roberson <jeff@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice unmodified, this list of conditions, and the following
10 *    disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27/*
28 * uma_dbg.c	Debugging features for UMA users
29 *
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/vm/uma_dbg.c 116226 2003-06-11 23:50:51Z obrien $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/types.h>
39#include <sys/queue.h>
40#include <sys/lock.h>
41#include <sys/mutex.h>
42#include <sys/malloc.h>
43
44#include <vm/vm.h>
45#include <vm/vm_object.h>
46#include <vm/vm_page.h>
47#include <vm/uma.h>
48#include <vm/uma_int.h>
49#include <vm/uma_dbg.h>
50
51static const u_int32_t uma_junk = 0xdeadc0de;
52
53/*
54 * Checks an item to make sure it hasn't been overwritten since freed.
55 *
56 * Complies with standard ctor arg/return
57 *
58 */
59void
60trash_ctor(void *mem, int size, void *arg)
61{
62	int cnt;
63	u_int32_t *p;
64
65	cnt = size / sizeof(uma_junk);
66
67	for (p = mem; cnt > 0; cnt--, p++)
68		if (*p != uma_junk)
69			panic("Memory modified after free %p(%d)\n",
70			    mem, size);
71}
72
73/*
74 * Fills an item with predictable garbage
75 *
76 * Complies with standard dtor arg/return
77 *
78 */
79void
80trash_dtor(void *mem, int size, void *arg)
81{
82	int cnt;
83	u_int32_t *p;
84
85	cnt = size / sizeof(uma_junk);
86
87	for (p = mem; cnt > 0; cnt--, p++)
88		*p = uma_junk;
89}
90
91/*
92 * Fills an item with predictable garbage
93 *
94 * Complies with standard init arg/return
95 *
96 */
97void
98trash_init(void *mem, int size)
99{
100	trash_dtor(mem, size, NULL);
101}
102
103/*
104 * Checks an item to make sure it hasn't been overwritten since it was freed.
105 *
106 * Complies with standard fini arg/return
107 *
108 */
109void
110trash_fini(void *mem, int size)
111{
112	trash_ctor(mem, size, NULL);
113}
114
115/*
116 * Checks an item to make sure it hasn't been overwritten since freed.
117 *
118 * Complies with standard ctor arg/return
119 *
120 */
121void
122mtrash_ctor(void *mem, int size, void *arg)
123{
124	struct malloc_type **ksp;
125	u_int32_t *p = mem;
126	int cnt;
127
128	size -= sizeof(struct malloc_type *);
129	ksp = (struct malloc_type **)mem;
130	ksp += size / sizeof(struct malloc_type *);
131	cnt = size / sizeof(uma_junk);
132
133	for (p = mem; cnt > 0; cnt--, p++)
134		if (*p != uma_junk) {
135			printf("Memory modified after free %p(%d)\n",
136			    mem, size);
137			panic("Most recently used by %s\n", (*ksp == NULL)?
138			    "none" : (*ksp)->ks_shortdesc);
139		}
140}
141
142/*
143 * Fills an item with predictable garbage
144 *
145 * Complies with standard dtor arg/return
146 *
147 */
148void
149mtrash_dtor(void *mem, int size, void *arg)
150{
151	int cnt;
152	u_int32_t *p;
153
154	size -= sizeof(struct malloc_type *);
155	cnt = size / sizeof(uma_junk);
156
157	for (p = mem; cnt > 0; cnt--, p++)
158		*p = uma_junk;
159}
160
161/*
162 * Fills an item with predictable garbage
163 *
164 * Complies with standard init arg/return
165 *
166 */
167void
168mtrash_init(void *mem, int size)
169{
170	struct malloc_type **ksp;
171
172	mtrash_dtor(mem, size, NULL);
173
174	ksp = (struct malloc_type **)mem;
175	ksp += (size / sizeof(struct malloc_type *)) - 1;
176	*ksp = NULL;
177}
178
179/*
180 * Checks an item to make sure it hasn't been overwritten since it was freed.
181 *
182 * Complies with standard fini arg/return
183 *
184 */
185void
186mtrash_fini(void *mem, int size)
187{
188	mtrash_ctor(mem, size, NULL);
189}
190
191static uma_slab_t
192uma_dbg_getslab(uma_zone_t zone, void *item)
193{
194	uma_slab_t slab;
195	u_int8_t *mem;
196
197	mem = (u_int8_t *)((unsigned long)item & (~UMA_SLAB_MASK));
198	if (zone->uz_flags & UMA_ZFLAG_MALLOC) {
199		slab = vtoslab((vm_offset_t)mem);
200	} else if (zone->uz_flags & UMA_ZFLAG_HASH) {
201		slab = hash_sfind(&zone->uz_hash, mem);
202	} else {
203		mem += zone->uz_pgoff;
204		slab = (uma_slab_t)mem;
205	}
206
207	return (slab);
208}
209
210/*
211 * Set up the slab's freei data such that uma_dbg_free can function.
212 *
213 */
214
215void
216uma_dbg_alloc(uma_zone_t zone, uma_slab_t slab, void *item)
217{
218	int freei;
219
220	if (slab == NULL) {
221		slab = uma_dbg_getslab(zone, item);
222		if (slab == NULL)
223			panic("uma: item %p did not belong to zone %s\n",
224			    item, zone->uz_name);
225	}
226
227	freei = ((unsigned long)item - (unsigned long)slab->us_data)
228	    / zone->uz_rsize;
229
230	slab->us_freelist[freei] = 255;
231
232	return;
233}
234
235/*
236 * Verifies freed addresses.  Checks for alignment, valid slab membership
237 * and duplicate frees.
238 *
239 */
240
241void
242uma_dbg_free(uma_zone_t zone, uma_slab_t slab, void *item)
243{
244	int freei;
245
246	if (slab == NULL) {
247		slab = uma_dbg_getslab(zone, item);
248		if (slab == NULL)
249			panic("uma: Freed item %p did not belong to zone %s\n",
250			    item, zone->uz_name);
251	}
252
253	freei = ((unsigned long)item - (unsigned long)slab->us_data)
254	    / zone->uz_rsize;
255
256	if (freei >= zone->uz_ipers)
257		panic("zone: %s(%p) slab %p freelist %d out of range 0-%d\n",
258		    zone->uz_name, zone, slab, freei, zone->uz_ipers-1);
259
260	if (((freei * zone->uz_rsize) + slab->us_data) != item) {
261		printf("zone: %s(%p) slab %p freed address %p unaligned.\n",
262		    zone->uz_name, zone, slab, item);
263		panic("should be %p\n",
264		    (freei * zone->uz_rsize) + slab->us_data);
265	}
266
267	if (slab->us_freelist[freei] != 255) {
268		printf("Slab at %p, freei %d = %d.\n",
269		    slab, freei, slab->us_freelist[freei]);
270		panic("Duplicate free of item %p from zone %p(%s)\n",
271		    item, zone, zone->uz_name);
272	}
273
274	/*
275	 * When this is actually linked into the slab this will change.
276	 * Until then the count of valid slabs will make sure we don't
277	 * accidentally follow this and assume it's a valid index.
278	 */
279	slab->us_freelist[freei] = 0;
280}
281