summaryrefslogtreecommitdiffstats
path: root/debug/risc-v-gsp-rm-vm/examples
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 08:36:35 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 08:36:35 -0400
commitba58dcdc5ad6ca021c723d279f33e3f14e1184df (patch)
tree47e43a2dad9a2d4bb40da46243654bff8b1302de /debug/risc-v-gsp-rm-vm/examples
parentfe485080e159c983242d699f4a584659df159818 (diff)
downloadopen-iov-ba58dcdc5ad6ca021c723d279f33e3f14e1184df.tar.gz
open-iov-ba58dcdc5ad6ca021c723d279f33e3f14e1184df.zip
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.
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/examples')
-rw-r--r--debug/risc-v-gsp-rm-vm/examples/probes/demo_probes.json25
-rw-r--r--debug/risc-v-gsp-rm-vm/examples/scripts/dump_diff.py33
-rw-r--r--debug/risc-v-gsp-rm-vm/examples/scripts/trace_rpc.py29
3 files changed, 87 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/examples/probes/demo_probes.json b/debug/risc-v-gsp-rm-vm/examples/probes/demo_probes.json
new file mode 100644
index 0000000..db623f1
--- /dev/null
+++ b/debug/risc-v-gsp-rm-vm/examples/probes/demo_probes.json
@@ -0,0 +1,25 @@
+{
+ "probes": [
+ {
+ "name": "sum-nonzero",
+ "symbol": "rpc_sum",
+ "when": "a1 > 0",
+ "on_enter": {
+ "log": ["a0", "a1"],
+ "dump": [{"reg": "a0", "len": 32, "label": "sum-input"}],
+ "note": "rpc_sum with a non-zero length"
+ },
+ "on_leave": {"log": ["retval"]}
+ },
+ {
+ "name": "state-machine",
+ "symbol": "rpc_state",
+ "on_leave": {"log": ["retval"], "note": "state transition"}
+ },
+ {
+ "name": "trap",
+ "symbol": "rpc_fault",
+ "on_enter": {"note": "rpc_fault entered; the ebreak trap follows"}
+ }
+ ]
+}
diff --git a/debug/risc-v-gsp-rm-vm/examples/scripts/dump_diff.py b/debug/risc-v-gsp-rm-vm/examples/scripts/dump_diff.py
new file mode 100644
index 0000000..329ffb1
--- /dev/null
+++ b/debug/risc-v-gsp-rm-vm/examples/scripts/dump_diff.py
@@ -0,0 +1,33 @@
+"""Snapshot-diff the uproc control block across a host-injected PING.
+
+Run from the tool root:
+
+ ./greeneye.sh run examples/scripts/dump_diff.py
+
+Demonstrates: symbol -> structure schema decoding, snapshot + diff, host
+stimulus via memory writes, and symbol-annotated output.
+"""
+import json
+from pathlib import Path
+
+from greeneye import Memory
+from greeneye.structs import render, schema_from_json
+
+TOOL_ROOT = Path(__file__).resolve().parents[2]
+schema = schema_from_json(json.loads((TOOL_ROOT / "firmware/uproc_demo/gsp_ctrl.schema.json").read_text()))
+ctrl = symbols.lookup("gsp_ctrl")
+
+# Let the firmware self-test settle.
+s.run(duration=0.4)
+before = s.snapshot(ctrl, schema.size, "ctrl-before-ping")
+
+# Host stimulus: PING with argument 0x1234.
+memory.write_u64(ctrl + 32, 1) # mailbox
+memory.write_u64(ctrl + 40, 0x1234)
+s.run(duration=0.4)
+after = s.snapshot(ctrl, schema.size, "ctrl-after-ping")
+
+print("decoded control block:")
+print(render(schema, schema.decode(after, base=ctrl)))
+print("\nchanged bytes:")
+print(Memory.render_diff(Memory.diff(before, after, base=ctrl), symbols))
diff --git a/debug/risc-v-gsp-rm-vm/examples/scripts/trace_rpc.py b/debug/risc-v-gsp-rm-vm/examples/scripts/trace_rpc.py
new file mode 100644
index 0000000..12b912b
--- /dev/null
+++ b/debug/risc-v-gsp-rm-vm/examples/scripts/trace_rpc.py
@@ -0,0 +1,29 @@
+"""Trace every uproc RPC handler with enter/leave hooks.
+
+Run from the tool root:
+
+ ./greeneye.sh run examples/scripts/trace_rpc.py
+
+The script namespace provides ``s``/``session``, ``memory``, ``symbols``,
+``recorder`` and ``ge`` (the greeneye package).
+"""
+NAMES = ["rpc_ping", "rpc_echo", "rpc_fill", "rpc_sum", "rpc_state", "rpc_fault"]
+events = []
+
+for name in NAMES:
+ sym = symbols.get(name)
+ if sym is None:
+ print(f"symbol {name} not found")
+ continue
+ s.hook(
+ sym.addr,
+ on_enter=lambda hit: events.append(("enter", hit.label(), hit.arg(0))),
+ on_leave=lambda hit: events.append(("leave", hit.label(), hit.retval)),
+ )
+
+s.run(duration=1.0)
+
+print(f"{len(events)} hook events:")
+for kind, label, value in events:
+ print(f" {kind:5} {label:14} {value:#018x}")
+recorder.event("trace_complete", events=len(events))