summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/wall2/gr_walk.py
blob: cbdb02d5edfa6eb85f9328343313f95020fb62ab (plain)
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
#!/usr/bin/env python3
# gr_walk.py - find the RM window memdesc records in the guest's own RAM
# (via /proc/kcore direct map) and walk their kernel page-list pointers in
# the SAME pass (addresses go stale otherwise). Prints VA->PA candidates.
import sys, struct
sys.path.insert(0, "/tmp")
import guest_pin_stream as gps

PAT_SIZE = struct.pack("<Q", 0x20000)
PAT_FLAGS = struct.pack("<Q", 0x03008000)

def main():
    kc = gps.Kcore()
    if not kc.load():
        print("# kcore load failed"); return 1
    pov = kc.page_offset_base
    print("# page_offset_base=0x%x" % pov)
    found = []
    CH = 1 << 20
    pa = 0x100000000
    end = 0x180000000
    while pa < end and len(found) < 12:
        va = pov + pa
        d = kc.read(va, CH)
        if d:
            st = 0
            while True:
                i = d.find(PAT_SIZE, st)
                if i < 0:
                    break
                st = i + 1
                if i + 16 <= len(d) and d[i+8:i+16] == PAT_FLAGS:
                    found.append((pa + i, d[i:i+0x60]))
        pa += CH
    print("# memdesc records: %d" % len(found))
    for (gpa, rec) in found:
        size, flags = struct.unpack_from("<QQ", rec, 0)
        wpa = struct.unpack_from("<Q", rec, 0x10)[0]
        kptrs = [struct.unpack_from("<Q", rec, o)[0] for o in (0x18, 0x20, 0x28, 0x30, 0x38)]
        print("rec@0x%x size=0x%x pa=0x%x kptrs=%s" %
              (gpa, size, wpa, ["0x%x" % k for k in kptrs]))
        # walk each kptr for PA-like lists
        for kp in kptrs:
            if not gps.is_kern_ptr(kp):
                continue
            dd = kc.read(kp, 0x80)
            if not dd:
                print("   kptr 0x%x: unreadable" % kp); continue
            words = struct.unpack_from("<%dQ" % (len(dd)//8), dd, 0)
            pas = [w for w in words if 0x100000000 <= w < 0x180000000]
            npas = [w for w in words if 0x100000000 <= (w & ~0xfff) < 0x180000000]
            print("   kptr 0x%x: %s" % (kp, " ".join("0x%x" % w for w in words[:10])))
            if len(npas) >= 2:
                print("      PA-like: %s" % ["0x%x" % w for w in npas[:16]])
    return 0

if __name__ == "__main__":
    sys.exit(main())