1 /* 2 * VMPAGEINFO.C 3 * 4 * cc -I/usr/src/sys vmpageinfo.c -o /usr/local/bin/vmpageinfo -lkvm 5 * 6 * vmpageinfo 7 * 8 * Validate the vm_page_buckets[] hash array against the vm_page_array 9 * 10 * 11 * Copyright (c) 2004 The DragonFly Project. All rights reserved. 12 * 13 * This code is derived from software contributed to The DragonFly Project 14 * by Matthew Dillon <dillon@backplane.com> 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in 24 * the documentation and/or other materials provided with the 25 * distribution. 26 * 3. Neither the name of The DragonFly Project nor the names of its 27 * contributors may be used to endorse or promote products derived 28 * from this software without specific, prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 33 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 34 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 35 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 36 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 38 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 39 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 40 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 41 * SUCH DAMAGE. 42 * 43 * $DragonFly: src/test/debug/vmpageinfo.c,v 1.1 2004/11/09 21:50:12 dillon Exp $ 44 */ 45 46 #define _KERNEL_STRUCTURES_ 47 #include <sys/param.h> 48 #include <sys/user.h> 49 #include <sys/malloc.h> 50 #include <sys/signalvar.h> 51 #include <sys/vnode.h> 52 #include <sys/namecache.h> 53 54 #include <vm/vm.h> 55 #include <vm/vm_page.h> 56 #include <vm/vm_kern.h> 57 #include <vm/vm_page.h> 58 #include <vm/vm_object.h> 59 #include <vm/swap_pager.h> 60 #include <vm/vnode_pager.h> 61 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <fcntl.h> 66 #include <kvm.h> 67 #include <nlist.h> 68 #include <getopt.h> 69 70 struct nlist Nl[] = { 71 { "_vm_page_buckets" }, 72 { "_vm_page_hash_mask" }, 73 { "_vm_page_array" }, 74 { "_vm_page_array_size" }, 75 { NULL } 76 }; 77 78 int debugopt; 79 struct vm_page **vm_page_buckets; 80 int vm_page_hash_mask; 81 struct vm_page *vm_page_array; 82 int vm_page_array_size; 83 84 void checkpage(kvm_t *kd, vm_page_t mptr, vm_page_t m, struct vm_object *obj); 85 void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes); 86 87 int 88 main(int ac, char **av) 89 { 90 const char *corefile = NULL; 91 const char *sysfile = NULL; 92 vm_page_t mptr; 93 struct vm_page m; 94 struct vm_object obj; 95 kvm_t *kd; 96 int ch; 97 int hv; 98 int i; 99 100 while ((ch = getopt(ac, av, "M:N:d")) != -1) { 101 switch(ch) { 102 case 'd': 103 ++debugopt; 104 break; 105 case 'M': 106 corefile = optarg; 107 break; 108 case 'N': 109 sysfile = optarg; 110 break; 111 default: 112 fprintf(stderr, "%s [-M core] [-N system]\n", av[0]); 113 exit(1); 114 } 115 } 116 ac -= optind; 117 av += optind; 118 119 if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) { 120 perror("kvm_open"); 121 exit(1); 122 } 123 if (kvm_nlist(kd, Nl) != 0) { 124 perror("kvm_nlist"); 125 exit(1); 126 } 127 128 kkread(kd, Nl[0].n_value, &vm_page_buckets, sizeof(vm_page_buckets)); 129 kkread(kd, Nl[1].n_value, &vm_page_hash_mask, sizeof(vm_page_hash_mask)); 130 kkread(kd, Nl[2].n_value, &vm_page_array, sizeof(vm_page_array)); 131 kkread(kd, Nl[3].n_value, &vm_page_array_size, sizeof(vm_page_array_size)); 132 133 /* 134 * Scan the vm_page_array validating all pages with associated objects 135 */ 136 for (i = 0; i < vm_page_array_size; ++i) { 137 if (debugopt) { 138 printf("page %d\r", i); 139 fflush(stdout); 140 } 141 kkread(kd, (u_long)&vm_page_array[i], &m, sizeof(m)); 142 if (m.object) { 143 kkread(kd, (u_long)m.object, &obj, sizeof(obj)); 144 checkpage(kd, &vm_page_array[i], &m, &obj); 145 } 146 } 147 if (debugopt) 148 printf("\n"); 149 150 /* 151 * Scan the vm_page_buckets array validating all pages found 152 */ 153 for (i = 0; i <= vm_page_hash_mask; ++i) { 154 if (debugopt) { 155 printf("index %d\r", i); 156 fflush(stdout); 157 } 158 kkread(kd, (u_long)&vm_page_buckets[i], &mptr, sizeof(mptr)); 159 while (mptr) { 160 kkread(kd, (u_long)mptr, &m, sizeof(m)); 161 if (m.object) { 162 kkread(kd, (u_long)m.object, &obj, sizeof(obj)); 163 hv = ((uintptr_t)m.object + m.pindex) ^ obj.hash_rand; 164 hv &= vm_page_hash_mask; 165 if (i != hv) 166 printf("vm_page_buckets[%d] ((struct vm_page *)%p)" 167 " should be in bucket %d\n", i, mptr, hv); 168 checkpage(kd, mptr, &m, &obj); 169 } else { 170 printf("vm_page_buckets[%d] ((struct vm_page *)%p)" 171 " has no object\n", i, mptr); 172 } 173 mptr = m.hnext; 174 } 175 } 176 if (debugopt) 177 printf("\n"); 178 return(0); 179 } 180 181 /* 182 * A page with an object. 183 */ 184 void 185 checkpage(kvm_t *kd, vm_page_t mptr, vm_page_t m, struct vm_object *obj) 186 { 187 struct vm_page scan; 188 vm_page_t scanptr; 189 int hv; 190 191 hv = ((uintptr_t)m->object + m->pindex) ^ obj->hash_rand; 192 hv &= vm_page_hash_mask; 193 kkread(kd, (u_long)&vm_page_buckets[hv], &scanptr, sizeof(scanptr)); 194 while (scanptr) { 195 if (scanptr == mptr) 196 break; 197 kkread(kd, (u_long)scanptr, &scan, sizeof(scan)); 198 scanptr = scan.hnext; 199 } 200 if (scanptr) { 201 if (debugopt > 1) 202 printf("good checkpage %p bucket %d\n", mptr, hv); 203 } else { 204 printf("vm_page_buckets[%d] ((struct vm_page *)%p)" 205 " page not found in bucket list\n", hv, mptr); 206 } 207 } 208 209 void 210 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 211 { 212 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 213 perror("kvm_read"); 214 exit(1); 215 } 216 } 217 218