xref: /freebsd/sys/vm/uma_dbg.c (revision 639c9550fb346921350cd3badad4545d92d09c25)
18efc4effSJeff Roberson /*
28efc4effSJeff Roberson  * Copyright (c) 2002, Jeffrey Roberson <jroberson@chesapeake.net>
38efc4effSJeff Roberson  * All rights reserved.
48efc4effSJeff Roberson  *
58efc4effSJeff Roberson  * Redistribution and use in source and binary forms, with or without
68efc4effSJeff Roberson  * modification, are permitted provided that the following conditions
78efc4effSJeff Roberson  * are met:
88efc4effSJeff Roberson  * 1. Redistributions of source code must retain the above copyright
98efc4effSJeff Roberson  *    notice unmodified, this list of conditions, and the following
108efc4effSJeff Roberson  *    disclaimer.
118efc4effSJeff Roberson  * 2. Redistributions in binary form must reproduce the above copyright
128efc4effSJeff Roberson  *    notice, this list of conditions and the following disclaimer in the
138efc4effSJeff Roberson  *    documentation and/or other materials provided with the distribution.
148efc4effSJeff Roberson  *
158efc4effSJeff Roberson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
168efc4effSJeff Roberson  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
178efc4effSJeff Roberson  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
188efc4effSJeff Roberson  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
198efc4effSJeff Roberson  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
208efc4effSJeff Roberson  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
218efc4effSJeff Roberson  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
228efc4effSJeff Roberson  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
238efc4effSJeff Roberson  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
248efc4effSJeff Roberson  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
258efc4effSJeff Roberson  *
268efc4effSJeff Roberson  * $FreeBSD$
278efc4effSJeff Roberson  *
288efc4effSJeff Roberson  */
298efc4effSJeff Roberson 
308efc4effSJeff Roberson /*
318efc4effSJeff Roberson  * uma_dbg.c	Debugging features for UMA users
328efc4effSJeff Roberson  *
338efc4effSJeff Roberson  */
348efc4effSJeff Roberson 
358efc4effSJeff Roberson 
368efc4effSJeff Roberson #include <sys/param.h>
378efc4effSJeff Roberson #include <sys/systm.h>
388efc4effSJeff Roberson #include <sys/kernel.h>
398efc4effSJeff Roberson #include <sys/types.h>
408efc4effSJeff Roberson #include <sys/queue.h>
418efc4effSJeff Roberson #include <sys/lock.h>
428efc4effSJeff Roberson #include <sys/mutex.h>
438efc4effSJeff Roberson 
448efc4effSJeff Roberson #include <machine/types.h>
458efc4effSJeff Roberson 
468efc4effSJeff Roberson #include <vm/uma.h>
478efc4effSJeff Roberson #include <vm/uma_int.h>
488efc4effSJeff Roberson #include <vm/uma_dbg.h>
498efc4effSJeff Roberson 
508efc4effSJeff Roberson static const u_int32_t uma_junk = 0xdeadc0de;
518efc4effSJeff Roberson 
528efc4effSJeff Roberson /*
538efc4effSJeff Roberson  * Checks an item to make sure it hasn't been overwritten since freed.
548efc4effSJeff Roberson  *
558efc4effSJeff Roberson  * Complies with standard ctor arg/return
568efc4effSJeff Roberson  *
578efc4effSJeff Roberson  */
588efc4effSJeff Roberson void
598efc4effSJeff Roberson trash_ctor(void *mem, int size, void *arg)
608efc4effSJeff Roberson {
618efc4effSJeff Roberson 	int cnt;
628efc4effSJeff Roberson 	u_int32_t *p;
638efc4effSJeff Roberson 
648efc4effSJeff Roberson 	cnt = size / sizeof(uma_junk);
658efc4effSJeff Roberson 
668efc4effSJeff Roberson 	for (p = mem; cnt > 0; cnt--, p++)
678efc4effSJeff Roberson 		if (*p != uma_junk)
688efc4effSJeff Roberson 			panic("Memory modified after free %p(%d)\n",
698efc4effSJeff Roberson 			    mem, size);
708efc4effSJeff Roberson }
718efc4effSJeff Roberson 
728efc4effSJeff Roberson /*
738efc4effSJeff Roberson  * Fills an item with predictable garbage
748efc4effSJeff Roberson  *
758efc4effSJeff Roberson  * Complies with standard dtor arg/return
768efc4effSJeff Roberson  *
778efc4effSJeff Roberson  */
788efc4effSJeff Roberson void
798efc4effSJeff Roberson trash_dtor(void *mem, int size, void *arg)
808efc4effSJeff Roberson {
818efc4effSJeff Roberson 	int cnt;
828efc4effSJeff Roberson 	u_int32_t *p;
838efc4effSJeff Roberson 
848efc4effSJeff Roberson 	cnt = size / sizeof(uma_junk);
858efc4effSJeff Roberson 
868efc4effSJeff Roberson 	for (p = mem; cnt > 0; cnt--, p++)
878efc4effSJeff Roberson 		*p = uma_junk;
888efc4effSJeff Roberson }
898efc4effSJeff Roberson 
908efc4effSJeff Roberson /*
918efc4effSJeff Roberson  * Fills an item with predictable garbage
928efc4effSJeff Roberson  *
938efc4effSJeff Roberson  * Complies with standard init arg/return
948efc4effSJeff Roberson  *
958efc4effSJeff Roberson  */
968efc4effSJeff Roberson void
978efc4effSJeff Roberson trash_init(void *mem, int size)
988efc4effSJeff Roberson {
998efc4effSJeff Roberson 	trash_dtor(mem, size, NULL);
1008efc4effSJeff Roberson }
1018efc4effSJeff Roberson 
1028efc4effSJeff Roberson /*
1038efc4effSJeff Roberson  * Checks an item to make sure it hasn't been overwritten since it was freed.
1048efc4effSJeff Roberson  *
1058efc4effSJeff Roberson  * Complies with standard fini arg/return
1068efc4effSJeff Roberson  *
1078efc4effSJeff Roberson  */
1088efc4effSJeff Roberson void
1098efc4effSJeff Roberson trash_fini(void *mem, int size)
1108efc4effSJeff Roberson {
1118efc4effSJeff Roberson 	trash_ctor(mem, size, NULL);
1128efc4effSJeff Roberson }
113639c9550SJeff Roberson 
114639c9550SJeff Roberson static uma_slab_t
115639c9550SJeff Roberson uma_dbg_getslab(uma_zone_t zone, void *item)
116639c9550SJeff Roberson {
117639c9550SJeff Roberson 	uma_slab_t slab;
118639c9550SJeff Roberson 	u_int8_t *mem;
119639c9550SJeff Roberson 
120639c9550SJeff Roberson 	mem = (u_int8_t *)((unsigned long)item & (~UMA_SLAB_MASK));
121639c9550SJeff Roberson 	if (zone->uz_flags & UMA_ZFLAG_MALLOC) {
122639c9550SJeff Roberson 		slab = hash_sfind(mallochash, mem);
123639c9550SJeff Roberson 	} else if (zone->uz_flags & UMA_ZFLAG_OFFPAGE) {
124639c9550SJeff Roberson 		ZONE_LOCK(zone);
125639c9550SJeff Roberson 		slab = hash_sfind(&zone->uz_hash, mem);
126639c9550SJeff Roberson 		ZONE_UNLOCK(zone);
127639c9550SJeff Roberson 	} else {
128639c9550SJeff Roberson 		mem += zone->uz_pgoff;
129639c9550SJeff Roberson 		slab = (uma_slab_t)mem;
130639c9550SJeff Roberson 	}
131639c9550SJeff Roberson 
132639c9550SJeff Roberson 	return (slab);
133639c9550SJeff Roberson }
134639c9550SJeff Roberson 
135639c9550SJeff Roberson /*
136639c9550SJeff Roberson  * Set up the slab's freei data such that uma_dbg_free can function.
137639c9550SJeff Roberson  *
138639c9550SJeff Roberson  */
139639c9550SJeff Roberson 
140639c9550SJeff Roberson void
141639c9550SJeff Roberson uma_dbg_alloc(uma_zone_t zone, uma_slab_t slab, void *item)
142639c9550SJeff Roberson {
143639c9550SJeff Roberson 	int freei;
144639c9550SJeff Roberson 
145639c9550SJeff Roberson 	if (slab == NULL) {
146639c9550SJeff Roberson 		slab = uma_dbg_getslab(zone, item);
147639c9550SJeff Roberson 		if (slab == NULL)
148639c9550SJeff Roberson 			panic("uma: item %p did not belong to zone %s\n",
149639c9550SJeff Roberson 			    item, zone->uz_name);
150639c9550SJeff Roberson 	}
151639c9550SJeff Roberson 
152639c9550SJeff Roberson 	freei = ((unsigned long)item - (unsigned long)slab->us_data)
153639c9550SJeff Roberson 	    / zone->uz_rsize;
154639c9550SJeff Roberson 
155639c9550SJeff Roberson 	slab->us_freelist[freei] = 255;
156639c9550SJeff Roberson 
157639c9550SJeff Roberson 	return;
158639c9550SJeff Roberson }
159639c9550SJeff Roberson 
160639c9550SJeff Roberson /*
161639c9550SJeff Roberson  * Verifies freed addresses.  Checks for alignment, valid slab membership
162639c9550SJeff Roberson  * and duplicate frees.
163639c9550SJeff Roberson  *
164639c9550SJeff Roberson  */
165639c9550SJeff Roberson 
166639c9550SJeff Roberson void
167639c9550SJeff Roberson uma_dbg_free(uma_zone_t zone, uma_slab_t slab, void *item)
168639c9550SJeff Roberson {
169639c9550SJeff Roberson 	int freei;
170639c9550SJeff Roberson 
171639c9550SJeff Roberson 	return;
172639c9550SJeff Roberson 
173639c9550SJeff Roberson 	if (slab == NULL) {
174639c9550SJeff Roberson 		slab = uma_dbg_getslab(zone, item);
175639c9550SJeff Roberson 		if (slab == NULL)
176639c9550SJeff Roberson 			panic("uma: Freed item %p did not belong to zone %s\n",
177639c9550SJeff Roberson 			    item, zone->uz_name);
178639c9550SJeff Roberson 	}
179639c9550SJeff Roberson 
180639c9550SJeff Roberson 	freei = ((unsigned long)item - (unsigned long)slab->us_data)
181639c9550SJeff Roberson 	    / zone->uz_rsize;
182639c9550SJeff Roberson 
183639c9550SJeff Roberson 	if (freei >= zone->uz_ipers)
184639c9550SJeff Roberson 		panic("zone: %s(%p) slab %p freelist %i out of range 0-%d\n",
185639c9550SJeff Roberson 		    zone->uz_name, zone, slab, freei, zone->uz_ipers-1);
186639c9550SJeff Roberson 
187639c9550SJeff Roberson 	if (((freei * zone->uz_rsize) + slab->us_data) != item) {
188639c9550SJeff Roberson 		printf("zone: %s(%p) slab %p freed address %p unaligned.\n",
189639c9550SJeff Roberson 		    zone->uz_name, zone, slab, item);
190639c9550SJeff Roberson 		panic("should be %p\n",
191639c9550SJeff Roberson 		    (freei * zone->uz_rsize) + slab->us_data);
192639c9550SJeff Roberson 	}
193639c9550SJeff Roberson 
194639c9550SJeff Roberson 	if (slab->us_freelist[freei] != 255) {
195639c9550SJeff Roberson 		printf("Slab at %p, freei %d = %d.\n",
196639c9550SJeff Roberson 		    slab, freei, slab->us_freelist[freei]);
197639c9550SJeff Roberson 		panic("Duplicate free of item %p from zone %p(%s)\n",
198639c9550SJeff Roberson 		    item, zone, zone->uz_name);
199639c9550SJeff Roberson 	}
200639c9550SJeff Roberson 
201639c9550SJeff Roberson 	/*
202639c9550SJeff Roberson 	 * When this is actually linked into the slab this will change.
203639c9550SJeff Roberson 	 * Until then the count of valid slabs will make sure we don't
204639c9550SJeff Roberson 	 * accidentally follow this and assume it's a valid index.
205639c9550SJeff Roberson 	 */
206639c9550SJeff Roberson 	slab->us_freelist[freei] = 0;
207639c9550SJeff Roberson }
208