summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/bpz10.py
blob: 30aa1daa903c061880930f6accb2cf81ef106bf5 (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
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
116
117
118
119
120
121
122
123
124
125
# gdb script: name the first failing call inside FUN_003e90c0 (ucode-image
# create, second half) after FUN_003d1e70 (blob parse) succeeded.
#
# PART 76 chain: FUN_00e21850 -> FUN_003e99d0 -> FUN_003d1e70 OK ->
# FUN_003e90c0 returns 1. This script breaks after EVERY call in
# FUN_003e90c0 (file 0x2e90c0..0x2e99b5), prints the return value, and
# finally prints the function's return + the caller's test site
# (CREATE2_RET at 0x2e9a3f).
#
# Run: sudo gdb -p <cdt-pid> -batch -x /tmp/bpz10.py
import gdb
import time

out = gdb.execute("info proc mappings", to_string=True)
base = None
for line in out.splitlines():
    if "libcuda" in line and "r-xp" in line:
        f = line.split()
        base = int(f[0], 16) - int(f[3], 16)
        break
print("BASE=0x%x" % (base or 0))
if base is None:
    raise SystemExit

gdb.execute("set pagination off")
gdb.execute("set confirm off")

# (file offset of the instruction AFTER the call, short name)
SITES = [
    (0x2e9110, "calloc"),
    (0x2e912a, "FUN_004aa820_alloc"),
    (0x2e918e, "FUN_00390290_status"),
    (0x2e91b3, "FUN_003df0d0_status"),
    (0x2e91f1, "destr_2e84d0"),
    (0x2e921d, "FUN_00391ee0_status"),
    (0x2e923c, "FUN_00371fa0_status"),
    (0x2e9282, "mutex_lock84"),
    (0x2e92b7, "mutex_unlock84"),
    (0x2e92bf, "FUN_00e4f3e0_status"),
    (0x2e9304, "mutex_lock68"),
    (0x2e931a, "mutex_unlock68"),
    (0x2e932a, "FUN_00363430_bool"),
    (0x2e9336, "FUN_003df340_bool"),
    (0x2e9363, "FUN_00406ff0_status"),
    (0x2e93ba, "FUN_00394190_status"),
    (0x2e93c9, "FUN_003bf520_status"),
    (0x2e9449, "free_a"),
    (0x2e9478, "FUN_00400550"),
    (0x2e948e, "FUN_004ab390"),
    (0x2e9497, "free_b"),
    (0x2e94a8, "free_c"),
    (0x2e94b6, "free_d_fail"),
    (0x2e9505, "FUN_003011e0_status"),
    (0x2e9525, "ind_0xa0_status"),
    (0x2e9564, "unlock_fail"),
    (0x2e9598, "unlock_b"),
    (0x2e95fc, "FUN_00e4b8c0"),
    (0x2e9615, "ind_0x4a48_ptr"),
    (0x2e9628, "FUN_005a5530"),
    (0x2e9643, "FUN_003df340_bool2"),
    (0x2e967a, "FUN_00e4f200_status"),
    (0x2e9687, "FUN_0034a4d0_bool"),
    (0x2e96e4, "FUN_00251730_done"),
    (0x2e9717, "unlock_ret0"),
    (0x2e9788, "FUN_003bf520_status2"),
    (0x2e97fa, "fprintf_fail"),
    (0x2e9808, "FUN_003be020_bool"),
    (0x2e9824, "FUN_0036b900_bool"),
    (0x2e9857, "FUN_003df340_bool3"),
    (0x2e9936, "FUN_00e4f2d0"),
    (0x2e9203, "FUN_3e90c0_RET"),
    (0x2e9a23, "PARSE_RET"),
    (0x2e9a3f, "CREATE2_RET"),
]
NAMES = dict(SITES)
for off, name in SITES:
    gdb.execute("break *0x%x" % (base + off))

t0 = time.time()
hits = 0
last_nonzero = None
inv = 0
while hits < 500:
    try:
        gdb.execute("continue")
    except gdb.error as e:
        print("CONTINUE_END %s" % e)
        break
    hits += 1
    rip = int(gdb.parse_and_eval("$rip")) & 0xffffffffffffffff
    off = rip - base
    name = NAMES.get(off, "?")
    eax = int(gdb.parse_and_eval("$eax")) & 0xffffffff
    r15 = int(gdb.parse_and_eval("$r15d")) & 0xffffffff
    print("HIT %d t=%.3f off=0x%x %-24s eax=0x%x r15=0x%x" %
          (hits, time.time() - t0, off, name, eax, r15))
    if name in ("FUN_00390290_status", "FUN_003df0d0_status",
                "FUN_00391ee0_status", "FUN_00371fa0_status",
                "FUN_00e4f3e0_status", "FUN_00406ff0_status",
                "FUN_00394190_status", "FUN_003bf520_status",
                "FUN_003bf520_status2", "FUN_003011e0_status",
                "FUN_00e4f200_status") and eax != 0:
        last_nonzero = (name, eax)
        print("  >>> LAST NONZERO %s = 0x%x" % (name, eax))
    if name == "FUN_3e90c0_RET":
        inv += 1
        print("INV %d FUN_3e90c0 return r15/eax=0x%x" % (inv, r15))
        if last_nonzero:
            print("  last nonzero status call: %s = 0x%x" % last_nonzero)
        if r15 != 0:
            try:
                print(gdb.execute("bt 6", to_string=True))
            except Exception as e:
                print("bt_fail %s" % e)
            break
        last_nonzero = None
    if name == "CREATE2_RET":
        print("CREATE2_RET eax=0x%x" % eax)
        if eax != 0:
            break

try:
    gdb.execute("detach")
except Exception:
    pass