xref: /freebsd/sys/vm/uma_dbg.c (revision a03c23931eec567b0957c2a0b1102dba8d538d98)
160727d8bSWarner Losh /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
408ecce74SRobert Watson  * Copyright (c) 2002, 2003, 2004, 2005 Jeffrey Roberson <jeff@FreeBSD.org>
508ecce74SRobert Watson  * Copyright (c) 2004, 2005 Bosko Milekic <bmilekic@FreeBSD.org>
608ecce74SRobert Watson  * All rights reserved.
78efc4effSJeff Roberson  *
88efc4effSJeff Roberson  * Redistribution and use in source and binary forms, with or without
98efc4effSJeff Roberson  * modification, are permitted provided that the following conditions
108efc4effSJeff Roberson  * are met:
118efc4effSJeff Roberson  * 1. Redistributions of source code must retain the above copyright
128efc4effSJeff Roberson  *    notice unmodified, this list of conditions, and the following
138efc4effSJeff Roberson  *    disclaimer.
148efc4effSJeff Roberson  * 2. Redistributions in binary form must reproduce the above copyright
158efc4effSJeff Roberson  *    notice, this list of conditions and the following disclaimer in the
168efc4effSJeff Roberson  *    documentation and/or other materials provided with the distribution.
178efc4effSJeff Roberson  *
188efc4effSJeff Roberson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
198efc4effSJeff Roberson  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
208efc4effSJeff Roberson  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
218efc4effSJeff Roberson  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
228efc4effSJeff Roberson  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
238efc4effSJeff Roberson  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
248efc4effSJeff Roberson  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
258efc4effSJeff Roberson  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
268efc4effSJeff Roberson  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
278efc4effSJeff Roberson  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
288efc4effSJeff Roberson  */
298efc4effSJeff Roberson 
308efc4effSJeff Roberson /*
318efc4effSJeff Roberson  * uma_dbg.c	Debugging features for UMA users
328efc4effSJeff Roberson  *
338efc4effSJeff Roberson  */
348efc4effSJeff Roberson 
35874651b1SDavid E. O'Brien #include <sys/cdefs.h>
36bc9d08e1SMark Johnston #include "opt_vm.h"
37bc9d08e1SMark Johnston 
388efc4effSJeff Roberson #include <sys/param.h>
398efc4effSJeff Roberson #include <sys/systm.h>
40ef72505eSJeff Roberson #include <sys/bitset.h>
418efc4effSJeff Roberson #include <sys/kernel.h>
428efc4effSJeff Roberson #include <sys/types.h>
438efc4effSJeff Roberson #include <sys/queue.h>
448efc4effSJeff Roberson #include <sys/lock.h>
458efc4effSJeff Roberson #include <sys/mutex.h>
468f70816cSJeff Roberson #include <sys/malloc.h>
478efc4effSJeff Roberson 
4899571dc3SJeff Roberson #include <vm/vm.h>
4999571dc3SJeff Roberson #include <vm/vm_object.h>
5099571dc3SJeff Roberson #include <vm/vm_page.h>
518efc4effSJeff Roberson #include <vm/uma.h>
528efc4effSJeff Roberson #include <vm/uma_int.h>
538efc4effSJeff Roberson #include <vm/uma_dbg.h>
54bc9d08e1SMark Johnston #include <vm/memguard.h>
558efc4effSJeff Roberson 
56*a03c2393SAlexander Motin #include <machine/stack.h>
57*a03c2393SAlexander Motin 
587c566d6cSAlexander Motin static const u_long uma_junk = (u_long)0xdeadc0dedeadc0de;
598efc4effSJeff Roberson 
608efc4effSJeff Roberson /*
61b23f72e9SBrian Feldman  * Checks an item to make sure it hasn't been overwritten since it was freed,
62b23f72e9SBrian Feldman  * prior to subsequent reallocation.
638efc4effSJeff Roberson  *
64*a03c2393SAlexander Motin  * Complies with standard ctor arg/return.  arg should be zone pointer or NULL.
658efc4effSJeff Roberson  */
66b23f72e9SBrian Feldman int
67b23f72e9SBrian Feldman trash_ctor(void *mem, int size, void *arg, int flags)
688efc4effSJeff Roberson {
69*a03c2393SAlexander Motin 	struct uma_zone *zone = arg;
707c566d6cSAlexander Motin 	u_long *p = mem, *e;
71*a03c2393SAlexander Motin 	int off;
728efc4effSJeff Roberson 
73bc9d08e1SMark Johnston #ifdef DEBUG_MEMGUARD
74bc9d08e1SMark Johnston 	if (is_memguard_addr(mem))
75bc9d08e1SMark Johnston 		return (0);
76bc9d08e1SMark Johnston #endif
77bc9d08e1SMark Johnston 
787c566d6cSAlexander Motin 	e = p + size / sizeof(*p);
797c566d6cSAlexander Motin 	for (; p < e; p++) {
80*a03c2393SAlexander Motin 		if (__predict_false(*p != uma_junk))
81*a03c2393SAlexander Motin 			goto dopanic;
828efc4effSJeff Roberson 	}
83cb6e5c1aSMike Silbersack 	return (0);
84*a03c2393SAlexander Motin 
85*a03c2393SAlexander Motin dopanic:
86*a03c2393SAlexander Motin 	off = (uintptr_t)p - (uintptr_t)mem;
87*a03c2393SAlexander Motin 	panic("Memory modified after free %p (%d, %s) + %d = %lx\n",
88*a03c2393SAlexander Motin 	    mem, size, zone ? zone->uz_name : "", off,  *p);
89*a03c2393SAlexander Motin 	return (0);
90cb6e5c1aSMike Silbersack }
918efc4effSJeff Roberson 
928efc4effSJeff Roberson /*
938efc4effSJeff Roberson  * Fills an item with predictable garbage
948efc4effSJeff Roberson  *
958efc4effSJeff Roberson  * Complies with standard dtor arg/return
968efc4effSJeff Roberson  */
978efc4effSJeff Roberson void
988efc4effSJeff Roberson trash_dtor(void *mem, int size, void *arg)
998efc4effSJeff Roberson {
1007c566d6cSAlexander Motin 	u_long *p = mem, *e;
1018efc4effSJeff Roberson 
102bc9d08e1SMark Johnston #ifdef DEBUG_MEMGUARD
103bc9d08e1SMark Johnston 	if (is_memguard_addr(mem))
104bc9d08e1SMark Johnston 		return;
105bc9d08e1SMark Johnston #endif
106bc9d08e1SMark Johnston 
1077c566d6cSAlexander Motin 	e = p + size / sizeof(*p);
1087c566d6cSAlexander Motin 	for (; p < e; p++)
1098efc4effSJeff Roberson 		*p = uma_junk;
1108efc4effSJeff Roberson }
1118efc4effSJeff Roberson 
1128efc4effSJeff Roberson /*
1138efc4effSJeff Roberson  * Fills an item with predictable garbage
1148efc4effSJeff Roberson  *
1158efc4effSJeff Roberson  * Complies with standard init arg/return
1168efc4effSJeff Roberson  */
117b23f72e9SBrian Feldman int
118b23f72e9SBrian Feldman trash_init(void *mem, int size, int flags)
1198efc4effSJeff Roberson {
1208efc4effSJeff Roberson 	trash_dtor(mem, size, NULL);
121b23f72e9SBrian Feldman 	return (0);
1228efc4effSJeff Roberson }
1238efc4effSJeff Roberson 
1248efc4effSJeff Roberson /*
125*a03c2393SAlexander Motin  * Checks an item to make sure it hasn't been overwritten since it was freed,
126*a03c2393SAlexander Motin  * prior to freeing it back to available memory.
1278efc4effSJeff Roberson  *
1288efc4effSJeff Roberson  * Complies with standard fini arg/return
1298efc4effSJeff Roberson  */
1308efc4effSJeff Roberson void
1318efc4effSJeff Roberson trash_fini(void *mem, int size)
1328efc4effSJeff Roberson {
133b23f72e9SBrian Feldman 	(void)trash_ctor(mem, size, NULL, 0);
1348efc4effSJeff Roberson }
135639c9550SJeff Roberson 
136*a03c2393SAlexander Motin /*
137*a03c2393SAlexander Motin  * Checks an item to make sure it hasn't been overwritten since it was freed,
138*a03c2393SAlexander Motin  * prior to subsequent reallocation.
139*a03c2393SAlexander Motin  *
140*a03c2393SAlexander Motin  * Complies with standard ctor arg/return.  arg should be zone pointer or NULL.
141*a03c2393SAlexander Motin  */
142b23f72e9SBrian Feldman int
143b23f72e9SBrian Feldman mtrash_ctor(void *mem, int size, void *arg, int flags)
1448f70816cSJeff Roberson {
145*a03c2393SAlexander Motin 	struct uma_zone *zone = arg;
1467c566d6cSAlexander Motin 	u_long *p = mem, *e;
147*a03c2393SAlexander Motin 	struct malloc_type **ksp;
148*a03c2393SAlexander Motin 	int off, osize = size;
1498f70816cSJeff Roberson 
150bc9d08e1SMark Johnston #ifdef DEBUG_MEMGUARD
151bc9d08e1SMark Johnston 	if (is_memguard_addr(mem))
152bc9d08e1SMark Johnston 		return (0);
153bc9d08e1SMark Johnston #endif
154bc9d08e1SMark Johnston 
1558f70816cSJeff Roberson 	size -= sizeof(struct malloc_type *);
1568f70816cSJeff Roberson 
1577c566d6cSAlexander Motin 	e = p + size / sizeof(*p);
1587c566d6cSAlexander Motin 	for (; p < e; p++) {
159*a03c2393SAlexander Motin 		if (__predict_false(*p != uma_junk))
160*a03c2393SAlexander Motin 			goto dopanic;
161*a03c2393SAlexander Motin 	}
162*a03c2393SAlexander Motin 	return (0);
163*a03c2393SAlexander Motin 
164*a03c2393SAlexander Motin dopanic:
165*a03c2393SAlexander Motin 	off = (uintptr_t)p - (uintptr_t)mem;
166*a03c2393SAlexander Motin 	ksp = (struct malloc_type **)mem;
167*a03c2393SAlexander Motin 	ksp += size / sizeof(struct malloc_type *);
168*a03c2393SAlexander Motin 	if (*ksp != NULL && INKERNEL((uintptr_t)*ksp)) {
169*a03c2393SAlexander Motin 		/*
170*a03c2393SAlexander Motin 		 * If *ksp is corrupted we may be unable to panic clean,
171*a03c2393SAlexander Motin 		 * so print what we have reliably while we still can.
172*a03c2393SAlexander Motin 		 */
173*a03c2393SAlexander Motin 		printf("Memory modified after free %p (%d, %s, %p) + %d = %lx\n",
174*a03c2393SAlexander Motin 		    mem, osize, zone ? zone->uz_name : "", *ksp, off, *p);
175*a03c2393SAlexander Motin 		panic("Memory modified after free %p (%d, %s, %s) + %d = %lx\n",
176*a03c2393SAlexander Motin 		    mem, osize, zone ? zone->uz_name : "", (*ksp)->ks_shortdesc,
177*a03c2393SAlexander Motin 		    off, *p);
178*a03c2393SAlexander Motin 	} else {
179*a03c2393SAlexander Motin 		panic("Memory modified after free %p (%d, %s, %p) + %d = %lx\n",
180*a03c2393SAlexander Motin 		    mem, osize, zone ? zone->uz_name : "", *ksp, off, *p);
1818f70816cSJeff Roberson 	}
182b23f72e9SBrian Feldman 	return (0);
1838f70816cSJeff Roberson }
1848f70816cSJeff Roberson 
1858f70816cSJeff Roberson /*
1868f70816cSJeff Roberson  * Fills an item with predictable garbage
1878f70816cSJeff Roberson  *
1888f70816cSJeff Roberson  * Complies with standard dtor arg/return
1898f70816cSJeff Roberson  */
1908f70816cSJeff Roberson void
1918f70816cSJeff Roberson mtrash_dtor(void *mem, int size, void *arg)
1928f70816cSJeff Roberson {
1937c566d6cSAlexander Motin 	u_long *p = mem, *e;
1948f70816cSJeff Roberson 
195bc9d08e1SMark Johnston #ifdef DEBUG_MEMGUARD
196bc9d08e1SMark Johnston 	if (is_memguard_addr(mem))
197bc9d08e1SMark Johnston 		return;
198bc9d08e1SMark Johnston #endif
199bc9d08e1SMark Johnston 
2008f70816cSJeff Roberson 	size -= sizeof(struct malloc_type *);
2018f70816cSJeff Roberson 
2027c566d6cSAlexander Motin 	e = p + size / sizeof(*p);
2037c566d6cSAlexander Motin 	for (; p < e; p++)
2048f70816cSJeff Roberson 		*p = uma_junk;
2058f70816cSJeff Roberson }
2068f70816cSJeff Roberson 
2078f70816cSJeff Roberson /*
2088f70816cSJeff Roberson  * Fills an item with predictable garbage
2098f70816cSJeff Roberson  *
2108f70816cSJeff Roberson  * Complies with standard init arg/return
2118f70816cSJeff Roberson  */
212b23f72e9SBrian Feldman int
213b23f72e9SBrian Feldman mtrash_init(void *mem, int size, int flags)
2148f70816cSJeff Roberson {
2158f70816cSJeff Roberson 	struct malloc_type **ksp;
2168f70816cSJeff Roberson 
217bc9d08e1SMark Johnston #ifdef DEBUG_MEMGUARD
218bc9d08e1SMark Johnston 	if (is_memguard_addr(mem))
219bc9d08e1SMark Johnston 		return (0);
220bc9d08e1SMark Johnston #endif
221bc9d08e1SMark Johnston 
2228f70816cSJeff Roberson 	mtrash_dtor(mem, size, NULL);
2238f70816cSJeff Roberson 
2248f70816cSJeff Roberson 	ksp = (struct malloc_type **)mem;
2258f70816cSJeff Roberson 	ksp += (size / sizeof(struct malloc_type *)) - 1;
2268f70816cSJeff Roberson 	*ksp = NULL;
227b23f72e9SBrian Feldman 	return (0);
2288f70816cSJeff Roberson }
2298f70816cSJeff Roberson 
2308f70816cSJeff Roberson /*
231b23f72e9SBrian Feldman  * Checks an item to make sure it hasn't been overwritten since it was freed,
232b23f72e9SBrian Feldman  * prior to freeing it back to available memory.
2338f70816cSJeff Roberson  *
2348f70816cSJeff Roberson  * Complies with standard fini arg/return
2358f70816cSJeff Roberson  */
2368f70816cSJeff Roberson void
2378f70816cSJeff Roberson mtrash_fini(void *mem, int size)
2388f70816cSJeff Roberson {
239b23f72e9SBrian Feldman 	(void)mtrash_ctor(mem, size, NULL, 0);
2408f70816cSJeff Roberson }
241