1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# 04 — writing risc-v-gsp-rm-debugger 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 risc-v-gsp-rm-debugger 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 risc-v-gsp-rm-debugger 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. The **MCP server is implemented as a bundled
plugin** (`../plugins/mcp_server.py`, see [20-MCP-SERVER](20-MCP-SERVER.md)):
stdlib-only, read-only by default, no dependency added to the core package.
## 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
./risc-v-gsp-rm-debugger.sh run examples/scripts/trace_rpc.py --plugin plugins/example_plugin.py
```
## 5. Testing a plugin
1. Load it against the demo firmware (`./risc-v-gsp-rm-debugger.sh demo --plugin …`) — the
session must remain green and the plugin's events must appear in
`events.jsonl`.
2. Unit-test pure logic outside risc-v-gsp-rm-debugger; 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).
|