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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
|
# 26 — risc-v-gsp-rm-debugger architecture: full picture, workflow and API surfaces
> Status: implemented, documented and tested (audit: docs/27-TOOL-AUDIT.md; value demos: docs/25-VALUE-VALIDATION.md).
> The architecture map for the risc-v-gsp-rm-debugger suite: how the pieces fit, which
> surface to call, and which document specifies each part. Every claim here is
> implemented in the tree or explicitly marked as a gated roadmap design.
> Development-only: never shipped, never a driver dependency, never in a guest.
## 1. What risc-v-gsp-rm-debugger is (and is not)
risc-v-gsp-rm-debugger runs GSP/uproc firmware in a controllable machine, observes it with
Frida-like primitives, records a durable session, changes the machine's inputs
(including injected code), and compares runs as evidence for `vgsp`
emulation changes.
| It is | It is not |
|---|---|
| A firmware runtime microscope (execution + memory, L0/L1) | A time, interrupt or device model (L2/L3 absent — [06](06-ACCURACY.md)) |
| A scriptable `Session` API with two backends | A GDB wrapper; there is no GDB dependency |
| A recorded-evidence system with a versioned format | A product component or a guest agent |
| A static/dynamic join with Ghidra | A decompiler or a CUDA-corpus replacement |
| An automation layer (harnesses, MCP, CI) | A fuzzing service against hardware; simulator/re-hosted code only |
## 2. The suite as a whole
```text
front doors control plane evidence
CLI/REPL/scripts ─┐
MCP (stdio) ──────┼─► GreenEyeAPI ─► Session ─┬─► QEMU-RSP backend ──┐
Ghidra bridge ────┤ (plugins) Memory │ qemu-system-riscv64│
harness/ ─────────┤ SymbolDB └─► native backend ────┼─► session dir
rmharness ────────┘ Recorder sim/machine.py │ events.jsonl
└─► analyze / compare /
export_hits / bundles
```
```mermaid
flowchart LR
CLI["CLI/REPL/scripts"] --> CORE
MCP["MCP server"] --> CORE
GH["Ghidra bridges"] --> CORE
HAR["harness/*.py"] --> CORE
RMH["rmharness (read-only)"] --> CORE
CORE["GreenEyeAPI + Session<br/>hooks, watchpoints, call, run_until<br/>Memory, SymbolDB, Recorder"]
CORE --> QB["QEMU-RSP backend"] --> SESS
CORE --> NB["native backend (M1/M1.5)"] --> SESS
SESS["session dir, greeneye-session/1"] --> REP["analyze / compare / export_hits / MCP / bundles"]
RMH --> SESS
```
Status: transport, core, recording, both backends (native M1 trace included),
injection ABI v1, both Ghidra bridges, traces, device map, harnesses, MCP (R3)
and `rmharness` are implemented and exercised. The `Backend` protocol
refactor (16 §5), the H2.2 QEMU device model, RM-core injection (H1.3) and the
H3 M2–M6 milestones are design/roadmap only ([16](16-CUSTOM-SIMULATOR.md)).
## 3. Session core: hooks, watchpoints and dispatch
`Session` ([greeneye/session.py](../greeneye/session.py)) owns all stop-driven
state and is backend-agnostic: every stop reads registers, resolves the PC,
records an event, invokes matching hooks/watchpoints, then resumes.
```mermaid
sequenceDiagram
S->>FW: set breakpoint / watchpoint
loop run(duration, max_stops)
FW-->>S: stop reply (T/S/W)
S->>S: resolve PC via SymbolDB
S->>R: bp_hit / watch_hit / stop / step
alt symbol entry
S->>H: on_enter(hit) with a0..a7
S->>S: arm return breakpoint from ra (LIFO)
S->>FW: continue
else return breakpoint
S->>H: on_leave(hit), a0 as retval
else watchpoint (Z2/Z3/Z4)
S->>FW: clear watch, step over store, re-arm
S->>H: callback + store PC
end
S->>R: on_event(kind, hit)
end
S->>R: session_end on close
```
| Primitive | Semantics / limits |
|---|---|
| `breakpoint(addr, kind=sw\|hw, temporary=)` | sw is stepped over transparently; hw uses the backend's `Z1` |
| `hook(target, on_enter, on_leave)` | leave is a return breakpoint on `ra`; tail calls/interrupt returns are not tracked |
| `watch(target, size, kind=w\|r\|a, callback)` | QEMU stops *at* the access; Session clears/steps/re-arms; store PC is recorded |
| `run(duration, max_stops)` | services stops until a budget or exit; the deadline path interrupts once |
| `run_until(target, timeout)` | temporary breakpoint; raises `RspTimeout` when not reached |
| `call(target, args, timeout)` | Frida-like remote call; restores `RESTORE_REGS` around it |
| `step(n)`, `note(text)`, `on_event(kind, fn)` | single-step with dispatch; annotate and observe the stream |
Instructions between stops are invisible unless the TCG plugin
(`qemu/greeneye_trace.c`) or the native trace (`sim/trace.py`) is on
(01 §11, 16 §1.1a).
## 4. Backend abstraction: QEMU-RSP and native
`Session` assumes a small RSP-shaped primitive set; `run_until` and `call`
live above it and work on every backend. M1 implements the same method
surface (`greeneye/sim_backend.py`) without the planned `Backend` protocol
refactor (16 §5); the table is the M2+ target.
```mermaid
flowchart LR
S["Session (backend-independent)"]
S -->|"read/write reg+mem, step, continue, Z0-Z4"| RC
S -->|"same surface"| ST
subgraph QEMU["QEMU-RSP backend (default)"]
QT["QemuTarget<br/>qemu-system-riscv64 virt"] --- RC["RspClient gdbstub packets"]
end
subgraph NAT["Native backend (--backend native)"]
ST["SimTarget / SimClient"] --- MC["sim.machine.Machine<br/>RAM + UART + decode loop"]
MC --- TR["sim.trace.Trace exec/access"]
MC --- DM["DeviceMap lenient MMIO"]
end
```
| Session need | QEMU-RSP | Native |
|---|---|---|
| registers/memory | `g`/`p`/`P`, `m`/`M`/`X` chunked to `PacketSize` | direct register file and memory map |
| breakpoints/watchpoints | `Z0`–`Z4` | dispatch-loop tables; same stop semantics |
| snapshots | region copies over RSP | direct map copy; machine moments are M2+ |
| virtual time | host wall clock | deterministic instruction count (`SIM_IPS`) |
| full-access trace | TCG plugin (`-plugin`) | in-process `sim/trace.py`, `--trace` |
| device environment | QEMU `virt` only (no TU104) | device map + lenient MMIO; real devices H2.2 |
| injection | debugger writes + `Session.call` | same SDK ABI; RM interception is M5 |
`--backend qemu|native` is accepted by `demo`, `run`, `attach`, `record`,
`inject` and `ghidra`; `attach --port` and QEMU `--trace` are QEMU-only;
`--trace` is native-only (16 §1.2).
## 5. Recording and the evidence format
A session directory is the durable artifact (`greeneye-session/1`,
[greeneye/record.py](../greeneye/record.py)). The event stream is the map; the
snapshot and blob files are the dump.
```text
dumps/<stamp>-<name>/
session.json # format, name, created, counts, snapshot inventory, meta
events.jsonl # append-only JSON lines: {"t": monotonic, "type": ...}
snapshots/*.bin.z # zlib-compressed region captures (sha256 recorded)
blobs/* # QEMU logs, trace.jsonl, rmharness stdout, plugin dumps
summary.md # rendered analysis
```
```mermaid
flowchart LR
E["Session stops, memory ops,<br/>probe/plugin/injection events"] --> R["Recorder.event()"]
R --> J["events.jsonl (append-only)"]
M["Memory.snapshot()"] --> Z["snapshots/*.bin.z + sha256"]
B["Recorder.blob()"] --> BD["blobs/*: trace.jsonl, qemu.log"]
X["rmharness external runs"] --> J
J --> A["analyze: summary.md"]
J --> C["compare: A/B delta report"]
J --> G["export_hits: greeneye_hits.tsv"]
J --> S10["value_demos s10: manifest + M1-M6 skeleton"]
```
Event classes: core stop/memory events (`session_start`, `image_loaded`,
`hook`, `watch`, `bp_hit`, `leave`, `watch_hit`, `stop`, `step`, `mem_read`,
`mem_write`, `snapshot*`, `probe*`, `plugin*`, `note`, `exit`, `session_end` —
01 §6); injection (`service_injected`, `call_enter`, `call_return` — 12 §6);
traces (`exec`/`access`); M2/M3 native bus (`device`/`irq`/`schedule` — 16
§10); `rmharness` (`rm_harness_run`, `t=0.0` with epoch `start`/`end` — 17 §5).
Format invariants: append-only (partial sessions stay readable); additive
versioning with migration notes (V2); `compare` treats `t`, host paths and
backend identity as non-semantic; a claim without a session is not evidence
(06 §7, 25 §1).
## 6. Injection SDK lifecycle
The SDK (`sdk/greeneye_service.h`, `sdk/injected_demo.c`) builds
position-independent ELF64 `EM_RISCV` blobs; `greeneye/inject.py` loads,
registers and invokes them. ABI v1: `ge_u64 (*)(ge_u64 cmd, ge_u64 a0,
ge_u64 a1)`, magic `0x47455356`, entry `ge_demo_service_dispatch`.
```mermaid
sequenceDiagram
Dev->>Inj: load_service(elf, slot=6, load_addr)
Inj->>FW: write PT_LOAD segments into RAM
Inj->>FW: patch gsp_ctrl.handlers[slot] entry
Inj->>Rec: service_injected + mem_write events
Dev->>Inj: invoke_remote(cmd, a0, a1)
Inj->>FW: Session.call(entry, args)
Rec-->>Rec: call_enter / call_return
Dev->>FW: mailbox = 16 + slot (arg0=cmd, arg1, arg2)
FW->>FW: dispatch handlers[slot]
FW-->>Rec: hook/watch events + result field
```
Demo registration: mailbox commands 16..23 select slots 0..7; slot 6 is the
SDK default; control-block offsets (`mailbox +0x20`, `handlers +0x150`) are
demo-specific and must come from `greeneye/inject.py` constants (12 §4).
Cleanup is not automatic in v1; record the injection so runs start from a
known state. Roadmap: RM-core shim, service registry and `log`/`stub`/
`forward` interception at M5/H1.3 (12 §8, 16 §11).
## 7. Ghidra bridges (two directions)
The static/dynamic join uses three address spaces — file vaddr, Ghidra program
addr, runtime addr — with a bias per source (01 §5, 05 §1).
```mermaid
sequenceDiagram
G->>B: {"id":n,"cmd":"run_until","args":{"target":"0x..."}}
B->>S: run_until(addr) (temporary breakpoint)
S->>T: continue; service intervening stops
T-->>S: stop at addr
S-->>B: {addr, symbol, kind}
B-->>G: JSON response
G->>B: read_mem / read_reg / call / snapshot / hits / export_hits
B->>R: hits and notes recorded in the session
R-->>G: greeneye_hits.tsv (via MarkGreenEyeHits.java)
```
| Tool | Purpose | Doc |
|---|---|---|
| `symbols export` + `SymbolDB` loaders | Ghidra TSV/JSON → runtime symbol DB | [05](05-GHIDRA-BRIDGE.md) |
| `greeneye.ghidra.export_hits` | session hits → `addr<TAB>hits<TAB>symbol<TAB>annotation` | 05 |
| `ExportForGreenEye.java` | Ghidra → `addr<TAB>name<TAB>size` TSV | 05 |
| `MarkGreenEyeHits.java` | annotate functions with runtime hits + bookmarks | 05 |
| `GreenEyeControl.java` + `risc-v-gsp-rm-debugger.sh ghidra` | drive a live session from GhidraScripts over localhost JSON-lines | [13](13-GHIDRA-CONTROL.md) |
Bridge commands: `ping`, `info`, `resolve`, `bp_set`, `bp_clear`, `bp_list`,
`watch_set`, `run_until`, `run`, `step`, `read_mem`, `write_mem`, `read_reg`,
`write_reg`, `call`, `snapshot`, `note`, `hits`, `export_hits`, `close`
(13 §3). Unauthenticated by design; localhost only.
## 8. MCP server tool surface
`plugins/mcp_server.py` serves the active `Session` over JSON-RPC 2.0 on
stdio (or loopback TCP) with no MCP library; read/observe by default,
`write_mem`/`call_function` require `--allow-write`, `inject_service`
requires `--allow-inject` ([20](20-MCP-SERVER.md)).
```mermaid
flowchart LR
AG["AI agent (Claude Code, opencode)"] -->|"JSON-RPC 2.0 over stdio"| M["plugins/mcp_server.py"]
M --> READ["read: session_info, symbols_resolve,<br/>read_mem, hexdump, snapshot, plugins_list"]
M --> OBS["observe: bp_set/clear, watch_set,<br/>run, run_until, step (recorded)"]
M --> WR["write (gated): write_mem, call_function"]
M --> INJ["inject (gated): inject_service"]
M --> TR["trace: trace_start/stop"]
M --> AN["analysis: analyze_current, compare_sessions, export_hits"]
M --> HN["harness: probe_firmware, mutation_run,<br/>portability_matrix_run"]
M --> CL["session: close"]
READ & OBS & WR & INJ & TR & AN & HN --> S["Session + Recorder"]
```
All results are one JSON text block; absent modules return a structured
`not_available` error; stdout carries protocol frames only (20 §4, §8). Full
argument schemas for all 31 tools are in 20 §5.
## 9. Automation harness
`harness/` turns the playbooks into repeatable, self-describing runs. Modules
bootstrap the tool root and use the QEMU backend by default (18, 19, 21, 28,
29); `common.py` provides flat-image relocation, session helpers and bounded
log reads.
```mermaid
flowchart TB
FW["firmware ELF / .fwimage"] --> PM & MU & CD & RE & VD & LV
SYM["Ghidra exports + symbol DBs"] --> PM & MU & CD & RE & VD & LV
STIM["stimulus / probe spec"] --> PM & MU & CD & RE & VD & LV
SEED["seed + budgets"] --> PM & MU & CD & RE & VD & LV
subgraph H["harness/"]
PM["portability_matrix.py R6/H4.1"]
MU["mutation_harness.py R5/H4.3"]
CD["control_discovery.py H4"]
RE["reach.py H4.1/H4.5"]
VD["version_diff.py H4.1"]
CR["ci_release.py"]
LV["value_demos/ s01..s10"]
end
VD --> CR
PM --> CR
MU --> CR
PM & MU & CD & RE & VD & LV & CR --> OUT["reports + sessions + findings.jsonl<br/>+ compare/ + bundle-manifest.json"]
```
| Entry point | Purpose | Outputs | Doc |
|---|---|---|---|
| `portability_matrix.py` | probe + symbols + fixed scenario + compare across targets; M1–M6 skeleton | `portability-report.json/.md`, `symbols/`, `sessions/`, `compare/` | 18 §1 |
| `mutation_harness.py` | seeded one-input mutation, outcome classes, per-attempt session | `findings.jsonl`, `summary.md`, `sessions/` | 18 §2 |
| `control_discovery.py` | sweep command/call surfaces; classify handler/default/trap/fault | `findings.jsonl`, `discovery-report.json`, `control-discovery.md` | 19 §3 |
| `reach.py` | reachability, trigger discovery, required args and effects for one symbol | `reach-report.json/.md`, `probe.json`, sessions | 19 §4 |
| `version_diff.py` | old vs new image: shape, symbols, corpus hints, probe, behavior, M1–M6 | `version-diff.json/.md`, `corpus/`, `compare/` | 21 §2 |
| `ci_release.py` | version_diff → matrix → mutation smoke, then hash the bundle | `release-report.json`, `bundle-manifest.json` | 21 §4 |
| `value_demos/run_all.py` | ten fixed scenarios (reply, counters, discovery, reach, diff, inject, version, mutation, Ghidra, evidence) | `artifacts/results.json` + per-demo JSON | 25 |
| `port_driver_versions.py` | version-list sweep of version_diff + matrix + mutation (dry-run default; unadmitted pilot) | per-version bundles + `sweep-summary.json/.md` | 28 §2 |
| `port_new_device.py` | device-port scaffold: profile, probe, symbols, matrix, checklist (dry-run default; unadmitted pilot) | `device-port.json/.md`, `port-checklist.json/.md`, bundle | 28 §3 |
| `package_sim.py` | build/run a trial simulation package (unadmitted pilot) | package tree + `manifest.json`, `results.json` | 29 |
| `common.py` | shared setup (relocate to `0x80000000`, open session, bounded logs) | library | 18 §1.2 |
Harness limits are intentional: QEMU/re-hosted/demo code only; no hardware,
guest, kernel module or existing gdbstub; bounded budgets; deterministic
findings for a fixed seed (18 §5, 19 §8, 21 §7).
## 10. Device map and lenient MMIO data flow
`greeneye-device-map/1` is versioned JSON keyed by
`(address, width, direction)` with values, hit counts and firmware PCs
([24](24-DEVICE-MAP.md)). It records what the firmware touched first and lets
the native interpreter step past unmodelled registers to collect the next
ones; it feeds the H2.2 QEMU device model and the H3 profile DSL.
```mermaid
flowchart LR
P["risc-v-gsp-rm-debugger.sh probe (raw .fwimage in QEMU)"] -->|"blobs/qemu.log + qemu_first_fault"| H["device_map.py harvest"]
H --> MAP["greeneye-device-map/1<br/>entries + meta (bias, sha256)"]
MAP --> LOOK["DeviceMap.lookup<br/>zero / value / unimplemented"]
LOOK --> LEN["Native Machine(unknown_mmio=lenient)"]
LEN --> LOG["machine.mmio_log / mmio_unknown"]
LEN --> LEARN["learn_mmio=True: source trace entries"]
LEARN --> MAP
MAP --> PROF["docs/16 profile DSL<br/>falcon/csb/ptimer/pmu stubs"]
PROF --> H22["H2.2 QEMU device model"]
LOG --> NEXT["next unmapped wall; promote to manual"]
NEXT --> MAP
```
Honest scope: lenient execution proves an unmodelled access *can* be served
deterministically; it does not model read-back, side effects, interrupts or
timing, and a zero that keeps the firmware running is a hypothesis, not a
silicon fact (24 §4).
## 11. Workflow architecture: scenario → evidence → emulation change
The canonical loop (H4.5, 06 §5, 07 P4, 25 §7). Each stage names its gate.
| Stage | Action / instrument | Success criterion | Failure signal |
|---|---|---|---|
| 1. Scenario | state the firmware question and the smallest stimulus (one command/control/boot phase) | question maps to a symbol or surface | no observable exists → add one (probe/plugin) |
| 2. Choose instrument | hooks/watchpoints for semantics; TCG/native trace for coverage; `run_until`/`call` for reachability; injection for new code | stop set answers the question without flooding | session too large/noisy → filter PCs, watch fields only |
| 3. Run | fresh bounded session; fixed stimulus, seed and budgets | run completes; UART/banner liveness holds | timeout, trap loop, wedged target → capture and retry clean |
| 4. Record | `greeneye-session/1` with snapshots and notes | events + snapshots + hashes written | missing `session.json`/empty analyzer → recording off |
| 5. Compare | `compare` against a reference (old firmware, hardware/VFIO capture, self-diff) | deltas explained symbolically; self-diff is zero | unexplained hit/watch/write delta → investigate first |
| 6. Decide | fill M1–M6 with the reference method (06 §5); mutation/triage for error paths | metric table improves or stays equal | metric claimed without a reference capture |
| 7. Implement | change `vgsp` (never the simulator for a product fix); keep the stimulus | physical confirmation for behaviour changes (06 §6, 14 §7) | product change from a simulator-only observation |
| 8. Regression | re-run step 3 with an unchanged stimulus; golden sessions/CI (`make test`, `risc-v-gsp-rm-debugger.yml`) | profile improves or stays equal; CI green | regression → revert and re-derive |
```mermaid
flowchart LR
Q["Question"] --> OBS["Observe<br/>probe / hooks / watch / trace"]
OBS --> ORI["Orient<br/>analyze + symbol decode + snapshots"]
ORI --> DEC["Decide<br/>compare + M1-M6 + mutation"]
DEC --> ACT["Act<br/>implement in vgsp"]
ACT --> REG["Regression<br/>same stimulus, same budgets"]
REG -->|"improved / equal"| SHIP["Evidence pack<br/>sessions + report + hashes"]
REG -->|"regressed"| Q
SHIP --> OBS
```
OODA compression evidence (analog, measured) is in 25 §7: hardware cycles are
minutes and campaigns hours/days; the risc-v-gsp-rm-debugger path for the same question
class is sub-second to seconds plus scripting.
## 12. API surfaces by tool
### 12.1 CLI (`risc-v-gsp-rm-debugger.sh`, `greeneye/cli.py`; usage in [02](02-USAGE.md))
| Command | Purpose | Not for |
|---|---|---|
| `info` | environment/tooling check | validating a firmware image |
| `demo` | canned boot + hooks + watch + record on the bundled uproc | booting real GSP (use `probe`) |
| `run <script.py>` | run a Python instrumentation session | shell pipelines (write Python) |
| `attach` / `launch` | interactive REPL / keep a target alive by port | injecting into a live product |
| `record` | boot and record with watches/snapshots/trace | post-processing an existing session |
| `probe <image>` | bounded run of a raw image; first divergence report | booting the image (no TU104 model) |
| `inject` | load/register/invoke an SDK service | shipping or hot-patching signed firmware |
| `ghidra` | serve a live session to GhidraScripts | network exposure (localhost only) |
| `analyze <session>` / `compare <a> <b>` | markdown report / symbolic A/B delta | proving accuracy without a reference |
| `symbols export\|resolve` | build/inspect a symbol DB | recovering types/decompilation |
| `plugins` | list discoverable plugins | loading untrusted code into the core |
| `python3 -m greeneye.device_map harvest\|show\|merge\|demo` | MMIO first-touch map data | a device model or timing source |
### 12.2 Python entry points (recipes in [03](03-SCRIPTING.md))
| Entry point | Purpose | Not for |
|---|---|---|
| `ge.launch/attach`, `Session.hook/watch/run/run_until/call/step/note` | session lifecycle and instrumentation | in-process C instrumentation |
| `Memory.read/write/hexdump/search_*/snapshot/diff/render_diff` | memory inspection and region diff | full-machine snapshots (M2+) |
| `SymbolDB.load_elf/*_tsv/*_json`, `resolve/annotate` | address-space-aware symbols | type recovery from Ghidra |
| `structs.schema_from_json/decode/render` | declarative struct decoding | automatic struct discovery |
| `probes.load_spec/install` | JSON probe specs (no arbitrary code) | complex control flow (write a script) |
| `inject.load_service/invoke_remote/invoke_via_firmware` | ABI v1 service load/invoke | product features or persistence |
| `ghidra.build_symbol_db/export_hits/corpus_location` | Ghidra TSV in/out and corpus location | replacing Ghidra analysis |
| `analyze.render_summary/compare_sessions/parse_qemu_faults/load_trace` | offline reports and QEMU fault parsing | live control |
| `record.Recorder/load_events/load_meta` | session writing/reading | a database (files are the interface) |
| `device_map.harvest_*/DeviceMap.*` | MMIO map authoring/merge | device semantics |
| `sim_backend.launch_native`, `sim.trace.Trace/make_trace` | native backend + trace knobs | timing/concurrency claims |
| `errors.*` (`GreenEyeError`, `RspTimeout`, ...) | typed failure surface | retrying a wedged target blindly |
### 12.3 Plugin API (`register(ge)`, [04](04-PLUGINS.md))
`ge` exposes live objects (`session`, `memory`, `symbols`, `recorder`),
instrumentation (`hook`, `watch`, `on_event`, `resolve`), CLI extension
(`add_command(name, fn, help)`, `commands`) and audit logging (`log`). A
raising plugin is recorded as `plugin_error` and skipped. Not for: shipping
dependencies, assuming a specific firmware, or hiding unrecorded state.
## 13. Extensibility and invariants
Where extension lives:
* **Plugins** (`plugins/`, `GREENEYE_PLUGINS`) — runtime RE tools, harnesses,
environment updates, agent integrations (04).
* **Harness modules** (`harness/`) — new sweeps/reports over the public
`Session`/analysis primitives; a new call surface is a `Surface` subclass
(19 §5.1).
* **SDK services** (`sdk/`) — PIC blobs behind ABI v1; v2 adds an RM-core call
table (12 §8).
* **Device maps/profiles** — versioned data (`greeneye-device-map/1`, the
`greenmachine-profile/1` DSL in 16 §7), never core special cases.
* **MCP tools** (`plugins/mcp_server.py`) — add tools in the plugin, keep the
core stdlib-only (20 §10).
Invariants (enforced by tests or review):
1. **stdlib-only core**: `greeneye/` and `sim/` import only the standard
library; optional deps live in plugins/harnesses.
2. **Session format**: `greeneye-session/1` is append-only and evolves
additively with migration notes (V2).
3. **Backend parity**: every backend satisfies the same `Session` primitives,
so scripts, probes, plugins, recordings and comparisons survive backend
changes (16 §4, R0).
4. **ABI**: blobs declare an ABI version and capability metadata; breaking
changes need a shim and a doc note (12 §8, V3).
5. **Markers**: the in-development notices were removed on 2026-10-02 after
the tool audit (27) and value demos (25); gated items stay marked as such.
Never shipped, never in a guest, never a driver dependency.
6. **Evidence**: no accuracy, portability or security claim without a recorded
A/B session and an explicit L2/L3 fidelity statement (06 §5–6, 25 §10).
7. **Provenance**: tracked docs describe components and behaviour;
conclusions cite recorded evidence (V6).
## 14. Diagram and document index
Section diagrams and their backing docs: §2 suite (00, 01, README); §3
dispatch (01, 03); §4 backends (01 §8, 16 §4–5); §5 recording (01 §6, 09, 12
§6, 16 §10, 17 §5); §6 injection (11, 12); §7 Ghidra (05, 13); §8 MCP (20);
§9 harness (18, 19, 21, 28, 29); §10 device map (24, 16 §7); §11 OODA (06, 07 P4, 25
§7). Roadmap keys: R3 = MCP (08), R5 = mutation (18), R6 = multi-version (18,
21), H1.3 = RM service injection (RISC-V-GSP-RM-DEBUGGER-ROADMAP), H2.2 = QEMU device
model, H3/M1–M6 = native simulator (16), H4 = adversarial navigation (14),
H7 = agentic platform (15, 20).
<!-- change (2026-10-02): list the docs 28/29 harness scripts in the automation
table and index so the architecture map matches the tree; scope: §9, §14 only;
benefit: the newest entry points are discoverable and labelled as pilots. -->
|