summaryrefslogtreecommitdiffstats
path: root/debug/risc-v-gsp-rm-vm/docs/04-PLUGINS.md
diff options
context:
space:
mode:
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/docs/04-PLUGINS.md')
-rw-r--r--debug/risc-v-gsp-rm-vm/docs/04-PLUGINS.md123
1 files changed, 123 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/docs/04-PLUGINS.md b/debug/risc-v-gsp-rm-vm/docs/04-PLUGINS.md
new file mode 100644
index 0000000..fa0fe0c
--- /dev/null
+++ b/debug/risc-v-gsp-rm-vm/docs/04-PLUGINS.md
@@ -0,0 +1,123 @@
+# 04 — writing green-eye plugins
+
+> **# TOOL IN DEVELOPMENT - NOT READY YET!** See 00 for status.
+
+A plugin is a Python module exposing `register(ge)`. It is loaded before the
+session runs (CLI `--plugin PATH`, `GREENEYE_PLUGINS`, or the bundled
+`plugins/` directory) and can add instrumentation, CLI commands and harness
+logic without touching green-eye itself.
+
+## 1. The API object
+
+```python
+def register(ge):
+ # live objects
+ ge.session # Session
+ ge.memory # Memory
+ ge.symbols # SymbolDB
+ ge.recorder # Recorder | NullRecorder
+
+ # instrumentation
+ ge.hook(target, on_enter=None, on_leave=None, kind="sw")
+ ge.watch(target, size=8, kind="w", callback=None)
+ ge.on_event(kind, callback) # kind in {"*", "bp_hit", "watch_hit", ...}
+ ge.resolve(target) # symbol/addr -> runtime address
+
+ # CLI + logging
+ ge.add_command("name", fn, help="…") # fn(session, args: list[str]) -> int
+ ge.log("message", any="field") # recorded as a "plugin" event
+ ge.commands # dict of registered commands
+```
+
+Everything a plugin records lands in the session's `events.jsonl`, so plugin
+findings are replayable and comparable like any other event.
+
+## 2. Lifecycle and safety
+
+* `register()` runs once, immediately after the session is attached and
+ symbols are loaded; the target is still stopped, so hooks are in place
+ before the first instruction.
+* A plugin that raises is recorded as `plugin_error` and skipped; it never
+ aborts the session or the other plugins.
+* Session close detaches all hooks/watchpoints, including plugin-installed
+ ones.
+* Plugins must be stdlib-only unless the dependency is documented; they are
+ development tooling and never shipped.
+
+## 3. The four plugin classes
+
+**(a) Runtime RE tools** — add analysis that green-eye does not have:
+
+```python
+def register(ge):
+ def on_state(hit):
+ ge.recorder.event("state_machine", result=hit.retval, pc=hit.pc)
+ ge.hook("rpc_state", on_leave=on_state)
+```
+
+Useful additions: allocation graphs, ring-buffer watermarks, page-table walks,
+coverage collectors built from `on_event("stop")` plus the TCG trace, entropy
+or checksum probes over structures.
+
+**(b) Harnesses** — drive the firmware and assert:
+
+```python
+def register(ge):
+ def check(session, args):
+ ctrl = session.symbols.lookup("gsp_ctrl")
+ before = session.memory.read_u64(ctrl + 0x10)
+ session.memory.write_u64(ctrl + 0x20, 1) # PING
+ session.run(duration=0.3)
+ after = session.memory.read_u64(ctrl + 0x10)
+ assert after == before + 1, "PING did not dispatch"
+ print("PING ok")
+ return 0
+ ge.add_command("check-ping", check)
+```
+
+**(c) Virtualization-environment updates** — alter how the target is built or
+driven: extra QEMU args, a rehosting shim for uproc sources, a device-model
+stub, a replay layer that feeds recorded events back into a run. Keep such
+changes behind plugin-level flags and document them in the session metadata
+(`s.recorder.meta`).
+
+**(d) AI/harness integration** — export sessions/reports to external tools,
+generate probe specs, score runs. **MCP servers are planned as a plugin**
+(`docs/08-ROADMAP.md`), not part of v0.1; do not add MCP dependencies to the
+core package before that rung is scheduled.
+
+## 4. Example plugin
+
+`plugins/example_plugin.py` demonstrates (a), (b) and logging:
+
+```python
+def register(ge):
+ ge.log("example plugin loaded")
+ def on_state(hit):
+ ge.recorder.event("plugin_state_transition", result=hit.retval)
+ if ge.symbols.get("rpc_state"):
+ ge.hook("rpc_state", on_leave=on_state)
+ ge.add_command("gehits", lambda session, args: print("…and 0"), help="…")
+```
+
+Run it with:
+
+```bash
+./greeneye.sh run examples/scripts/trace_rpc.py --plugin plugins/example_plugin.py
+```
+
+## 5. Testing a plugin
+
+1. Load it against the demo firmware (`./greeneye.sh demo --plugin …`) — the
+ session must remain green and the plugin's events must appear in
+ `events.jsonl`.
+2. Unit-test pure logic outside green-eye; keep hooks small.
+3. Never let a plugin assume a particular firmware: gate on
+ `ge.symbols.get(name)` and log a skip instead of failing.
+
+## 6. Distribution
+
+Plugins can live anywhere. For in-tree plugins that document the workflow,
+put them under `plugins/` in this tool directory; for local or
+target-specific tooling, use `GREENEYE_PLUGINS` and keep paths out of tracked
+docs (project rule).