xref: /dragonfly/test/debug/vmobjinfo.c (revision 8835adf8d6f12ed2e2bc71c55e928e81ae0339c0)
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
main(int ac,char ** av)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
scan_vmobjs(kvm_t * kd,struct object_q * obj_list)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
dump_swap(kvm_t * kd,struct swblock * swbp)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
dump_memq(kvm_t * kd,struct vm_page * pgp)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
kkread(kvm_t * kd,u_long addr,void * buf,size_t nbytes)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
devoffset(long blkno,int * whichp)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