1 1.7 ad /* $NetBSD: subr_debug.c,v 1.7 2008/04/30 20:20:53 ad Exp $ */ 2 1.2 ad 3 1.2 ad /*- 4 1.7 ad * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc. 5 1.2 ad * All rights reserved. 6 1.2 ad * 7 1.2 ad * This code is derived from software contributed to The NetBSD Foundation 8 1.2 ad * by Andrew Doran. 9 1.2 ad * 10 1.2 ad * Redistribution and use in source and binary forms, with or without 11 1.2 ad * modification, are permitted provided that the following conditions 12 1.2 ad * are met: 13 1.2 ad * 1. Redistributions of source code must retain the above copyright 14 1.2 ad * notice, this list of conditions and the following disclaimer. 15 1.2 ad * 2. Redistributions in binary form must reproduce the above copyright 16 1.2 ad * notice, this list of conditions and the following disclaimer in the 17 1.2 ad * documentation and/or other materials provided with the distribution. 18 1.2 ad * 19 1.2 ad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.2 ad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.2 ad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.2 ad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.2 ad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.2 ad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.2 ad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.2 ad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.2 ad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.2 ad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.2 ad * POSSIBILITY OF SUCH DAMAGE. 30 1.2 ad */ 31 1.2 ad 32 1.2 ad /* 33 1.2 ad * Shared support code for kernels built with the DEBUG option. 34 1.2 ad */ 35 1.2 ad 36 1.2 ad #include <sys/cdefs.h> 37 1.7 ad __KERNEL_RCSID(0, "$NetBSD: subr_debug.c,v 1.7 2008/04/30 20:20:53 ad Exp $"); 38 1.2 ad 39 1.2 ad #include "opt_ddb.h" 40 1.2 ad 41 1.2 ad #include <sys/param.h> 42 1.2 ad #include <sys/proc.h> 43 1.2 ad #include <sys/systm.h> 44 1.2 ad #include <sys/kmem.h> 45 1.2 ad #include <sys/debug.h> 46 1.7 ad #include <sys/atomic.h> 47 1.7 ad #include <sys/cpu.h> 48 1.2 ad 49 1.2 ad #include <uvm/uvm_extern.h> 50 1.2 ad 51 1.2 ad #include <machine/lock.h> 52 1.2 ad 53 1.2 ad /* 54 1.2 ad * Allocation/free validation by pointer address. Introduces 55 1.2 ad * significant overhead and is not enabled by default. Patch 56 1.2 ad * `debug_freecheck' to 1 at boot time to enable. 57 1.2 ad */ 58 1.2 ad #define FREECHECK_BYTES (8*1024*1024) 59 1.2 ad 60 1.2 ad typedef struct fcitem { 61 1.2 ad void *i_addr; 62 1.2 ad struct fcitem *i_next; 63 1.2 ad } fcitem_t; 64 1.2 ad 65 1.2 ad fcitem_t *freecheck_free; 66 1.2 ad __cpu_simple_lock_t freecheck_lock; 67 1.7 ad u_int debug_freecheck; 68 1.2 ad 69 1.2 ad void 70 1.2 ad debug_init(void) 71 1.2 ad { 72 1.2 ad size_t cnt; 73 1.2 ad fcitem_t *i; 74 1.2 ad 75 1.2 ad __cpu_simple_lock_init(&freecheck_lock); 76 1.2 ad 77 1.2 ad if (debug_freecheck) { 78 1.2 ad i = (fcitem_t *)uvm_km_alloc(kernel_map, FREECHECK_BYTES, 0, 79 1.2 ad UVM_KMF_WIRED); 80 1.2 ad if (i == NULL) { 81 1.2 ad printf("freecheck_init: unable to allocate memory"); 82 1.2 ad return; 83 1.2 ad } 84 1.2 ad 85 1.2 ad for (cnt = FREECHECK_BYTES / sizeof(*i); cnt != 0; cnt--) { 86 1.2 ad i->i_next = freecheck_free; 87 1.2 ad freecheck_free = i++; 88 1.2 ad } 89 1.2 ad } 90 1.2 ad } 91 1.2 ad 92 1.2 ad void 93 1.2 ad freecheck_out(void **head, void *addr) 94 1.2 ad { 95 1.2 ad fcitem_t *i; 96 1.2 ad int s; 97 1.2 ad 98 1.2 ad if (!debug_freecheck) 99 1.2 ad return; 100 1.2 ad 101 1.2 ad s = splvm(); 102 1.2 ad __cpu_simple_lock(&freecheck_lock); 103 1.3 ad for (i = *head; i != NULL; i = i->i_next) { 104 1.3 ad if (i->i_addr != addr) 105 1.3 ad continue; 106 1.3 ad __cpu_simple_unlock(&freecheck_lock); 107 1.3 ad splx(s); 108 1.3 ad panic("freecheck_out: %p already out", addr); 109 1.3 ad } 110 1.2 ad if ((i = freecheck_free) != NULL) { 111 1.2 ad freecheck_free = i->i_next; 112 1.2 ad i->i_addr = addr; 113 1.2 ad i->i_next = *head; 114 1.2 ad *head = i; 115 1.2 ad } 116 1.2 ad __cpu_simple_unlock(&freecheck_lock); 117 1.2 ad splx(s); 118 1.2 ad 119 1.2 ad if (i == NULL) { 120 1.7 ad if (atomic_swap_uint(&debug_freecheck, 1) == 0) 121 1.7 ad printf("freecheck_out: no more slots\n"); 122 1.2 ad } 123 1.2 ad } 124 1.2 ad 125 1.2 ad void 126 1.2 ad freecheck_in(void **head, void *addr) 127 1.2 ad { 128 1.2 ad fcitem_t *i; 129 1.2 ad void *pp; 130 1.2 ad int s; 131 1.2 ad 132 1.2 ad if (!debug_freecheck) 133 1.2 ad return; 134 1.2 ad 135 1.2 ad s = splvm(); 136 1.2 ad __cpu_simple_lock(&freecheck_lock); 137 1.2 ad for (i = *head, pp = head; i != NULL; pp = &i->i_next, i = i->i_next) { 138 1.2 ad if (i->i_addr == addr) { 139 1.2 ad *(fcitem_t **)pp = i->i_next; 140 1.2 ad i->i_next = freecheck_free; 141 1.2 ad freecheck_free = i; 142 1.2 ad break; 143 1.2 ad } 144 1.2 ad } 145 1.2 ad __cpu_simple_unlock(&freecheck_lock); 146 1.2 ad splx(s); 147 1.2 ad 148 1.2 ad if (i != NULL) 149 1.2 ad return; 150 1.2 ad 151 1.2 ad #ifdef DDB 152 1.5 yamt printf("freecheck_in: %p not out\n", addr); 153 1.2 ad Debugger(); 154 1.2 ad #else 155 1.2 ad panic("freecheck_in: %p not out", addr); 156 1.2 ad #endif 157 1.2 ad } 158