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
56a03c2393SAlexander Motin #include <machine/stack.h>
57a03c2393SAlexander 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 *
64a03c2393SAlexander Motin * Complies with standard ctor arg/return. arg should be zone pointer or NULL.
658efc4effSJeff Roberson */
66b23f72e9SBrian Feldman int
trash_ctor(void * mem,int size,void * arg,int flags)67b23f72e9SBrian Feldman trash_ctor(void *mem, int size, void *arg, int flags)
688efc4effSJeff Roberson {
69a03c2393SAlexander Motin struct uma_zone *zone = arg;
707c566d6cSAlexander Motin u_long *p = mem, *e;
71a03c2393SAlexander 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++) {
80a03c2393SAlexander Motin if (__predict_false(*p != uma_junk))
81a03c2393SAlexander Motin goto dopanic;
828efc4effSJeff Roberson }
83cb6e5c1aSMike Silbersack return (0);
84a03c2393SAlexander Motin
85a03c2393SAlexander Motin dopanic:
86a03c2393SAlexander Motin off = (uintptr_t)p - (uintptr_t)mem;
87a03c2393SAlexander Motin panic("Memory modified after free %p (%d, %s) + %d = %lx\n",
88a03c2393SAlexander Motin mem, size, zone ? zone->uz_name : "", off, *p);
89a03c2393SAlexander 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
trash_dtor(void * mem,int size,void * arg)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
trash_init(void * mem,int size,int flags)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 /*
125a03c2393SAlexander Motin * Checks an item to make sure it hasn't been overwritten since it was freed,
126a03c2393SAlexander Motin * prior to freeing it back to available memory.
1278efc4effSJeff Roberson *
1288efc4effSJeff Roberson * Complies with standard fini arg/return
1298efc4effSJeff Roberson */
1308efc4effSJeff Roberson void
trash_fini(void * mem,int size)1318efc4effSJeff Roberson trash_fini(void *mem, int size)
1328efc4effSJeff Roberson {
133b23f72e9SBrian Feldman (void)trash_ctor(mem, size, NULL, 0);
1348efc4effSJeff Roberson }
135639c9550SJeff Roberson
136a03c2393SAlexander Motin /*
137a03c2393SAlexander Motin * Checks an item to make sure it hasn't been overwritten since it was freed,
138a03c2393SAlexander Motin * prior to subsequent reallocation.
139a03c2393SAlexander Motin *
140a03c2393SAlexander Motin * Complies with standard ctor arg/return. arg should be zone pointer or NULL.
141a03c2393SAlexander Motin */
142b23f72e9SBrian Feldman int
mtrash_ctor(void * mem,int size,void * arg,int flags)143b23f72e9SBrian Feldman mtrash_ctor(void *mem, int size, void *arg, int flags)
1448f70816cSJeff Roberson {
145a03c2393SAlexander Motin struct uma_zone *zone = arg;
1467c566d6cSAlexander Motin u_long *p = mem, *e;
147a03c2393SAlexander Motin struct malloc_type **ksp;
148a03c2393SAlexander 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++) {
159a03c2393SAlexander Motin if (__predict_false(*p != uma_junk))
160a03c2393SAlexander Motin goto dopanic;
161a03c2393SAlexander Motin }
162a03c2393SAlexander Motin return (0);
163a03c2393SAlexander Motin
164a03c2393SAlexander Motin dopanic:
165a03c2393SAlexander Motin off = (uintptr_t)p - (uintptr_t)mem;
166a03c2393SAlexander Motin ksp = (struct malloc_type **)mem;
167a03c2393SAlexander Motin ksp += size / sizeof(struct malloc_type *);
168*f0fa4086SAlexander Motin if (*ksp != NULL
169*f0fa4086SAlexander Motin #ifdef INKERNEL
170*f0fa4086SAlexander Motin && INKERNEL((uintptr_t)*ksp)
171*f0fa4086SAlexander Motin #endif
172*f0fa4086SAlexander Motin ) {
173a03c2393SAlexander Motin /*
174a03c2393SAlexander Motin * If *ksp is corrupted we may be unable to panic clean,
175a03c2393SAlexander Motin * so print what we have reliably while we still can.
176a03c2393SAlexander Motin */
177a03c2393SAlexander Motin printf("Memory modified after free %p (%d, %s, %p) + %d = %lx\n",
178a03c2393SAlexander Motin mem, osize, zone ? zone->uz_name : "", *ksp, off, *p);
179a03c2393SAlexander Motin panic("Memory modified after free %p (%d, %s, %s) + %d = %lx\n",
180a03c2393SAlexander Motin mem, osize, zone ? zone->uz_name : "", (*ksp)->ks_shortdesc,
181a03c2393SAlexander Motin off, *p);
182a03c2393SAlexander Motin } else {
183a03c2393SAlexander Motin panic("Memory modified after free %p (%d, %s, %p) + %d = %lx\n",
184a03c2393SAlexander Motin mem, osize, zone ? zone->uz_name : "", *ksp, off, *p);
1858f70816cSJeff Roberson }
186b23f72e9SBrian Feldman return (0);
1878f70816cSJeff Roberson }
1888f70816cSJeff Roberson
1898f70816cSJeff Roberson /*
1908f70816cSJeff Roberson * Fills an item with predictable garbage
1918f70816cSJeff Roberson *
1928f70816cSJeff Roberson * Complies with standard dtor arg/return
1938f70816cSJeff Roberson */
1948f70816cSJeff Roberson void
mtrash_dtor(void * mem,int size,void * arg)1958f70816cSJeff Roberson mtrash_dtor(void *mem, int size, void *arg)
1968f70816cSJeff Roberson {
1977c566d6cSAlexander Motin u_long *p = mem, *e;
1988f70816cSJeff Roberson
199bc9d08e1SMark Johnston #ifdef DEBUG_MEMGUARD
200bc9d08e1SMark Johnston if (is_memguard_addr(mem))
201bc9d08e1SMark Johnston return;
202bc9d08e1SMark Johnston #endif
203bc9d08e1SMark Johnston
2048f70816cSJeff Roberson size -= sizeof(struct malloc_type *);
2058f70816cSJeff Roberson
2067c566d6cSAlexander Motin e = p + size / sizeof(*p);
2077c566d6cSAlexander Motin for (; p < e; p++)
2088f70816cSJeff Roberson *p = uma_junk;
2098f70816cSJeff Roberson }
2108f70816cSJeff Roberson
2118f70816cSJeff Roberson /*
2128f70816cSJeff Roberson * Fills an item with predictable garbage
2138f70816cSJeff Roberson *
2148f70816cSJeff Roberson * Complies with standard init arg/return
2158f70816cSJeff Roberson */
216b23f72e9SBrian Feldman int
mtrash_init(void * mem,int size,int flags)217b23f72e9SBrian Feldman mtrash_init(void *mem, int size, int flags)
2188f70816cSJeff Roberson {
2198f70816cSJeff Roberson struct malloc_type **ksp;
2208f70816cSJeff Roberson
221bc9d08e1SMark Johnston #ifdef DEBUG_MEMGUARD
222bc9d08e1SMark Johnston if (is_memguard_addr(mem))
223bc9d08e1SMark Johnston return (0);
224bc9d08e1SMark Johnston #endif
225bc9d08e1SMark Johnston
2268f70816cSJeff Roberson mtrash_dtor(mem, size, NULL);
2278f70816cSJeff Roberson
2288f70816cSJeff Roberson ksp = (struct malloc_type **)mem;
2298f70816cSJeff Roberson ksp += (size / sizeof(struct malloc_type *)) - 1;
2308f70816cSJeff Roberson *ksp = NULL;
231b23f72e9SBrian Feldman return (0);
2328f70816cSJeff Roberson }
2338f70816cSJeff Roberson
2348f70816cSJeff Roberson /*
235b23f72e9SBrian Feldman * Checks an item to make sure it hasn't been overwritten since it was freed,
236b23f72e9SBrian Feldman * prior to freeing it back to available memory.
2378f70816cSJeff Roberson *
2388f70816cSJeff Roberson * Complies with standard fini arg/return
2398f70816cSJeff Roberson */
2408f70816cSJeff Roberson void
mtrash_fini(void * mem,int size)2418f70816cSJeff Roberson mtrash_fini(void *mem, int size)
2428f70816cSJeff Roberson {
243b23f72e9SBrian Feldman (void)mtrash_ctor(mem, size, NULL, 0);
2448f70816cSJeff Roberson }
245