summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/tracker_walk.py
blob: 3846fa178b9ff883bfd76f0491566197a1fb01f0 (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
#!/usr/bin/env python3
# tracker_walk.py - read a UVM tracking semaphore's expected payload and walk
# its semaphore object via /proc/kcore (run in the guest as root).
#
# Use with a live stuck client: the udvt/uvtw kprobes or the scanner's #sem
# lines give the tracker kptr (e.g. 0xffff899a885b5480); this prints
#   tracker+0x0  = semaphore kptr
#   tracker+0x28 = expected payload (the value the client waits to observe)
#   semaphore+0.. = its pointers (rm_mem/page) and candidate value words
# Pair it with the host's pool-wr/deferred-release logs and a pool page dump
# (pool_page.py) to compare what the driver expects vs what the host wrote.
import sys
import struct

sys.argv = ["tracker_walk"]
sys.path.insert(0, "/tmp")
import guest_pin_stream as g  # noqa: E402

kc = g.Kcore()
if not kc.load():
    print("KCORE LOAD FAILED")
    sys.exit(1)


def r64(a):
    d = kc.read(a, 8)
    return struct.unpack("<Q", d)[0] if d else None


def r32(a):
    d = kc.read(a, 4)
    return struct.unpack("<I", d)[0] if d else None


for arg in sys.argv[1:] or ["0xffff899a885b5480"]:
    SEM = int(arg, 16)
    print("tracker 0x%x:" % SEM)
    for off in range(0, 0x40, 8):
        print("  +0x%x = 0x%x" % (off, r64(SEM + off) or 0))
    sp = r64(SEM)
    print("semaphore=0x%x" % (sp or 0))
    if sp and g.is_kern_ptr(sp):
        for off in range(0, 0x80, 8):
            v = r64(sp + off)
            print("  sem+0x%x = 0x%x" % (off, v or 0))
        for off in range(0, 0x80, 8):
            v = r64(sp + off)
            if v and g.is_kern_ptr(v):
                w = r32(v)
                print("  *sem+0x%x -> dword=0x%x (%u)" % (off, w or 0, w or 0))