#define _KERNEL_STRUCTURES
#include <sys/param.h>
#include <sys/user.h>
#include <sys/malloc.h>
#include <sys/signalvar.h>
#include <sys/namecache.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/buf.h>
#include <vm/vm.h>
#include <vm/vm_page.h>
#include <vm/vm_kern.h>
#include <vm/vm_object.h>
#include <vm/swap_pager.h>
#include <vm/vnode_pager.h>
#include <vfs/ufs/quota.h>
#include <vfs/ufs/inode.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <kvm.h>
#include <nlist.h>
#include <getopt.h>
#include <ctype.h>
TAILQ_HEAD(object_q, vm_object);
struct nlist Nl[] = {
{ "_vm_object_lists" },
{ "_nswdev" },
{ "_dmmax" },
{ NULL }
};
int VerboseOpt;
int nswdev;
int dmmax;
int memfds = -1;
int *swapfds;
char pgbuf[PAGE_SIZE];
static void scan_vmobjs(kvm_t *kd, struct object_q *obj_list);
static void dump_swap(kvm_t *kd, struct swblock *swbp);
static void dump_memq(kvm_t *kd, struct vm_page *pgp);
static void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes);
static off_t devoffset(long blkno, int *whichp);
int
main(int ac, char **av)
{
struct object_q obj_list[VMOBJ_HSIZE];
kvm_t *kd;
int i;
int nswap;
int ch;
const char *corefile = NULL;
const char *sysfile = NULL;
while ((ch = getopt(ac, av, "M:N:v")) != -1) {
switch(ch) {
case 'M':
corefile = optarg;
break;
case 'N':
sysfile = optarg;
break;
case 'v':
++VerboseOpt;
break;
default:
fprintf(stderr, "%s [-M core] [-N system]\n", av[0]);
exit(1);
}
}
if ((kd = kvm_open(sysfile, corefile, NULL, O_RDONLY, "kvm:")) == NULL) {
perror("kvm_open");
exit(1);
}
if (kvm_nlist(kd, Nl) != 0) {
perror("kvm_nlist");
exit(1);
}
kkread(kd, Nl[1].n_value, &nswdev, sizeof(nswdev));
kkread(kd, Nl[2].n_value, &dmmax, sizeof(dmmax));
if (VerboseOpt) {
swapfds = calloc(sizeof(int), nswdev);
for (i = 0; i < nswdev && i < ac - optind; ++i) {
printf("open %s\n", av[optind + i]);
swapfds[i] = open(av[optind + i], O_RDONLY);
}
while (i < nswdev) {
swapfds[i] = -1;
++i;
}
memfds = open("/dev/mem", O_RDONLY);
}
kkread(kd, Nl[0].n_value, obj_list, sizeof(obj_list));
for (i = 0; i < VMOBJ_HSIZE; ++i)
scan_vmobjs(kd, &obj_list[i]);
return(0);
}
static void
scan_vmobjs(kvm_t *kd, struct object_q *obj_list)
{
struct vm_object *op;
struct vm_object obj;
op = TAILQ_FIRST(obj_list);
while (op) {
kkread(kd, (long)op, &obj, sizeof(obj));
printf("%p type=%d size=%016jx handle=%p swblocks=%d\n",
op, obj.type, (intmax_t)obj.size, obj.handle,
obj.swblock_count);
printf("\t\t ref_count=%d backing_obj=%p\n",
obj.ref_count, obj.backing_object);
if (VerboseOpt) {
dump_swap(kd, obj.swblock_root.rbh_root);
if (obj.type == OBJT_DEFAULT || obj.type == OBJT_SWAP)
dump_memq(kd, obj.rb_memq.rbh_root);
}
op = TAILQ_NEXT(&obj, object_list);
}
}
static void
dump_swap(kvm_t *kd, struct swblock *swbp)
{
struct swblock swb;
int which;
int i;
int j;
int k;
int fd;
off_t off;
if (swbp == NULL)
return;
kkread(kd, (long)swbp, &swb, sizeof(swb));
dump_swap(kd, swb.swb_entry.rbe_left);
for (i = 0; i < SWAP_META_PAGES; ++i) {
printf(" %016lx: ", (swb.swb_index + i) * 4096L);
if (swb.swb_pages[i] == SWAPBLK_NONE) {
printf(" (unassigned)\n");
continue;
}
printf(" %ld\n", swb.swb_pages[i]);
off = devoffset(swb.swb_pages[i], &which);
if (swapfds[which] >= 0) {
lseek(swapfds[which], off, 0);
if (read(swapfds[which], pgbuf, sizeof(pgbuf)) <= 0)
printf("\t(read failed)\n");
else
for (j = 0; j < PAGE_SIZE; j += 16) {
printf("\t%04x ", j);
for (k = 0; k < 16; ++k) {
printf(" %02x", (uint8_t)pgbuf[j+k]);
if (k == 7)
printf(" ");
}
printf(" ");
for (k = 0; k < 16; ++k) {
if (isprint((uint8_t)pgbuf[j+k]))
printf("%c", pgbuf[j+k]);
else
printf(".");
}
printf("\n");
}
}
}
dump_swap(kd, swb.swb_entry.rbe_right);
}
static void
dump_memq(kvm_t *kd, struct vm_page *pgp)
{
struct vm_page pg;
int j;
int k;
if (pgp == NULL)
return;
kkread(kd, (long)pgp, &pg, sizeof(pg));
dump_memq(kd, pg.rb_entry.rbe_left);
printf(" %016lx: %016jx (physical)\n",
pg.pindex * 4096L, (intmax_t)pg.phys_addr);
lseek(memfds, pg.phys_addr, 0);
if (read(memfds, pgbuf, sizeof(pgbuf)) <= 0) {
printf("\t(read failed)\n");
} else {
for (j = 0; j < PAGE_SIZE; j += 16) {
printf("\t%04x ", j);
for (k = 0; k < 16; ++k) {
printf(" %02x", (uint8_t)pgbuf[j+k]);
if (k == 7)
printf(" ");
}
printf(" ");
for (k = 0; k < 16; ++k) {
if (isprint((uint8_t)pgbuf[j+k]))
printf("%c", pgbuf[j+k]);
else
printf(".");
}
printf("\n");
}
}
dump_memq(kd, pg.rb_entry.rbe_right);
}
static void
kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes)
{
if (kvm_read(kd, addr, buf, nbytes) != nbytes) {
perror("kvm_read");
exit(1);
}
}
static off_t
devoffset(long blkno, int *whichp)
{
off_t off;
long seg;
if (nswdev > 1) {
off = blkno % dmmax;
seg = blkno / dmmax;
*whichp = seg % nswdev;
seg /= nswdev;
off = (off_t)(seg * dmmax + off) << PAGE_SHIFT;
} else {
*whichp = 0;
off = blkno * PAGE_SIZE;
}
}