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 69 TAILQ_HEAD(object_q, vm_object); 70 71 struct nlist Nl[] = { 72 { "_vm_object_lists" }, 73 { "_nswdev" }, 74 { "_dmmax" }, 75 { NULL } 76 }; 77 78 int VerboseOpt; 79 int nswdev; 80 int dmmax; 81 int memfds = -1; 82 int *swapfds; 83 char pgbuf[PAGE_SIZE]; 84 85 static void scan_vmobjs(kvm_t *kd, struct object_q *obj_list); 86 static void dump_swap(kvm_t *kd, struct swblock *swbp); 87 static void dump_memq(kvm_t *kd, struct vm_page *pgp); 88 static void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes); 89 static off_t devoffset(long blkno, int *whichp); 90 91 int 92 main(int ac, char **av) 93 { 94 struct object_q obj_list[VMOBJ_HSIZE]; 95 kvm_t *kd; 96 int i; 97 int nswap; 98 int ch; 99 const char *corefile = NULL; 100 const char *sysfile = NULL; 101 102 while ((ch = getopt(ac, av, "M:N:v")) != -1) { 103 switch(ch) { 104 case 'M': 105 corefile = optarg; 106 break; 107 case 'N': 108 sysfile = optarg; 109 break; 110 case 'v': 111 ++VerboseOpt; 112 break; 113 default: 114 fprintf(stderr, "%s [-M core] [-N system]\n", av[0]); 115 exit(1); 116 } 117 } 118 if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) { 119 perror("kvm_open"); 120 exit(1); 121 } 122 if (kvm_nlist(kd, Nl) != 0) { 123 perror("kvm_nlist"); 124 exit(1); 125 } 126 kkread(kd, Nl[1].n_value, &nswdev, sizeof(nswdev)); 127 kkread(kd, Nl[2].n_value, &dmmax, sizeof(dmmax)); 128 129 if (VerboseOpt) { 130 swapfds = calloc(sizeof(int), nswdev); 131 for (i = 0; i < nswdev && i < ac - optind; ++i) { 132 printf("open %s\n", av[optind + i]); 133 swapfds[i] = open(av[optind + i], O_RDONLY); 134 } 135 while (i < nswdev) { 136 swapfds[i] = -1; 137 ++i; 138 } 139 memfds = open("/dev/mem", O_RDONLY); 140 } 141 142 kkread(kd, Nl[0].n_value, obj_list, sizeof(obj_list)); 143 for (i = 0; i < VMOBJ_HSIZE; ++i) 144 scan_vmobjs(kd, &obj_list[i]); 145 return(0); 146 } 147 148 static void 149 scan_vmobjs(kvm_t *kd, struct object_q *obj_list) 150 { 151 struct vm_object *op; 152 struct vm_object obj; 153 154 op = TAILQ_FIRST(obj_list); 155 while (op) { 156 kkread(kd, (long)op, &obj, sizeof(obj)); 157 158 printf("%p type=%d size=%016jx handle=%p swblocks=%d\n", 159 op, obj.type, (intmax_t)obj.size, obj.handle, 160 obj.swblock_count); 161 printf("\t\t ref_count=%d backing_obj=%p\n", 162 obj.ref_count, obj.backing_object); 163 164 if (VerboseOpt) { 165 dump_swap(kd, obj.swblock_root.rbh_root); 166 if (obj.type == OBJT_DEFAULT || obj.type == OBJT_SWAP) 167 dump_memq(kd, obj.rb_memq.rbh_root); 168 } 169 170 op = TAILQ_NEXT(&obj, object_list); 171 } 172 } 173 174 static void 175 dump_swap(kvm_t *kd, struct swblock *swbp) 176 { 177 struct swblock swb; 178 int which; 179 int i; 180 int j; 181 int k; 182 int fd; 183 off_t off; 184 185 if (swbp == NULL) 186 return; 187 kkread(kd, (long)swbp, &swb, sizeof(swb)); 188 dump_swap(kd, swb.swb_entry.rbe_left); 189 190 for (i = 0; i < SWAP_META_PAGES; ++i) { 191 printf(" %016lx: ", (swb.swb_index + i) * 4096L); 192 if (swb.swb_pages[i] == SWAPBLK_NONE) { 193 printf(" (unassigned)\n"); 194 continue; 195 } 196 printf(" %ld\n", swb.swb_pages[i]); 197 off = devoffset(swb.swb_pages[i], &which); 198 if (swapfds[which] >= 0) { 199 lseek(swapfds[which], off, 0); 200 if (read(swapfds[which], pgbuf, sizeof(pgbuf)) <= 0) 201 printf("\t(read failed)\n"); 202 else 203 for (j = 0; j < PAGE_SIZE; j += 16) { 204 printf("\t%04x ", j); 205 for (k = 0; k < 16; ++k) { 206 printf(" %02x", (uint8_t)pgbuf[j+k]); 207 if (k == 7) 208 printf(" "); 209 } 210 printf(" "); 211 for (k = 0; k < 16; ++k) { 212 if (isprint((uint8_t)pgbuf[j+k])) 213 printf("%c", pgbuf[j+k]); 214 else 215 printf("."); 216 } 217 printf("\n"); 218 } 219 } 220 } 221 222 dump_swap(kd, swb.swb_entry.rbe_right); 223 } 224 225 static void 226 dump_memq(kvm_t *kd, struct vm_page *pgp) 227 { 228 struct vm_page pg; 229 int j; 230 int k; 231 232 if (pgp == NULL) 233 return; 234 kkread(kd, (long)pgp, &pg, sizeof(pg)); 235 dump_memq(kd, pg.rb_entry.rbe_left); 236 printf(" %016lx: %016jx (physical)\n", 237 pg.pindex * 4096L, (intmax_t)pg.phys_addr); 238 lseek(memfds, pg.phys_addr, 0); 239 if (read(memfds, pgbuf, sizeof(pgbuf)) <= 0) { 240 printf("\t(read failed)\n"); 241 } else { 242 for (j = 0; j < PAGE_SIZE; j += 16) { 243 printf("\t%04x ", j); 244 for (k = 0; k < 16; ++k) { 245 printf(" %02x", (uint8_t)pgbuf[j+k]); 246 if (k == 7) 247 printf(" "); 248 } 249 printf(" "); 250 for (k = 0; k < 16; ++k) { 251 if (isprint((uint8_t)pgbuf[j+k])) 252 printf("%c", pgbuf[j+k]); 253 else 254 printf("."); 255 } 256 printf("\n"); 257 } 258 } 259 260 dump_memq(kd, pg.rb_entry.rbe_right); 261 } 262 263 static void 264 kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes) 265 { 266 if (kvm_read(kd, addr, buf, nbytes) != nbytes) { 267 perror("kvm_read"); 268 exit(1); 269 } 270 } 271 272 static off_t 273 devoffset(long blkno, int *whichp) 274 { 275 off_t off; 276 long seg; 277 278 if (nswdev > 1) { 279 off = blkno % dmmax; 280 seg = blkno / dmmax; 281 *whichp = seg % nswdev; 282 seg /= nswdev; 283 off = (off_t)(seg * dmmax + off) << PAGE_SHIFT; 284 } else { 285 *whichp = 0; 286 off = blkno * PAGE_SIZE; 287 } 288 } 289