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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
#!/usr/bin/env python3
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2026 Open-IOV contributors
# gdb script (run with: sudo gdb -p <pid> -batch -x /tmp/dumpctx.py)
# Dumps the libcuda client wait-loop context: the ctx object's queue/entry
# array (ctx+0x10 = count, ctx+0x18 = array of 0x28-byte entries) plus each
# entry's target object, so the host emulation knows which tracker /
# notification memory it must write to complete the wait.
import gdb
def r32(a):
return int.from_bytes(gdb.selected_inferior().read_memory(a, 4).tobytes(), "little")
def r64(a):
return int.from_bytes(gdb.selected_inferior().read_memory(a, 8).tobytes(), "little")
def rmem(a, n):
return gdb.selected_inferior().read_memory(a, n).tobytes()
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()
# gdb format: start end size offset objfile (offset is field 3)
base = int(f[0], 16) - int(f[3], 16)
print("MAPLINE " + line.strip())
break
if base is None:
print("NO_LIBCUDA_BASE")
raise SystemExit
LO = base + 0x23f700
HI = base + 0x23fd10
print("LIBBASE=0x%x SPIN=[0x%x,0x%x)" % (base, LO, HI))
found = None
for t in gdb.selected_inferior().threads():
t.switch()
f = gdb.newest_frame()
for i in range(14):
if f is None:
break
try:
pc = int(f.pc())
except Exception:
pc = 0
if LO <= pc < HI:
try:
rb = int(f.read_register("rbx")) & 0xffffffffffffffff
except Exception:
rb = None
found = (t, pc, rb, i)
break
f = f.older()
if found:
break
if not found:
print("NO_SPIN_FRAME")
for t in gdb.selected_inferior().threads():
t.switch()
top = ""
try:
f0 = gdb.newest_frame()
top = f0.name() or ""
except Exception:
pass
print("== tid=%s top=%s" % (t.num, top))
try:
print(gdb.execute("bt 6", to_string=True).rstrip())
except Exception as e:
print("bt_fail %s" % e)
try:
print(gdb.execute("info registers rdi rsi rdx rax rip", to_string=True).rstrip())
except Exception as e:
print("regs_fail %s" % e)
if "ioctl" in top or "poll" in top:
try:
rax = int(gdb.parse_and_eval("$rax")) & 0xffffffffffffffff
rdx = int(gdb.parse_and_eval("$rdx")) & 0xffffffffffffffff
print("ARG64@0x%x=%s" % (rdx, rmem(rdx, 0x40).hex()))
except Exception as e:
print("arg_fail %s" % e)
print("REGS_HINT")
try:
print(gdb.execute("thread apply all info registers rip rbx r13 r12", to_string=True).rstrip())
except Exception as e:
print("regs_fail %s" % e)
print("DONE_NOSPIN")
raise SystemExit
t, pc, ctx, depth = found
print("SPINNER tid=%s pc=0x%x depth=%d ctx=0x%x" % (t.num, pc, depth, ctx))
if ctx is None:
raise SystemExit
try:
count = r32(ctx + 0x10)
ent = r64(ctx + 0x18)
ctx0 = r64(ctx)
gpu = r64(ctx0 + 8)
print("CTX=0x%x count=%d entries=0x%x ctx0=0x%x gpu=0x%x gpu+3de0=0x%x" %
(ctx, count, ent, ctx0, gpu, r64(gpu + 0x3de0)))
except Exception as e:
print("CTX_READ_FAIL %s" % e)
raise SystemExit
n = min(count, 32)
for i in range(n):
e = ent + i * 0x28
try:
typ = r32(e + 0)
p = r64(e + 8)
v = r32(e + 0x10)
x18 = r64(e + 0x18)
x20 = r64(e + 0x20)
except Exception as ex:
print("e%d @0x%x UNREADABLE %s" % (i, e, ex))
continue
line = "e%d @0x%x type=%d p=0x%x v=0x%x x18=0x%x x20=0x%x" % (i, e, typ, p, v, x18, x20)
try:
hdr = rmem(p, 0x20)
line += " p32=%d p64=0x%x p[0:0x20]=%s" % (
int.from_bytes(hdr[0:4], "little"),
int.from_bytes(hdr[0:8], "little"),
hdr.hex())
except Exception:
line += " p_UNREADABLE"
if typ == 1:
try:
trk = rmem(p + 0x9410, 0x40)
vals = [int.from_bytes(trk[o:o+8], "little") for o in (0, 8, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38)]
line += " TRK=%s q=%s" % (trk.hex(), ",".join("0x%x" % x for x in vals))
except Exception:
line += " TRK_UNREADABLE"
print(line)
print("DONE_SPIN")
import os
if os.environ.get("CTX_POKE"):
inf = gdb.selected_inferior()
npk = 0
for i in range(n):
e = ent + i * 0x28
try:
if r32(e) != 1:
continue
p = r64(e + 8)
inf.write_memory(p + 0x9410 + 0x10, (1).to_bytes(8, "little"))
inf.write_memory(p + 0x9410 + 0x18, (1).to_bytes(8, "little"))
npk += 1
except Exception as ex:
print("poke e%d fail %s" % (i, ex))
print("POKED=%d" % npk)
|