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
|