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
|
# 07 — Version-upgrade playbook: re-running the CUDA analysis
When the guest driver, CUDA runtime, GSP firmware or GPU generation changes,
this is the procedure that refreshes the analysis with minimal effort and
keeps the name map and interface knowledge accumulating.
## 0. Before you start
* You need the new `libcuda.so.<version>` (from the guest with
`570.144/scripts/fetch_from_guest.sh`, or from the driver package with
`--extract-only`).
* Work in a new version directory `userspace/cuda/<version>/` — never
overwrite an analysed version. Copy the structure from `570.144/`
(`scripts/`, `ghidra/`, `annotations/`) and create `run/`.
* Announce the new tree in the project handoff so parallel agents know which
tree is being analysed (the per-area coordination file used during the
first pass was local scratch and has been removed).
## 1. Cheap triage (minutes)
```
tools/cudatool.py info <lib>
tools/cudatool.py delta <previous_lib> <lib> > run/delta.txt
tools/cudatool.py crash <lib> <map_base> <ip> # if a guest crash is known
```
Read `delta.txt`:
* **no export moves, small text growth** → patch release: most names and
offsets from the previous version transfer; spot-check the subsystems
touched by the release notes.
* **new exports** → feature release: identify the new API surface, map it to
engine functions via decompilation of the new stubs.
* **many moves** → reshuffle (toolchain/linker change): plan a full re-analysis
and re-apply the name map, expecting to fix a fraction.
## 2. Full analysis (tens of minutes)
```
tools/ghidra_full_analysis.sh <lib> <version_dir>/run/ghidra-full cuda-full
tools/ghidra_export_index.sh <version_dir>/run/ghidra-full cuda-full <program> <version_dir>/run/analysis/elf-index
tools/ghidra_batch_decompile.sh <version_dir>/run/ghidra-full cuda-full <program> <version_dir>/run/analysis/decompiled \
<text_start> <text_end> 0x100000 5 120
tools/ghidra_index_merge.sh <version_dir>/run/analysis/decompiled
```
Get `<text_start>`/`<text_end>` from `cudatool.py info`. Confirm the image base
with `PrintProgramInfo.java` before citing addresses.
## 3. Transfer names and knowledge
Measure the transfer first, before copying anything:
```
tools/cudatool.py fdematch <previous>/run/libcuda.so.<old> <libcuda.so.<new>> \
--names <previous>/annotations/names.tsv
```
`fdematch` matches function ranges from both `.eh_frame_hdr` tables using the
common exports as local address anchors (same FDE size within a small window
of `old_addr + nearest-export delta`), and breaks the previous name map down
by its `source` column. Measured for **570.144 → 570.211.01**
(`570.144/run/analysis/fdematch-570.144-570.211.txt`, gitignored):
| Map part | Transferable | How |
|---|---|---|
| 659 exports | **100%**, exact | same name, same size, address = old + local delta |
| verified internals | 5/7 (71%) | anchored same-size window |
| wrapper-callee internals | 21/29 (72%) | anchored same-size window |
| generated `wrapper_*` | **1.1%** | **do not transfer by address** |
| all A functions | 85.5% matched (58.3% unique) | anchored same-size window |
The wrapper result is the important one: the generated wrapper region is
re-laid-out between patch versions, so wrapper addresses must be re-resolved
on the new binary with `tools/cudatool.py wrappers` (and then
`annotate_corpus.py` re-run), never by adding a delta to the old map. Export
and hand-written internal names do carry over.
```
cp <previous>/annotations/names.tsv <new>/annotations/names.tsv
# translate addresses: the map is file-vaddr keyed, so for unchanged
# functions the offsets are usually identical; where the delta shows moves,
# adjust from the decompiled corpus.
analyzeHeadless <proj> cuda-full -process <program> -noanalysis \
-scriptPath tools/ghidra -postScript ApplyNameMap.java <new>/annotations/names.tsv --dry-run
# then without --dry-run
```
Also transfer the *subsystem index* (`annotations/subsystems.tsv`: address,
our name, subsystem, evidence) and re-validate the entries that the delta
marked as moved. For corpus-level measurement (added/removed/resized
functions, not just name transfer) use `tools/diff_corpus.py` on the old and
new `decompiled_index.tsv` once the new version has been decompiled.
## 4. Validate against the guest
1. Load the stack and run the guest smoke test (`tools/test/cuda_drv_test.c`
compiled as `/tmp/cdt`), with the ioctl tracer
(`tools/guest-diag/ioctl_trace.c`) attached.
2. Compare the observed ioctl/control sequence with the previous version's
`docs/05` sequence; new or reordered controls are the interesting deltas.
3. Run the host/guest A/B harness (`tools/cuda-ab/ab.sh all`) for a numerical
correctness check.
4. If the guest fails, use the crash decoder + corpus lookup (§1, §2) to get
from a dmesg `ip` to the exact function and line in the decompiled corpus,
then to the control reply the driver consumed.
## 5. Update the documents
* `docs/05-<version>-decompilation.md` — new version-specific map and crash
notes (copy the structure from `docs/05-570.144-decompilation.md`).
* `annotations/names.tsv` and `annotations/subsystems.tsv` — the deltas.
* `docs/04-virtualization-and-emulation.md` — only if the *interface* changed
(new controls, new capability bits, new object classes).
* `README.md` status table.
## 6. What not to do
* Do not patch the guest driver or add `LD_PRELOAD` shims to make things work;
that breaks the anti-fragility rule (`docs/04` §3). If a reply must change,
change the emulation.
* Do not commit decompiled output, extracted binaries or Ghidra projects; they
are gitignored for a reason (vendor-derived, large).
* Do not name non-public source locations in tracked docs; describe behaviour
and cite `libcuda+0x...` offsets.
* Do not run a second analysis in the same Ghidra project while another
process has it open (exclusive lock, even read-only); use the per-chunk
project copies in `ghidra_batch_decompile.sh`.
|