1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2002, 2003, 2004, 2005 Jeffrey Roberson <jeff@FreeBSD.org> 5 * Copyright (c) 2004, 2005 Bosko Milekic <bmilekic@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice unmodified, this list of conditions, and the following 13 * disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * uma_dbg.c Debugging features for UMA users 32 * 33 */ 34 35 #include <sys/cdefs.h> 36 #include "opt_vm.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/bitset.h> 41 #include <sys/kernel.h> 42 #include <sys/types.h> 43 #include <sys/queue.h> 44 #include <sys/lock.h> 45 #include <sys/mutex.h> 46 #include <sys/malloc.h> 47 48 #include <vm/vm.h> 49 #include <vm/vm_object.h> 50 #include <vm/vm_page.h> 51 #include <vm/uma.h> 52 #include <vm/uma_int.h> 53 #include <vm/uma_dbg.h> 54 #include <vm/memguard.h> 55 56 #include <machine/stack.h> 57 58 static const u_long uma_junk = (u_long)0xdeadc0dedeadc0de; 59 60 /* 61 * Checks an item to make sure it hasn't been overwritten since it was freed, 62 * prior to subsequent reallocation. 63 * 64 * Complies with standard ctor arg/return. arg should be zone pointer or NULL. 65 */ 66 int 67 trash_ctor(void *mem, int size, void *arg, int flags) 68 { 69 struct uma_zone *zone = arg; 70 u_long *p = mem, *e; 71 int off; 72 73 #ifdef DEBUG_MEMGUARD 74 if (is_memguard_addr(mem)) 75 return (0); 76 #endif 77 78 e = p + size / sizeof(*p); 79 for (; p < e; p++) { 80 if (__predict_false(*p != uma_junk)) 81 goto dopanic; 82 } 83 return (0); 84 85 dopanic: 86 off = (uintptr_t)p - (uintptr_t)mem; 87 panic("Memory modified after free %p (%d, %s) + %d = %lx\n", 88 mem, size, zone ? zone->uz_name : "", off, *p); 89 return (0); 90 } 91 92 /* 93 * Fills an item with predictable garbage 94 * 95 * Complies with standard dtor arg/return 96 */ 97 void 98 trash_dtor(void *mem, int size, void *arg) 99 { 100 u_long *p = mem, *e; 101 102 #ifdef DEBUG_MEMGUARD 103 if (is_memguard_addr(mem)) 104 return; 105 #endif 106 107 e = p + size / sizeof(*p); 108 for (; p < e; p++) 109 *p = uma_junk; 110 } 111 112 /* 113 * Fills an item with predictable garbage 114 * 115 * Complies with standard init arg/return 116 */ 117 int 118 trash_init(void *mem, int size, int flags) 119 { 120 trash_dtor(mem, size, NULL); 121 return (0); 122 } 123 124 /* 125 * Checks an item to make sure it hasn't been overwritten since it was freed, 126 * prior to freeing it back to available memory. 127 * 128 * Complies with standard fini arg/return 129 */ 130 void 131 trash_fini(void *mem, int size) 132 { 133 (void)trash_ctor(mem, size, NULL, 0); 134 } 135 136 /* 137 * Checks an item to make sure it hasn't been overwritten since it was freed, 138 * prior to subsequent reallocation. 139 * 140 * Complies with standard ctor arg/return. arg should be zone pointer or NULL. 141 */ 142 int 143 mtrash_ctor(void *mem, int size, void *arg, int flags) 144 { 145 struct uma_zone *zone = arg; 146 u_long *p = mem, *e; 147 struct malloc_type **ksp; 148 int off, osize = size; 149 150 #ifdef DEBUG_MEMGUARD 151 if (is_memguard_addr(mem)) 152 return (0); 153 #endif 154 155 size -= sizeof(struct malloc_type *); 156 157 e = p + size / sizeof(*p); 158 for (; p < e; p++) { 159 if (__predict_false(*p != uma_junk)) 160 goto dopanic; 161 } 162 return (0); 163 164 dopanic: 165 off = (uintptr_t)p - (uintptr_t)mem; 166 ksp = (struct malloc_type **)mem; 167 ksp += size / sizeof(struct malloc_type *); 168 if (*ksp != NULL 169 #ifdef INKERNEL 170 && INKERNEL((uintptr_t)*ksp) 171 #endif 172 ) { 173 /* 174 * If *ksp is corrupted we may be unable to panic clean, 175 * so print what we have reliably while we still can. 176 */ 177 printf("Memory modified after free %p (%d, %s, %p) + %d = %lx\n", 178 mem, osize, zone ? zone->uz_name : "", *ksp, off, *p); 179 panic("Memory modified after free %p (%d, %s, %s) + %d = %lx\n", 180 mem, osize, zone ? zone->uz_name : "", (*ksp)->ks_shortdesc, 181 off, *p); 182 } else { 183 panic("Memory modified after free %p (%d, %s, %p) + %d = %lx\n", 184 mem, osize, zone ? zone->uz_name : "", *ksp, off, *p); 185 } 186 return (0); 187 } 188 189 /* 190 * Fills an item with predictable garbage 191 * 192 * Complies with standard dtor arg/return 193 */ 194 void 195 mtrash_dtor(void *mem, int size, void *arg) 196 { 197 u_long *p = mem, *e; 198 199 #ifdef DEBUG_MEMGUARD 200 if (is_memguard_addr(mem)) 201 return; 202 #endif 203 204 size -= sizeof(struct malloc_type *); 205 206 e = p + size / sizeof(*p); 207 for (; p < e; p++) 208 *p = uma_junk; 209 } 210 211 /* 212 * Fills an item with predictable garbage 213 * 214 * Complies with standard init arg/return 215 */ 216 int 217 mtrash_init(void *mem, int size, int flags) 218 { 219 struct malloc_type **ksp; 220 221 #ifdef DEBUG_MEMGUARD 222 if (is_memguard_addr(mem)) 223 return (0); 224 #endif 225 226 mtrash_dtor(mem, size, NULL); 227 228 ksp = (struct malloc_type **)mem; 229 ksp += (size / sizeof(struct malloc_type *)) - 1; 230 *ksp = NULL; 231 return (0); 232 } 233 234 /* 235 * Checks an item to make sure it hasn't been overwritten since it was freed, 236 * prior to freeing it back to available memory. 237 * 238 * Complies with standard fini arg/return 239 */ 240 void 241 mtrash_fini(void *mem, int size) 242 { 243 (void)mtrash_ctor(mem, size, NULL, 0); 244 } 245