summaryrefslogtreecommitdiffstats
path: root/debug/risc-v-gsp-rm-vm/examples/scripts
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
commit31e27d455969d33190d28917ef98f034888d217b (patch)
treec0c4dc18e78e6a1702fcda43bc2806e7cfb7c931 /debug/risc-v-gsp-rm-vm/examples/scripts
parentc155ee8de5b642cbd407bf2231041f17ebe43734 (diff)
downloadopen-iov-31e27d455969d33190d28917ef98f034888d217b.tar.gz
open-iov-31e27d455969d33190d28917ef98f034888d217b.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/scripts')
-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
2 files changed, 62 insertions, 0 deletions
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))