DF-2675 / ovrdump.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | /* * DF-2675 ovrdump: for buffer slots 0..N, print kvabase, present-PTE count, * the buffer's b_loffset (offset 160), int fields equal to 65536 * (b_bufsize/b_bcount candidates), and the first 48 bytes of physical * memory currently mapped at kvabase + MAXBSIZE (the overflow page). */ #include <sys/types.h> #include <err.h> #include <fcntl.h> #include <kvm.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define PMASK 0x000FFFFFFFFFF000ULL #define MAXBSIZE_ 65536 static int memfd; static uint64_t KPML4; static int rdphys(uint64_t pa, void *buf, size_t len) { return (pread(memfd, buf, len, (off_t)pa) == (ssize_t)len); } static uint64_t pteof(uint64_t va) { uint64_t pml4[512], pud[512], pd[512], pt[512]; int i4, i3, i2; i4 = (int)((va >> 39) & 511); i3 = (int)((va >> 30) & 511); i2 = (int)((va >> 21) & 511); if (!rdphys(KPML4, pml4, 4096) || !(pml4[i4] & 1)) return 0; if (!rdphys(pml4[i4] & PMASK, pud, 4096) || !(pud[i3] & 1)) return 0; if (pud[i3] & 0x80) return 0; if (!rdphys(pud[i3] & PMASK, pd, 4096) || !(pd[i2] & 1)) return 0; if (pd[i2] & 0x80) return 0; if (!rdphys(pd[i2] & PMASK, pt, 4096)) return 0; return pt[(va >> 12) & 511]; } int main(int argc, char **argv) { kvm_t *kd; struct nlist nl[] = { { "_buf" }, { "_KPML4phys" }, { NULL } }; unsigned char *arr; long nbuf, szbuf, n, lim; uint64_t bufva; kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "ovrdump"); if (!kd) return 1; if (kvm_nlist(kd, nl) != 0) errx(1, "nlist"); if (kvm_read(kd, nl[1].n_value, &KPML4, 8) != 8) errx(1, "kpml4"); if (kvm_read(kd, nl[0].n_value, &bufva, 8) != 8) errx(1, "bufptr"); { int v; size_t l = sizeof(v); if (sysctlbyname("vfs.nbuf", &v, &l, NULL, 0) < 0) err(1, "nbuf"); nbuf = v; l = sizeof(v); if (sysctlbyname("debug.sizeof.buf", &v, &l, NULL, 0) < 0) err(1, "sz"); szbuf = v; } kvm_close(kd); memfd = open("/dev/mem", O_RDONLY); if (memfd < 0) err(1, "/dev/mem"); arr = malloc(nbuf * szbuf); if (!arr) err(1, "malloc"); kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "ovrdump2"); if (kvm_read(kd, bufva, arr, nbuf * szbuf) != nbuf * szbuf) errx(1, "read array"); kvm_close(kd); lim = (argc > 1) ? atol(argv[1]) : 60; for (n = 0; n < nbuf && n < lim; n++) { uint64_t kv; unsigned char rec[1400]; memcpy(rec, arr + n * szbuf, szbuf); memcpy(&kv, rec + 1024, 8); if (kv == 0) continue; { uint64_t loff = 0; int xio_npages, kvasize, i; memcpy(&xio_npages, rec + 1056, 4); memcpy(&kvasize, rec + 1032, 4); if (xio_npages > kvasize / 4096) { uint64_t p16; char hex[128]; unsigned char buf[48]; memcpy(&loff, rec + 176, 8); p16 = pteof(kv + MAXBSIZE_) & PMASK; memset(buf, 0, sizeof(buf)); if (p16) rdphys(p16, buf, 48); for (i = 0; i < 24; i++) snprintf(hex + i*2, 4, "%02x", buf[i]); printf("OVRBUF n=%ld kva=%#llx npages=%d kvasize=%d " "loff=%#llx p16phys=%#llx\n data=%s\n ascii: ", n, (unsigned long long)kv, xio_npages, kvasize, (unsigned long long)loff, (unsigned long long)p16, hex); for (i = 0; i < 48; i++) putchar((buf[i] >= 32 && buf[i] < 127) ? buf[i] : '.'); putchar('\n'); } } } return 0; } |