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