#define _KERNEL_STRUCTURES_
#include <sys/param.h>
#include <sys/user.h>
#include <sys/malloc.h>
#include <sys/slaballoc.h>
#include <sys/signalvar.h>
#include <sys/globaldata.h>
#include <machine/globaldata.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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <fcntl.h>
#include <kvm.h>
#include <nlist.h>
#include <err.h>
#include <getopt.h>
struct nlist Nl[] = {
{ "_CPU_prvspace" },
{ "_ncpus" },
{ NULL }
};
int debugopt;
int verboseopt;
static void dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab);
static void kkread(kvm_t *kd, u_long addr, void *buf, size_t nbytes);
int
main(int ac, char **av)
{
const char *corefile = NULL;
const char *sysfile = NULL;
struct SLGlobalData slab;
u_long baseptr;
kvm_t *kd;
int ncpus;
int ch;
int cpu;
while ((ch = getopt(ac, av, "M:N:dv")) != -1) {
switch(ch) {
case 'd':
++debugopt;
break;
case 'v':
++verboseopt;
break;
case 'M':
corefile = optarg;
break;
case 'N':
sysfile = optarg;
break;
default:
fprintf(stderr, "%s [-M core] [-N system]\n", av[0]);
exit(1);
}
}
ac -= optind;
av += optind;
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, &ncpus, sizeof(ncpus));
for (cpu = 0; cpu < ncpus; cpu++) {
kkread(kd, Nl[0].n_value + cpu * sizeof(baseptr),
&baseptr, sizeof(baseptr));
kkread(kd, baseptr + offsetof(struct mdglobaldata, mi.gd_slab),
&slab, sizeof(slab));
dumpslab(kd, cpu, &slab);
}
printf("Done\n");
return(0);
}
static void
dumpslab(kvm_t *kd, int cpu, struct SLGlobalData *slab)
{
struct SLZone *zonep;
struct SLZone zone;
SLChunk *chunkp;
SLChunk chunk;
int z;
int pass;
int xcount;
int rcount;
int first;
int64_t save;
int64_t extra = 0;
printf("cpu %d NFreeZones=%d JunkIndex=%d\n", cpu, slab->NFreeZones,
slab->JunkIndex);
for (z = 0; z < NZONES; z++) {
for (pass = 1; pass <= 2; ++pass) {
zonep = TAILQ_FIRST(&slab->ZoneAry[z]);
first = 1;
save = extra;
while (zonep) {
kkread(kd, (u_long)zonep, &zone, sizeof(zone));
if (pass == 1) {
if (first) {
printf(" zone %2d", z);
printf(" chunk=%-5d elms=%-4d ",
zone.z_ChunkSize, zone.z_NMax);
}
} else if (pass == 2 && first == 0) {
printf(",");
}
first = 0;
if (pass == 2)
printf(" %d", zone.z_NFree);
extra += zone.z_NFree * zone.z_ChunkSize;
chunkp = zone.z_RChunks;
rcount = 0;
while (chunkp) {
kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk));
chunkp = chunk.c_Next;
++rcount;
}
xcount = rcount;
if (xcount) {
if (pass == 2)
printf(" [rc=%d", xcount);
extra += xcount * zone.z_ChunkSize;
}
chunkp = zone.z_LChunks;
rcount = 0;
while (chunkp) {
kkread(kd, (u_long)chunkp, &chunk, sizeof(chunk));
chunkp = chunk.c_Next;
++rcount;
}
if (rcount) {
if (pass == 2) {
if (xcount)
printf(",");
else
printf(" [");
printf("lc=%d", rcount);
}
extra += rcount * zone.z_ChunkSize;
}
if (rcount || xcount) {
if (pass == 2)
printf("]");
}
zonep = TAILQ_NEXT(&zone, z_Entry);
}
if (first == 0 && pass == 1)
printf(" %6jdK free:", (intmax_t)(extra - save) / 1024);
if (first == 0 && pass == 2)
printf("\n");
}
}
printf(" TotalUnused %jd.%03dM\n",
(intmax_t)extra / 1024 / 1024,
(int)(extra % 1024) * 999 / 1024);
}
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);
}
}