summaryrefslogtreecommitdiffstats
path: root/debug/risc-v-gsp-rm-vm/docs/15-AGENTIC-GSP-IDE.md
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 09:13:00 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-02 09:13:00 -0400
commit1e701396b1b6d204dfd8e5a8ddcd3007038029ac (patch)
tree8dde895cf9d3e66ce912d01cb1a72ff674dc850f /debug/risc-v-gsp-rm-vm/docs/15-AGENTIC-GSP-IDE.md
parentab48e44832db55fdedadcf44f55fa9904ca36f2f (diff)
downloadopen-iov-1e701396b1b6d204dfd8e5a8ddcd3007038029ac.tar.gz
open-iov-1e701396b1b6d204dfd8e5a8ddcd3007038029ac.zip
debug: green-eye wave 2 - injection SDK, Frida-like calls, Ghidra control bridge, long-term docs
Adds to debug/risc-v-gsp-rm-vm/: - Session.call / run_until: Frida-like remote function calls and run-to-cursor, with register restoration; verified live (rpc_ping -> 0xaffe). - symbol+offset target resolution (gsp_ctrl+0x10) across all APIs and the REPL. - Injection SDK (sdk/) and 'greeneye inject': position-independent RV64 service blobs (verified zero relocations), loaded into RAM, registered in the demo handler table, and invoked either directly or through the firmware mailbox dispatcher. Demo ABI extended: mailbox 16..23 selects slots, arg0 carries the service command, arg2 added (struct now 0x190; schema updated). - Ghidra control bridge (greeneye ghidra + GreenEyeControl.java): run-until-here, breakpoints, memory/register access, remote calls, hit export; verified end-to-end with Ghidra headless (run_until reached rpc_sum from a GhidraScript). - MarkGreenEyeHits.java fixed for the Ghidra 12 createBookmark API; verified headless together with ExportForGreenEye.java. - Analyzer renders a QEMU first-fault table for probe sessions (fault count, epc with firmware vaddr translation, access address/size, reason). - Tests now 35 green, including injection, Ghidra bridge, remote call, run-until and REPL command smoke tests. - Documentation: docs/11-16 (GSP RM service developer guide, injection SDK specification, Ghidra control, adversarial interoperability guide, agentic GSP IDE, custom simulator design) and GREEN-EYE-ROADMAP.md (long-term H1-H7 program); doc maps and the project RISC-V VM doc updated.
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/docs/15-AGENTIC-GSP-IDE.md')
-rw-r--r--debug/risc-v-gsp-rm-vm/docs/15-AGENTIC-GSP-IDE.md387
1 files changed, 387 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/docs/15-AGENTIC-GSP-IDE.md b/debug/risc-v-gsp-rm-vm/docs/15-AGENTIC-GSP-IDE.md
new file mode 100644
index 0000000..79d17b8
--- /dev/null
+++ b/debug/risc-v-gsp-rm-vm/docs/15-AGENTIC-GSP-IDE.md
@@ -0,0 +1,387 @@
+# 15 — green-eye as an agentic integrated development, analysis and debugging environment for the GPU System Processor
+
+> **# TOOL IN DEVELOPMENT - NOT READY YET!** See 00 for status.
+
+## 1. Vision and what "agentic" means here
+
+green-eye already has the two properties that make an agent loop possible:
+a **deterministic, scriptable harness** (`ge.launch`/`ge.attach`, `Session`,
+`record`, `compare`) and a **durable evidence format** (the session directory).
+"Agentic" here means:
+
+* AI agents drive the deterministic harness — they choose instrumentation,
+ run stimuli, compare sessions and write findings;
+* sessions are the shared state between agents, humans and Ghidra, so every
+ claim is inspectable after the fact;
+* **humans keep product-change authority**: an agent may propose an
+ `open-iov-vfio` change with evidence, but only a human merges it, and the
+ physical-confirmation rules of docs/06 and docs/07 still apply.
+
+Non-goals: autonomous hardware cycles, unattended reboots, agents that "fix"
+the emulation directly, or replacing the engineer reading the decompiler.
+This document describes the environment that exists today plus the roadmap
+hooks that would make a full agent platform real.
+
+## 2. Architecture
+
+```
+ +-------------------- agents (triage / hypothesis / RE / portability) ----+
+ | |
+ | CLI: ./greeneye.sh info|demo|run|attach|launch|probe|record|analyze| |
+ | compare|symbols|plugins|inject|ghidra |
+ | Python: ge.launch/attach, Session.*, memory.*, symbols.*, structs, |
+ | probes, plugins, ghidra.export_hits, inject.* |
+ | REPL: bp/hook/watch/call/x/snap/events/note |
+ | Ghidra bridge: JSON lines over localhost (docs/13) |
+ | MCP: planned plugin only (roadmap R3) — does not exist in v0.1 |
+ +----------------------------------+---------------------------------------+
+ v
+ session directory (events.jsonl + session.json + snapshots + summary.md)
+```
+
+### 2.1 The session directory is the shared state
+
+| Artifact | Content | Consumers |
+|---|---|---|
+| `events.jsonl` | append-only event stream (`bp_hit`, `watch_hit`, `mem_write`, `call_enter/return`, `note`, `service_injected`, …) | `analyze`, `compare`, `export_hits`, plugins |
+| `session.json` | format, name, counts, snapshot inventory, meta | report tooling, provenance |
+| `snapshots/*.bin.z` | zlib-compressed region captures with sha256 | offline diff, field decode |
+| `blobs/*` | plugin/probe dumps (e.g. qemu.log) | forensics |
+| `summary.md` | rendered report | humans, PR attachments |
+
+`greeneye compare dumps/<a> dumps/<b> --symbols` is the primary agent
+primitive: it turns two sessions into hit/watch/write deltas. Format
+`greeneye-session/1` evolves additively (roadmap V2).
+
+### 2.2 Surfaces an agent may use
+
+* `./greeneye.sh …` — the stable CLI (all real subcommands listed above).
+* `./greeneye.sh run script.py` — the preloaded Python namespace (`ge`,
+ `session`/`s`, `memory`, `symbols`, `recorder`) makes a harness file the
+ unit of automation.
+* `./greeneye.sh ghidra` + `GreenEyeControl.java` — JSON-lines bridge for the
+ decompiler loop (`run_until`, `bp_set`, `read_mem`, `call`, `hits`,
+ `export_hits`; protocol in docs/13 §3).
+* Plugins — the extension point (docs/04). A plugin's `register(ge)` can add
+ instrumentation, CLI commands (`ge.add_command`) and recorded events; plugin
+ output lands in the same `events.jsonl`.
+* **MCP is planned, not present.** Roadmap R3/H7 reserves an MCP plugin that
+ would expose sessions as local stdio tools. Until that rung is scheduled, do
+ not add MCP dependencies to the core package (docs/04 §3d).
+
+### 2.3 Why the evidence model matters for agents
+
+A human can hold context across steps; an agent cannot. The session directory
+makes the context external: an agent can be restarted, handed a directory, and
+re-derive the same conclusion without replaying its own reasoning. This is the
+difference between an agent that reports opinions and one that produces
+reviewable evidence.
+
+## 3. Agent roles and workflows
+
+| Role | Input | Tools | Output | Stop condition |
+|---|---|---|---|---|
+| Triage | question + firmware version(s) | `symbols export`, `probe`, `analyze` | delta candidates, prioritised symbol list | every changed symbol classified |
+| Hypothesis | one behaviour question | `run` scripts, hooks, watchpoints, `compare` | session pair + verdict | delta attributed to one variable |
+| RE | decompiled function | `greeneye ghidra`, `run_until`, breakpoints, `export_hits` | hits TSV + annotation, reachability answer | function hit or timeout recorded |
+| Portability | version/device pair | docs/07 playbook, baseline + candidate sessions, M1–M6 | portability report | metric table complete |
+| Injection | service idea | `sdk/`, `inject`, `load_service`, `invoke_remote`, `invoke_via_firmware` | injected-service session pair | direct and firmware paths agree |
+| Verification | another agent's finding | golden sessions, `compare`, `analyze` | pass/fail + counterexample | finding reproduced or refuted |
+
+Role separation is deliberate: the agent that made a claim should not be the
+only one that checks it. Verification requires re-running the original
+stimulus, not re-reading the original report.
+
+## 4. Runbooks
+
+Each runbook is written so a human or an agent can execute it start to finish,
+and each ends with the evidence pack from docs/14 §6.
+
+### 4.1 Answer an emulation reply question
+
+Question template: "For control `<X>`, does the firmware set field `<Y>` of
+the reply/object, and in what order relative to `<Z>`?"
+
+1. Frame it as A/B: the emulation's reply (reference capture, docs/07 P4) and
+ the firmware's reply in green-eye. One session alone cannot answer it.
+2. Resolve the handler and object from the symbol DB; never hardcode:
+
+ ```bash
+ ./greeneye.sh symbols resolve --db symbols-<ver>.json <handler-or-addr>
+ ```
+
+3. Capture the firmware side with a hook + before/after snapshots:
+
+ ```python
+ # reply_q.py -- ./greeneye.sh run reply_q.py --kernel <rehosted.elf>
+ import greeneye as ge
+ from greeneye import Memory
+
+ s = ge.launch(kernel="<rehosted.elf>", record=True, name="reply-q")
+ try:
+ ctrl = s.symbols.lookup("<control-symbol>") # demo: gsp_ctrl
+ s.hook("<handler-symbol>",
+ on_enter=lambda h: s.note("enter", a0=h.arg(0)),
+ on_leave=lambda h: s.note("leave", retval=h.retval))
+ before = s.snapshot(ctrl, 0x100, "before")
+ s.memory.write_u64(ctrl + 0x20, 1) # stimulus
+ s.run(duration=0.5)
+ after = s.snapshot(ctrl, 0x100, "after")
+ print(Memory.render_diff(Memory.diff(before, after, base=ctrl), s.symbols))
+ finally:
+ s.close()
+ ```
+
+4. Decode the captured bytes with the structure schema so the answer is
+ field-by-field, not byte noise:
+
+ ```python
+ import json
+ from greeneye.structs import schema_from_json, decode, render
+ schema = schema_from_json(json.load(open("firmware/uproc_demo/gsp_ctrl.schema.json")))
+ values = decode(schema, s.memory.read(ctrl, schema.size), base=ctrl)
+ print(render(schema, values))
+ ```
+
+5. Compare against the reference capture with
+ `greeneye.analyze.compare_sessions(...)` / `./greeneye.sh compare …` for
+ ordering (M3) and state the field diff in words (M2). If the reply is in a
+ different object, repeat step 3 on that object's address.
+6. Report: question, session pair, `compare` output, M2/M3 rows, fidelity
+ statement, explicit "cannot answer because L3 absent" where applicable.
+
+### 4.2 Find why a handler disappeared
+
+1. Build/refresh the static inventory for both firmware versions:
+
+ ```bash
+ $GHIDRA/support/analyzeHeadless <proj> <name> -process <program> -noanalysis \
+ -scriptPath debug/risc-v-gsp-rm-vm/ghidra \
+ -postScript ExportForGreenEye.java /tmp/symbols-<ver>.tsv
+ ./greeneye.sh symbols export --index /tmp/symbols-<ver>.tsv --bias 0 -o symbols-<ver>.json
+ diff <(cut -f2 /tmp/symbols-old.tsv | sort) <(cut -f2 /tmp/symbols-new.tsv | sort)
+ ```
+
+2. Probe the new image for early structure changes:
+
+ ```bash
+ ./greeneye.sh probe <new.fwimage> --symbols symbols-<ver>.json --record
+ ```
+
+3. Record the same stimulus against each version. Hook the old handler name;
+ a missing symbol is itself evidence — catch `SymbolNotFound` and log it
+ rather than aborting the run. Also hook the dispatcher and the old
+ handler's neighbours from the inventory diff.
+4. Compare the sessions:
+
+ ```bash
+ ./greeneye.sh compare dumps/<old-run> dumps/<new-run> --symbols
+ ./greeneye.sh analyze dumps/<new-run> --symbols symbols-<ver>.json --out new.md
+ ```
+
+5. Classify the disappearance with the table below, then confirm in Ghidra:
+
+ | Observation | Likely cause | Next step |
+ |---|---|---|
+ | name absent from new symbol DB | removed or renamed before build | match by size/callgraph in Ghidra |
+ | old function exists, dispatcher hits moved to another symbol | merged or re-routed | `run_until` the new dispatcher entry, `bp_set` there |
+ | old function exists, zero hits under the standard stimulus | coverage gap or decoy | widen stimulus, check xrefs from the dispatch table |
+ | dispatch table entry changed but code identical | behaviour moved (state/input) | inspect the table with bridge `read_mem`/snapshot |
+
+6. With the bridge running (`./greeneye.sh ghidra --kernel <elf>`), execute
+ until the dispatch site from the decompiler and set breakpoints:
+
+ ```bash
+ $GHIDRA/support/analyzeHeadless <proj> <name> -process <program> -noanalysis \
+ -scriptPath debug/risc-v-gsp-rm-vm/ghidra \
+ -postScript GreenEyeControl.java 7000 0x<dispatch-address>
+ ```
+
+7. Export hits and annotate the old function's fate:
+
+ ```bash
+ ./greeneye.sh analyze dumps/<new-run> --symbols symbols-<ver>.json --out new.md
+ python3 - <<'PY'
+ from greeneye.ghidra import export_hits
+ from greeneye.symbols import SymbolDB
+ db = SymbolDB(); db.load_json("symbols-<ver>.json")
+ print(export_hits("dumps/<new-run>", "greeneye_hits.tsv", symbols=db))
+ PY
+ ```
+
+8. Report: static delta, dynamic delta, classification, and whether the
+ emulation must change (with the docs/14 evidence pack).
+
+### 4.3 Prototype a service
+
+1. Build the SDK reference service and prove position independence:
+
+ ```bash
+ make -C sdk
+ make -C sdk relocs # must print "no relocations in this file"
+ ```
+
+2. Inject and invoke through both paths (direct debugger call, then firmware
+ mailbox dispatch):
+
+ ```bash
+ ./greeneye.sh inject --service sdk/build/injected_demo.elf \
+ --cmd 1 --arg0 0x41 --arg1 0x42
+ ```
+
+3. Iterate programmatically when the CLI shape is not enough:
+
+ ```python
+ from greeneye.inject import load_service, invoke_remote, invoke_via_firmware
+ svc = load_service(s, "sdk/build/injected_demo.elf", slot=6)
+ print(hex(invoke_remote(s, svc, 2, 0x10, 0x20)))
+ s.run(duration=0.3)
+ print(hex(invoke_via_firmware(s, svc, 2, 0x10, 0x20)))
+ ```
+
+4. Instrument the service like firmware: hooks on the entry, watchpoints on
+ its data, snapshots before/after each command (docs/11 §7).
+5. Compare two versions of the service to see the behavioural delta:
+
+ ```bash
+ ./greeneye.sh compare dumps/<svc-v1> dumps/<svc-v2> --symbols
+ ```
+
+6. Stop condition: direct and firmware-dispatched results agree, the session
+ is recorded, and the prototype is documented as development-only. Product
+ code goes to `open-iov-vfio` only through the accuracy loop (docs/11 §8,
+ docs/12 §9); GSP-RM registration is roadmap H1.3.
+
+### 4.4 Prepare a portability report
+
+1. Follow the P1 loop in docs/07-PORTABILITY-PLAYBOOKS.md with real commands:
+
+ ```bash
+ ./greeneye.sh probe <old.fwimage> --symbols symbols-old.json --record
+ ./greeneye.sh probe <new.fwimage> --symbols symbols-new.json --record
+ ./greeneye.sh record --kernel <rehosted-old.elf> --duration 2.0 \
+ --watch gsp_ctrl+0x10:8 --snapshot gsp_ctrl:392
+ ./greeneye.sh record --kernel <rehosted-new.elf> --duration 2.0 \
+ --watch gsp_ctrl+0x10:8 --snapshot gsp_ctrl:392
+ ./greeneye.sh compare dumps/<old-run> dumps/<new-run> --symbols
+ ```
+
+2. Keep the stimulus identical across versions: use one script/probe spec and
+ record it in the pack (docs/14 §4.1).
+3. Fill the M1–M6 table from docs/06-ACCURACY.md. M7 (timing) is never
+ claimed; L2/L3 statements are mandatory.
+4. Produce the report with the docs/14 §6 template and attach session hashes,
+ symbol DB hashes and the Ghidra export provenance.
+5. Verification agent step: replay the candidate stimulus against the checked-in
+ golden session (roadmap V1) and require `compare` to match expectations.
+
+## 5. Guardrails
+
+Hard rules (no agent may override them):
+
+* **Never claim cycles, time or reboots from the simulator.** L2 is not
+ modelled; L3 is absent until H2 (docs/06).
+* **No guest modifications** and no instrumentation of a guest driver; the
+ tool is never shipped and never present in a guest (docs/00, V4).
+* **Sessions are mandatory evidence.** A finding without a session directory
+ and a `compare` report is not a finding (docs/11 §8).
+* **No unattended hardware.** The agent runs against the simulator by default;
+ physical GPU cycles are supervised and human-driven (H7).
+* **Human approval for product changes.** Agents produce proposals and
+ evidence packs; only humans merge `open-iov-vfio` changes.
+* **Budgets everywhere.** Every run uses `duration=`/`max_stops=`/`timeout=`
+ and a wall-clock cap; a wedged target leaves the session stopped and is
+ restarted clean rather than poked.
+
+Capability manifest for actions (proposed file for the harness; see §7):
+
+| Class | Examples | Who runs it | Preconditions |
+|---|---|---|---|
+| Read | `info`, `plugins`, `symbols resolve`, `analyze`, `compare` | agent, unattended | path/DB provenance recorded |
+| Observe | `probe`, `record`, `demo`, hooks/watch/step | agent, unattended on simulator | timeout, session recording on |
+| Write (target) | `memory.write*`, `call`, `run_until`, `inject`, mailbox stimulus | agent with manifest | declared address/range, fresh session, before/after snapshots, mutation values noted |
+| Product | `open-iov-vfio` patch | human only | M1–M6 + physical confirmation rules (docs/07 P4.5) |
+| Hardware | physical cycles/reboots | human only | supervised, never unattended |
+
+A write action's manifest entry names the session, the target range, the
+purpose and the budget; the session records the action, so the manifest and
+the evidence can be cross-checked.
+
+## 6. Evaluation
+
+An agent workflow is judged on the same axis as the human one: how long until
+a reviewable answer, and does the answer survive verification.
+
+| Metric | Definition | Instrument |
+|---|---|---|
+| TTFA | question → first evidence-backed answer | wall clock; session count |
+| TTEP | question → complete evidence pack (docs/14 §6) | pack checklist |
+| Evidence yield | sessions/`compare` reports per accepted finding | `dumps/` inventory |
+| Verification pass rate | findings reproduced by the verification role | replay runs |
+| Coverage | inventory observed vs emulated (M1) | docs/06 table |
+| Accuracy trend | M1–M6 per release | docs/06 tables |
+| Regression lead time | firmware drop → delta report | probe/compare timestamps |
+| Human minutes | manual minutes per accepted finding | benchmark log |
+
+Benchmark protocol: take five questions from recent history, run each twice —
+once with the agent (all actions recorded) and once manually — on the same
+machine and firmware set, then compare TTFA/TTEP/evidence yield. Re-run the
+manual side offline against the agent's sessions to separate speed from
+correctness. Publish the ratios with the raw session directories, not just
+the numbers (the project's "never a single run" rule applies to tooling too).
+
+Golden data is the regression bed: the demo session and re-hosted workloads
+are checked in CI (roadmap V1), and every new stimulus script should grow a
+golden expectation once it is stable.
+
+## 7. Roadmap hooks (H7) and what would make this real
+
+| H7 item | What exists today | What is missing |
+|---|---|---|
+| MCP plugin (R3) | JSON-lines Ghidra bridge; sessions as data | MCP server plugin (`plugins/mcp_server.py` when built) |
+| deterministic harnesses | `run` scripts, probes, plugins, `record`/`compare` | named harness entry points, budgets, manifests |
+| sessions as evidence | `greeneye-session/1`, `summary.md`, `compare` | session index, signed/hashed pack tooling |
+| autonomous loops | hooks/watchpoints/compare primitives | hypothesis/verification controllers, stop conditions |
+| safety | local-only bridge, no network, no hardware | enforced capability manifest, process isolation |
+
+What would make this real:
+
+1. **MCP tool schema** (sketch; planned only, no code in v0.1):
+
+ ```json
+ {
+ "transport": "local stdio; no network exposure by default",
+ "tools": [
+ {"name": "list_sessions", "args": {}},
+ {"name": "open_session", "args": {"dir": "string"}},
+ {"name": "symbols_resolve", "args": {"session": "string", "name": "string"}},
+ {"name": "memory_read", "args": {"session": "string", "addr": "string", "size": "int"}},
+ {"name": "memory_hexdump", "args": {"session": "string", "addr": "string", "size": "int"}},
+ {"name": "set_breakpoint", "args": {"session": "string", "target": "string", "kind": "sw|hw"}},
+ {"name": "watch", "args": {"session": "string", "target": "string", "size": "int", "kind": "w|r|a"}},
+ {"name": "run", "args": {"session": "string", "duration": "float", "max_stops": "int"}},
+ {"name": "run_until", "args": {"session": "string", "target": "string", "timeout": "float"}},
+ {"name": "snapshot", "args": {"session": "string", "addr": "string", "size": "int", "label": "string"}},
+ {"name": "compare_sessions", "args": {"a": "string", "b": "string", "symbols": "bool"}},
+ {"name": "export_hits", "args": {"session": "string", "out": "string"}}
+ ]
+ }
+ ```
+
+ Baseline names follow docs/08 R3; `watch` and `run_until` follow the
+ bridge command set and H7.
+
+2. **Harness scripts** with fixed names and budgets: `stimulus.py` (one
+ workload), `probe_matrix.py` (version × device), `golden_check.py`
+ (compare against expected profiles). Today these are written ad hoc.
+3. **Golden data**: checked-in expectation files for the demo and at least one
+ re-hosted workload, wired into `make test` (roadmap V1).
+4. **Capability manifest** file the harness reads before any write action
+ (§5 table), with the session recording as the audit trail.
+5. **Session index** for agents: a small JSONL listing session dirs, questions
+ and outcomes, so triage starts from history instead of from zero.
+6. **Physical-escalation gate**: a write-up checklist that must be complete
+ before an agent-proposed change reaches a supervised hardware cycle.
+
+Until R3 lands, the agent loop is: CLI/scripts + Ghidra bridge + sessions —
+nothing more, and the documentation should keep saying so.