From 31e27d455969d33190d28917ef98f034888d217b Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Fri, 2 Oct 2026 08:36:35 -0400 Subject: debug: add green-eye GSP/uproc RISC-V VM runtime analysis tooling Adds open-iov/debug/risc-v-gsp-rm-vm: a GDB-free instrumentation stack that boots uproc/GSP firmware in qemu-system-riscv64 and provides Frida-like hooks, breakpoints, watchpoints, memory dumps, structure decoding, snapshot diffs, recorded sessions, declarative probes, a plugin API and a Ghidra symbol/hit bridge. Verified: 25 tests green (including a live QEMU smoke test); the demo uproc boots with correct hook/leave/watch/schema/snapshot/fault evidence; the optional TCG trace plugin builds and recorded 15M trace lines in 3 s; the TU104 570.144 fwimage probe reports its first exception (load access fault at firmware vaddr 0x4009014 reading 0x2000000000000A00). Documentation: lean tool docs under debug/risc-v-gsp-rm-vm/docs/00-10, a new docs/05-operations/03-risc-v-gsp-rm-vm.md debugging document, and '# TOOL IN DEVELOPMENT - NOT READY YET!' markers in docs/README.md, the onboarding tooling table and the debugging workflows doc. Vendors qemu-plugin.h from QEMU v8.2.2 (GPL-2.0-or-later), with its license header intact, so the optional TCG plugin builds without a QEMU source tree. --- debug/risc-v-gsp-rm-vm/docs/05-GHIDRA-BRIDGE.md | 105 ++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 debug/risc-v-gsp-rm-vm/docs/05-GHIDRA-BRIDGE.md (limited to 'debug/risc-v-gsp-rm-vm/docs/05-GHIDRA-BRIDGE.md') diff --git a/debug/risc-v-gsp-rm-vm/docs/05-GHIDRA-BRIDGE.md b/debug/risc-v-gsp-rm-vm/docs/05-GHIDRA-BRIDGE.md new file mode 100644 index 0000000..857102e --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/docs/05-GHIDRA-BRIDGE.md @@ -0,0 +1,105 @@ +# 05 — Ghidra bridge + +> **# TOOL IN DEVELOPMENT - NOT READY YET!** See 00 for status. + +Ghidra answers *what is the code*; green-eye answers *what did it do*. The +bridge joins them in both directions: Ghidra symbols into the runtime session, +runtime hit addresses back into the Ghidra project. + +## 1. Address conventions (read this first) + +| Space | Meaning | Transformation | +|---|---|---| +| file vaddr | offset in the binary (`libcuda+0x…`) | base | +| Ghidra program addr | what the decompiler shows | file vaddr + image base (`0x100000` for libcuda) | +| runtime addr | live process / emulator address | file vaddr + load bias | + +* Firmware linked at its load address: bias 0 (the demo, and a + relocated-to-RAM GSP image when using the probe bias). +* CUDA `libcuda` in the host oracle: runtime base from `/proc//maps`; + `--bias` normalises it if you want runtime addresses in the DB. +* The project's `decompiled_index.tsv`/bucket TSVs carry **both** program and + file addresses; green-eye parses both and stores the program address in + `symbol.extras["program_addr"]`. + +## 2. Build a symbol DB from Ghidra exports + +```bash +./greeneye.sh symbols export \ + --names ../../userspace/cuda/570.144/annotations/names.tsv \ + --index ../../userspace/cuda/570.144/run/analysis/decompiled/decompiled_index.tsv \ + --exports ../../userspace/cuda/570.144/run/analysis/elf-index/exports.tsv \ + --callgraph ../../userspace/cuda/570.144/run/analysis/elf-index/callgraph.tsv \ + --bias 0 -o symbols-cuda.json +``` + +For the GSP firmware project (`tools/ghidra/gsp-fwimage-570.144/`), first run +the existing export scripts (`ExportFunctionIndex.java`, +`DecompileFunctions.java`, …) to produce TSVs, then: + +```bash +./greeneye.sh symbols export --index --bias 0 -o symbols-gsp.json +``` + +`load_index_tsv` is column-aware: it accepts +`\t\t\t\t\t\t`, the 4-column +exports form, or a plain `\t` two-column form. + +## 3. Runtime addresses in the session + +```python +db = SymbolDB() +db.load_json("symbols-cuda.json") +db.load_names_tsv("names.tsv", bias=runtime_base - file_base) +s.symbols = db # or pass symbols= to attach()/launch() +``` + +`resolve()` then annotates every hit with the Ghidra name, and +`greeneye.ghidra.corpus_location(symbol, corpus_root)` returns +`:` when the index carried that information — the pointer from a +live hit to the decompiled body. + +## 4. Annotate hits back into Ghidra + +```bash +./greeneye.sh analyze dumps/ --symbols symbols-gsp.json --out run.md +python3 - <<'PY' +from greeneye.ghidra import export_hits +from greeneye.symbols import SymbolDB +db = SymbolDB(); db.load_json("symbols-gsp.json") +print(export_hits("dumps/", "greeneye_hits.tsv", symbols=db)) +PY +``` + +`greeneye_hits.tsv` is `addrhitssymbolannotation`. Then run the +bundled Java script in Ghidra headless: + +```bash +$GHIDRA/support/analyzeHeadless -process -noanalysis \ + -scriptPath debug/risc-v-gsp-rm-vm/ghidra \ + -postScript MarkGreenEyeHits.java /abs/path/greeneye_hits.tsv +``` + +`ExportForGreenEye.java` is the reverse helper: it walks the current program +and writes a green-eye-compatible `addrnamesize` TSV. + +## 5. Breakpoints from Ghidra + +Two practical routes today: + +1. `greeneye decompose/decompile` → note the file vaddr → script + `s.hook("0x…")` (green-eye translates to runtime via the bias you loaded). +2. Use `symbols export` from the Ghidra index, then `s.hook("")` by + name — the most robust route across recompilations. + +A future Ghidra-side green-eye console (roadmap item) can call +`greeneye` through its CLI to set breakpoints directly from the tool. + +## 6. Limits + +* Wrapper-generated functions are re-laid-out between driver patch versions; + transfer names, never raw wrapper addresses (the CUDA playbook's lesson). +* The decompiler does not recover struct types; structure schemas for + green-eye decoding must be written or exported separately. +* `decompiled_index.tsv` buckets are large and gitignored; keep symbol JSONs + small (name/size/subsystem only) if they must be tracked. -- cgit v1.2.3