summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/guest_pmap_win.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/guest-diag/guest_pmap_win.py')
-rw-r--r--tools/guest-diag/guest_pmap_win.py47
1 files changed, 47 insertions, 0 deletions
diff --git a/tools/guest-diag/guest_pmap_win.py b/tools/guest-diag/guest_pmap_win.py
new file mode 100644
index 0000000..a9b74a7
--- /dev/null
+++ b/tools/guest-diag/guest_pmap_win.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+# guest_pmap_win.py - dump present pages of a process's VA range through the
+# guest's own pagemap (root in the guest). Batched reads (512 entries per
+# pread) so a 256 MB window takes about a second, not minutes.
+#
+# Usage: sudo python3 guest_pmap_win.py <pid> <lo-hex> <hi-hex> [max-pairs] [pa-max-hex]
+# Output: one "0x<va>,0x<pa>" line per present page (ascending VA), capped at
+# max-pairs. PAs of 0 are skipped; pages above pa-max are skipped unless 0.
+import os
+import sys
+
+pid = int(sys.argv[1])
+lo = int(sys.argv[2], 16) & ~0xFFF
+hi = int(sys.argv[3], 16)
+maxp = int(sys.argv[4]) if len(sys.argv) > 4 else 20000
+pa_max = int(sys.argv[5], 16) if len(sys.argv) > 5 else 0
+
+BATCH = 512
+out = []
+fd = os.open('/proc/%d/pagemap' % pid, os.O_RDONLY)
+try:
+ va = lo
+ while va < hi:
+ n = min(BATCH, (hi - va) // 0x1000)
+ if n <= 0:
+ break
+ os.lseek(fd, (va // 4096) * 8, 0)
+ data = os.read(fd, n * 8)
+ got = len(data) // 8
+ for i in range(got):
+ e = int.from_bytes(data[i * 8:i * 8 + 8], 'little')
+ if not ((e >> 63) & 1):
+ continue
+ pfn = e & ((1 << 55) - 1)
+ pa = pfn << 12
+ if not pa:
+ continue
+ if pa_max and pa >= pa_max:
+ continue
+ out.append('0x%x,0x%x' % (va + i * 0x1000, pa))
+ if len(out) >= maxp:
+ print('\n'.join(out))
+ sys.exit(0)
+ va += got * 0x1000
+finally:
+ os.close(fd)
+print('\n'.join(out))