xref: /dragonfly/test/debug/vmobjinfo.c (revision 0ca59c34)
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