1 /* 2 * VMOBJINFO.C 3 * 4 * cc -I/usr/src/sys vmobjinfo.c -o ~/bin/vmobjinfo -lkvm 5 * 6 * Dump all vm_object's in the system 7 * 8 * Copyright (c) 2010 The DragonFly Project. All rights reserved. 9 * 10 * This code is derived from software contributed to The DragonFly Project 11 * by Matthew Dillon <dillon@backplane.com> 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in 21 * the documentation and/or other materials provided with the 22 * distribution. 23 * 3. Neither the name of The DragonFly Project nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific, prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 31 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 32 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 33 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 35 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 37 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 41 #define _KERNEL_STRUCTURES 42 #include <sys/param.h> 43 #include <sys/user.h> 44 #include <sys/malloc.h> 45 #include <sys/signalvar.h> 46 #include <sys/namecache.h> 47 #include <sys/mount.h> 48 #include <sys/vnode.h> 49 #include <sys/buf.h> 50 51 #include <vm/vm.h> 52 #include <vm/vm_page.h> 53 #include <vm/vm_kern.h> 54 #include <vm/vm_object.h> 55 #include <vm/swap_pager.h> 56 #include <vm/vnode_pager.h> 57 58 #include <vfs/ufs/quota.h> 59 #include <vfs/ufs/inode.h> 60 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 #include <fcntl.h> 65 #include <kvm.h> 66 #include <nlist.h> 67 #include <getopt.h> 68 #include <ctype.h> 69 70 TAILQ_HEAD(object_q, vm_object); 71 72 struct nlist Nl[] = { 73 { "_vm_object_lists" }, 74 { "_nswdev" }, 75 { "_dmmax" }, 76 { NULL } 77 }; 78 79 int VerboseOpt; 80 int nswdev; 81 int dmmax; 82 int memfds = -1; 83 int *swapfds; 84 char pgbuf[PAGE_SIZE]; 85 86 static void scan_vmobjs(kvm_t *kd, struct object_q *obj_list); 87 static void dump_swap(kvm_t *kd, struct swblock *swbp); 88 static void dump_memq(kvm_t *kd, struct vm_page *pgp); 89 static void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes); 90 static off_t devoffset(long blkno, int *whichp); 91 92 int 93 main(int ac, char **av) 94 { 95 struct object_q obj_list[VMOBJ_HSIZE]; 96 kvm_t *kd; 97 int i; 98 int nswap; 99 int ch; 100 const char *corefile = NULL; 101 const char *sysfile = NULL; 102 103 while ((ch = getopt(ac, av, "M:N:v")) != -1) { 104 switch(ch) { 105 case 'M': 106 corefile = optarg; 107 break; 108 case 'N': 109 sysfile = optarg; 110 break; 111 case 'v': 112 ++VerboseOpt; 113 break; 114 default: 115 fprintf(stderr, "%s [-M core] [-N system]\n", av[0]); 116 exit(1); 117 } 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 kkread(kd, Nl[1].n_value, &nswdev, sizeof(nswdev)); 128 kkread(kd, Nl[2].n_value, &dmmax, sizeof(dmmax)); 129 130 if (VerboseOpt) { 131 swapfds = calloc(sizeof(int), nswdev); 132 for (i = 0; i < nswdev && i < ac - optind; ++i) { 133 printf("open %s\n", av[optind + i]); 134 swapfds[i] = open(av[optind + i], O_RDONLY); 135 } 136 while (i < nswdev) { 137 swapfds[i] = -1; 138 ++i; 139 } 140 memfds = open("/dev/mem", O_RDONLY); 141 } 142 143 kkread(kd, Nl[0].n_value, obj_list, sizeof(obj_list)); 144 for (i = 0; i < VMOBJ_HSIZE; ++i) 145 scan_vmobjs(kd, &obj_list[i]); 146 return(0); 147 } 148 149 static void 150 scan_vmobjs(kvm_t *kd, struct object_q *obj_list) 151 { 152 struct vm_object *op; 153 struct vm_object obj; 154 155 op = TAILQ_FIRST(obj_list); 156 while (op) { 157 kkread(kd, (long)op, &obj, sizeof(obj)); 158 159 printf("%p type=%d size=%016jx handle=%p swblocks=%d\n", 160 op, obj.type, (intmax_t)obj.size, obj.handle, 161 obj.swblock_count); 162 printf("\t\t ref_count=%d backing_obj=%p\n", 163 obj.ref_count, obj.backing_object); 164 165 if (VerboseOpt) { 166 dump_swap(kd, obj.swblock_root.rbh_root); 167 if (obj.type == OBJT_DEFAULT || obj.type == OBJT_SWAP) 168 dump_memq(kd, obj.rb_memq.rbh_root); 169 } 170 171 op = TAILQ_NEXT(&obj, object_list); 172 } 173 } 174 175 static void 176 dump_swap(kvm_t *kd, struct swblock *swbp) 177 { 178 struct swblock swb; 179 int which; 180 int i; 181 int j; 182 int k; 183 int fd; 184 off_t off; 185 186 if (swbp == NULL) 187 return; 188 kkread(kd, (long)swbp, &swb, sizeof(swb)); 189 dump_swap(kd, swb.swb_entry.rbe_left); 190 191 for (i = 0; i < SWAP_META_PAGES; ++i) { 192 printf(" %016lx: ", (swb.swb_index + i) * 4096L); 193 if (swb.swb_pages[i] == SWAPBLK_NONE) { 194 printf(" (unassigned)\n"); 195 continue; 196 } 197 printf(" %ld\n", swb.swb_pages[i]); 198 off = devoffset(swb.swb_pages[i], &which); 199 if (swapfds[which] >= 0) { 200 lseek(swapfds[which], off, 0); 201 if (read(swapfds[which], pgbuf, sizeof(pgbuf)) <= 0) 202 printf("\t(read failed)\n"); 203 else 204 for (j = 0; j < PAGE_SIZE; j += 16) { 205 printf("\t%04x ", j); 206 for (k = 0; k < 16; ++k) { 207 printf(" %02x", (uint8_t)pgbuf[j+k]); 208 if (k == 7) 209 printf(" "); 210 } 211 printf(" "); 212 for (k = 0; k < 16; ++k) { 213 if (isprint((uint8_t)pgbuf[j+k])) 214 printf("%c", pgbuf[j+k]); 215 else 216 printf("."); 217 } 218 printf("\n"); 219 } 220 } 221 } 222 223 dump_swap(kd, swb.swb_entry.rbe_right); 224 } 225 226 static void 227 dump_memq(kvm_t *kd, struct vm_page *pgp) 228 { 229 struct vm_page pg; 230 int j; 231 int k; 232 233 if (pgp == NULL) 234 return; 235 kkread(kd, (long)pgp, &pg, sizeof(pg)); 236 dump_memq(kd, pg.rb_entry.rbe_left); 237 printf(" %016lx: %016jx (physical)\n", 238 pg.pindex * 4096L, (intmax_t)pg.phys_addr); 239 lseek(memfds, pg.phys_addr, 0); 240 if (read(memfds, pgbuf, sizeof(pgbuf)) <= 0) { 241 printf("\t(read failed)\n"); 242 } else { 243 for (j = 0; j < PAGE_SIZE; j += 16) { 244 printf("\t%04x ", j); 245 for (k = 0; k < 16; ++k) { 246 printf(" %02x", (uint8_t)pgbuf[j+k]); 247 if (k == 7) 248 printf(" "); 249 } 250 printf(" "); 251 for (k = 0; k < 16; ++k) { 252 if (isprint((uint8_t)pgbuf[j+k])) 253 printf("%c", pgbuf[j+k]); 254 else 255 printf("."); 256 } 257 printf("\n"); 258 } 259 } 260 261 dump_memq(kd, pg.rb_entry.rbe_right); 262 } 263 264 static void 265 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 266 { 267 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 268 perror("kvm_read"); 269 exit(1); 270 } 271 } 272 273 static off_t 274 devoffset(long blkno, int *whichp) 275 { 276 off_t off; 277 long seg; 278 279 if (nswdev > 1) { 280 off = blkno % dmmax; 281 seg = blkno / dmmax; 282 *whichp = seg % nswdev; 283 seg /= nswdev; 284 off = (off_t)(seg * dmmax + off) << PAGE_SHIFT; 285 } else { 286 *whichp = 0; 287 off = blkno * PAGE_SIZE; 288 } 289 } 290