diff options
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/docs/27-TOOL-AUDIT.md')
| -rw-r--r-- | debug/risc-v-gsp-rm-vm/docs/27-TOOL-AUDIT.md | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/docs/27-TOOL-AUDIT.md b/debug/risc-v-gsp-rm-vm/docs/27-TOOL-AUDIT.md new file mode 100644 index 0000000..e208253 --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/docs/27-TOOL-AUDIT.md @@ -0,0 +1,252 @@ +# 27 — green-eye tool audit + +> **# TOOL IN DEVELOPMENT - NOT READY YET!** See [00-OVERVIEW](00-OVERVIEW.md) +> for status and [06-ACCURACY](06-ACCURACY.md) for fidelity limits. +> Development-only: never shipped, never a driver dependency, never in a guest. + +Audit date: 2026-10-02. Scope: every runnable surface in +`debug/risc-v-gsp-rm-vm/` (CLI, Python package, `sim/`, `harness/`, +`plugins/`, `qemu/`, `ghidra/`, `rmharness/`, `sdk/`, firmware demo, +`examples/`, `tests/`, docs). The goal is that every tool is either exercised +somewhere, documented well enough to be unmistakable, or explicitly marked +`not used yet`. + +## 0. Method (what was actually run) + +Environment: QEMU 8.2.2 (`qemu-system-riscv64`), Python 3.12, clang/lld. +Every safe smoke below was executed from the tool root; device/WPR paths were +not touched. + +* all 13 `./greeneye.sh <cmd> --help` parsers, `--version`; +* `info`, `demo --backend native`, `record --backend native --trace`, + `analyze`, `compare`, `plugins`, `inject --backend native`; +* `probe --instructions 400` against the real 570.144 `.fwimage`; +* `launch` (bounded, QEMU killed afterwards) and the attach REPL path via + `tests/test_injection.py`; +* `symbols export` from a synthetic Ghidra index TSV, then `symbols resolve`; +* `run` of every `examples/scripts/*.py` as documented, plus the declarative + probe spec `examples/probes/demo_probes.json`; +* `make demo`, `make sdk`, `make -C qemu` (plugin already built) and a live + QEMU run with `qemu/greeneye-trace.so` (8,012,129 JSONL events in ~1 s); +* `harness/*.py --help`; `harness/value_demos/run_all.py --only s02,s05`; + `examples/scripts/sim_bench.py`, `sim_diff.py`; +* `plugin --help` / MCP suite; `rmharness/*.sh --help`, + `rmharness/harness.sh` capture with `rmtool gpu list` (read-only `/proc`); + `python3 rmharness/tests/test_rmharness_plugin.py` (3 tests); +* `python3 -m greeneye.device_map --help` and `demo` (bounded 50k + instructions, lenient MMIO); +* full suite: `python3 -m unittest discover -s tests -t .` → **155 tests, OK**; +* `python3 scripts/check-docs-links.py` from `open-iov/` → **OK, 55 files**; +* `git check-ignore -v` for the local-only ignore patterns. + +Status vocabulary: `verified useful` (exercised and/or wired into +tests/demos/docs), `not used yet` (no caller found; decision recorded), +`needs improvement` (concrete weakness; fixed where safe), `prune candidate` +(clearly dead; none found). + +## 1. Master table — `greeneye.sh` CLI + +| surface | purpose | API / entry points | tests | used by | status | notes/actions | +|---|---|---|---|---|---|---| +| `info` | environment/tooling check | `greeneye/cli.py:173`, `greeneye.sh info` | indirect (smoke) | README, 00, 02 | verified useful | ran; native sim + fwimage + CUDA names detection all correct | +| `demo` | canned demo boot + hooks/watch/diff/trap | `cli.py:209` | smoke via `test_smoke_qemu.py` | README, 00, 02; `make demo-run` | verified useful | ran on `--backend native`; 17 hook lines, diff + trap work | +| `run` | run a Python instrumentation script | `cli.py:272` | `test_injection.py` (REPL), `test_sim_trace.py` | 02, 03, examples scripts | needs improvement (fixed) | the exec namespace lacked `__file__`, so the documented `dump_diff.py` failed; namespace now sets `__file__`/`__name__`, doc 03 notes it | +| `attach` | interactive REPL | `cli.py:486`, `GreenEyeRepl` | `test_injection.py:68` | README, 02 | verified useful | REPL commands all back onto tested Session APIs | +| `launch` | start target, keep alive for attach | `cli.py:509`; `qemu/launch.sh` | smoke (bounded run) | README, 02 | verified useful | prints gdbstub endpoint; QEMU survives Ctrl-C by design | +| `probe` | run arbitrary/real firmware, report first divergence | `cli.py:551`; `test_probe.py` unit | `test_probe.py` (ELF/flat/fault parse) | README, 00, 06, 24 (`harvest` input) | verified useful | ran vs real fwimage: first fault `fault_fetch @0x0`, recorded session evidence | +| `record` | record a memory-activity session (+ native trace) | `cli.py:529` | `test_sim_trace.py` | README, 02, 03 | verified useful | ran with `--trace`; trace blob + watch events rendered by `analyze` | +| `analyze` | session → symbol-annotated report | `cli.py:690`, `greeneye/analyze.py` | `test_sim_trace.py`, `test_smoke_qemu.py` | 02, 03, 05, 13, 14, 25 | verified useful | ran on recorded session | +| `compare` | A/B recorded sessions | `cli.py:704`, `analyze.compare_sessions` | `test_sim_backend.py`, `test_value_demos.py` | 02, 03, 14, 25 | verified useful | ran demo-vs-record; correct profile deltas | +| `symbols export\|resolve` | build/inspect symbol DB | `cli.py:711` | `test_core.py` (loaders) | 05, README | needs improvement (fixed) | bad `--db` JSON produced a traceback; `SymbolDB.load_json` now raises a clean `GreenEyeError` (exit 2) | +| `plugins` | list discoverable plugins | `cli.py:733` | smoke | README, 04 | verified useful | lists all three bundled plugins | +| `inject` | load + call an injected RV64 service | `cli.py:630`; `greeneye/inject.py` | `test_injection.py` | 11, 12, 14 | verified useful | ran native: direct call and firmware mailbox both `0xbeae` | +| `ghidra` | serve session to GhidraScripts | `cli.py:660`; `greeneye/gdbridge.py` | `test_bridge.py` (full protocol) | 05, 13, 14 | verified useful | bridge protocol covered live over a socket; Java side needs Ghidra | + +## 2. Master table — Python API (`greeneye/*.py`) + +| surface | purpose | API / entry points | tests | used by | status | notes/actions | +|---|---|---|---|---|---|---| +| `__init__.py` | public API: `launch`, `attach`, exports | `ge.launch(backend=, trace=, ...)` | all integration tests | README, 02, 03 | verified useful | stable-ish v0.1 surface, documented | +| `errors.py` | exception taxonomy | `GreenEyeError` + subclasses | everywhere | 03 §13 | verified useful | small and meaningful | +| `rsp.py` | GDB-free RSP client | `RspClient`, `StopReply` | `test_rsp.py`, `test_mcp.py` | 01, 03 | verified useful | fake-stub unit tests | +| `elf.py` | ELF64/32 reader, flat kernel writer | `load_elf`, `write_flat_kernel`, `write_relocated_elf`, `FirmwareImage` | `test_core.py` (`write_relocated_elf` test added), `test_probe.py`, `test_device_map.py` | 06, 12 | verified useful | `write_relocated_elf` had no caller; a relocation test now locks its entry/PT_LOAD shift | +| `symbols.py` | symbol DB, address translation, TSV/JSON loaders | `SymbolDB.get/lookup/resolve/annotate/by_subsystem`, `Symbol` | `test_core.py` (`by_subsystem` + list/bad JSON tests added), `test_mcp.py`, `test_memory_record.py` | 03, 05 | verified useful | `load_json` list payloads worked by accident? no — they crashed; fixed and tested; parse errors now `GreenEyeError` | +| `memory.py` | read/write/hexdump/search/snapshot/diff | `Memory`, `Diff` | `test_memory_record.py` | 03 §5/§7 | verified useful | full docs in 03 | +| `structs.py` | schema-driven struct decode/render | `schema_from_json`, `Schema`, `render` | `test_core.py` | 03 §6 | verified useful | docs example matches demo schema | +| `record.py` | durable session: events.jsonl/snapshots/summary | `Recorder`, `NullRecorder`, `load_events` | `test_memory_record.py` | 01, 02, 03 | verified useful | `rmharness/harness.sh` also appends compatible events | +| `session.py` | hooks/bp/watchpoints/events/step/call | `Session`, `hook`, `watch`, `run`, `call` | `test_injection.py`, `test_mcp.py`, `test_bridge.py` | 01, 03, everywhere | verified useful | `Session.symbol_at` is a thin alias of `symbols.resolve` with no caller yet; docstring added, kept for API symmetry | +| `target.py` | QEMU process lifecycle + UART/dlog | `QemuTarget`, `find_qemu`, `free_port` | `test_smoke_qemu.py`, `test_injection.py` | 01, 02 | verified useful | `launch`/`probe` both exercise it | +| `sim_backend.py` | in-process native backend (M1) | `launch_native`, `SimClient`, `SimTarget` | `test_sim_backend.py`, `test_sim_trace.py`, `test_device_map.py`, `test_mcp.py` | README, 16, 24 | verified useful | QEMU-parity differential test | +| `analyze.py` | report renderer, fault parser, A/B compare | `render_summary`, `compare_sessions`, `describe_fault` | `test_sim_trace.py`, `test_probe.py`, `test_smoke_qemu.py` | 02, 03, 06, 25 | verified useful | consumed by CLI and value demos | +| `device_map.py` | versioned first-touch MMIO map + lenient policy | `python3 -m greeneye.device_map {harvest,show,merge,demo}` | `test_device_map.py` | 24 | verified useful | `demo` reproduced the documented first GSP access (lenient run 50k insns) | +| `gdbridge.py` | JSON-lines Ghidra control server | `GhidraBridge`, `cmd_*` | `test_bridge.py` | 05, 13 | verified useful | 25 commands; protocol tested live | +| `ghidra.py` | symbol import / hit export | `build_symbol_db`, `export_hits`, `corpus_location`, `render_ghidra_command` | `test_core.py` (TSV loaders), `test_value_demos.py` s09 (`export_hits`), `test_bridge.py` (`render_ghidra_command` test added) | 05, 13, 25 | verified useful | `render_ghidra_command` now has a test and is cited from 05 §4 | +| `inject.py` | position-independent service load/call | `load_service`, `invoke_remote`, `invoke_via_firmware` | `test_injection.py` | 11, 12 | verified useful | both call paths run in tests and in the CLI smoke | +| `plugins.py` | plugin discovery/API | `PluginManager`, `GreenEyeAPI` | `test_injection.py`; plugin smoke | 04, plugins/README | verified useful | bundled + `GREENEYE_PLUGINS` paths | +| `probes.py` | declarative JSON probes | `load_spec`, `install`, `compile_condition` | `test_smoke_qemu.py`; `demo_probes.json` smoke | 03 §9, 14 | verified useful | 3 probes installed, fired as expected; no standalone runner needed (documented snippet) | +| `cli.py` | argparse entry points (section 1) | `main`, `build_parser` | CLI smokes + integration tests | everywhere | needs improvement (fixed) | docstring now lists `launch`/`inject`/`ghidra`; `run` sets `__file__` | + +## 3. Master table — simulator, harness, plugins, host tooling + +| surface | purpose | API / entry points | tests | used by | status | notes/actions | +|---|---|---|---|---|---|---| +| `sim/decode.py` | RV64IMAC decoder | `decode32`, `decode16` | `test_sim_backend.py` | 16 | verified useful | compressed canonicalisation tested | +| `sim/machine.py` | deterministic machine, UART, lenient MMIO | `Machine`, `Uart16550` | `test_sim_backend.py`, `test_sim_trace.py`, `test_device_map.py` | 16, 24 | verified useful | no wall-clock claims (06) | +| `sim/trace.py` | native exec/access trace (R4) | `Trace` | `test_sim_trace.py` | 16, README | verified useful | trace blob rendered by `analyze` | +| `harness/common.py` | shared harness helpers | `load_target`, `write_json`, `read_faults_window`, … | `test_harness.py`, `test_discovery.py`, `test_version_diff.py` | 18–23 | verified useful | internal, well factored | +| `harness/ci_release.py` | release triage orchestration | `python3 harness/ci_release.py --old … --new …` | `test_version_diff.py` | 21 | verified useful | dry-run supported; manifest/mini-gate | +| `harness/control_discovery.py` | unknown-call discovery ("Sandsifter for RM") | CLI, `--surface demo\|rm` | `test_discovery.py` | 19, 21 | verified useful | deterministic probe generation + effect observer | +| `harness/mutation_harness.py` | bounded deterministic mutation | CLI `--iterations/--seed` | `test_harness.py` (integration, seed replay byte-identical) | 18, 20, 23 | verified useful | replayed identically in test | +| `harness/portability_matrix.py` | multi-target portability runs | CLI `--target` (repeatable) | `test_harness.py` (self-comparison all-zero deltas) | 18, 22 | verified useful | includes probe/scenario/compare sections | +| `harness/reach.py` | reachability answers for a target | CLI `--method auto\|stimulus\|trigger\|run\|call` | `test_discovery.py` | 19 | verified useful | emits suggested probe spec | +| `harness/version_diff.py` | old-vs-new firmware diff | CLI `--old/--new` | `test_version_diff.py` | 21, 25 | verified useful | composes ci_release | +| `harness/value_demos/*` | s01–s10 value validation + `run_all.py` | `python3 harness/value_demos/run_all.py [--only]` | `test_value_demos.py` | 25, MCP tools | verified useful | ran s02/s05 from the CLI; artifacts under `value_demos/artifacts/` | +| `plugins/example_plugin.py` | plugin authoring reference | `register(ge)` | plugin smoke (`--plugin`) | 04, plugins/README | verified useful | loaded via `greeneye run --plugin` | +| `plugins/mcp_server.py` | MCP server (stdio/loopback) | `--stdio`, `--tcp`, `--allow-write`, `--allow-inject` | `test_mcp.py` (431 lines) | 08/R3, 15, 20 | verified useful | read-only default; structured `not_available` fallbacks | +| `plugins/rmharness_plugin.py` | REPL commands for host RM oracle | `register(ge)`; commands `rmtool/rmtop/rmq` | `rmharness/tests/test_rmharness_plugin.py` (3 tests) | 17, 23 | verified useful | write-named args refused (`rm_harness_skip`) | +| `qemu/greeneye_trace.c` | full TCG exec/access JSONL trace | `make -C qemu`; `-plugin greeneye-trace.so,path=…` | none automated; **live-verified in this audit** | 10, 16, 14 | verified useful | 8M exec events in 1 s on the demo; vendored `qemu-plugin.h` builds out of the box | +| `qemu/launch.sh` | one-line `greeneye launch` wrapper | `qemu/launch.sh --kernel <elf>` | smoke | qemu/README | verified useful | thin `exec` of `greeneye.sh launch` | +| `ghidra/*.java` (Export/Mark/Control) | static/dynamic join inside Ghidra | `analyzeHeadless -postScript …` | protocol counterpart covered by `test_bridge.py`; no Ghidra installed here | 05, 13 | verified useful (static) | README documents exact command lines; Java not executed in this environment | +| `rmharness/rmtool.sh` | RM oracle wrapper | passthrough to `tools/rmtool` | `harness.sh` capture smoke (`gpu list`) | 17, 23 | verified useful | builds tool on first use; read-only | +| `rmharness/rmtop.sh` | dashboard wrapper | passthrough to `tools/rmtop` | `--help` | 17 | verified useful | `--once` for captures | +| `rmharness/rmq.sh` | pre-existing rmq wrapper | passthrough to `tools/rmq` | `--help` | 17 | needs improvement (fixed) | `--help` used to fall through and open the RM; wrapper now answers help itself | +| `rmharness/harness.sh` | capture tool run into a green-eye session | `--session DIR -- TOOL ARGS` | capture smoke (verified event + blobs) | 17, 22 | verified useful | additive recording; read-only allowlist enforced | +| `rmharness/tests/` | plugin registration check | `python3 rmharness/tests/test_rmharness_plugin.py` | 3 tests, run and green | 17 | needs improvement (open) | not part of `tests/` discovery nor CI; kept separate by design, documented in 17/README — consider CI step when the workflow is next edited | +| `sdk/injected_demo.c` | position-independent service SDK | `make sdk` | `test_injection.py`; `inject` smoke | 11, 12 | verified useful | direct + firmware call paths | +| `firmware/uproc_demo/` | bundled RV64 uproc (mailbox RPC/state/trap) | `make demo` | many integration tests | README, 00, 02 | verified useful | self-test + scripted stimulus work | +| `examples/scripts/dump_diff.py` | schema decode + snapshot diff demo | `./greeneye.sh run examples/scripts/dump_diff.py` | verified after `__file__` fix | 02 | needs improvement (fixed) | was broken by the `run` namespace gap; now prints decoded ctrl + changed bytes | +| `examples/scripts/trace_rpc.py` | hook every RPC handler | `./greeneye.sh run …` | ran | 02, 16, 18 | verified useful | 17 hook events from the demo | +| `examples/scripts/sim_bench.py` | native throughput benchmark | standalone CLI | ran (0.92 MIPS untraced, pure Python) | 16 | verified useful | self-bootstraps `sys.path`, works from anywhere | +| `examples/scripts/sim_diff.py` | QEMU-vs-native differential | standalone CLI | ran: `PARITY: OK` | 16 | verified useful | exit 1 on divergence, 0 on skip | +| `examples/probes/demo_probes.json` | declarative probe spec sample | loaded by `greeneye.probes.install` | installed + fired via `greeneye run` | 03 §9 | verified useful | 3 probes, hits `[1, 3, 0]` on the demo | +| `tests/` (15 files) | unit + live QEMU integration | `python3 -m unittest discover -s tests -t .` | **155 tests OK** | CI (`greeneye.yml`) | verified useful | includes live QEMU, native parity, MCP, bridge, harness, value demos | + +## 4. Scripting API purpose review + +* **Entry points and lifetime.** `ge.launch()` (QEMU or `backend="native"`) + and `ge.attach()` return a `Session`; `close()` clears breakpoints and kills + owned QEMU unless `keep_alive=True`. Documented in 03 §1 and the + `__init__` docstring. +* **`greeneye run` namespace.** Preloads `ge`, `session`/`s`, `memory`, + `symbols`, `recorder`, plus `__file__`/`__name__` (fixed here so scripts can + locate bundled assets; `examples/scripts/dump_diff.py` depends on it). + `docs/03-SCRIPTING.md` §intro now states this. +* **Static/dynamic join.** `SymbolDB` understands ELF, Ghidra name/index/ + export/callgraph TSVs and native JSON; `resolve()/annotate()` power every + report. `by_subsystem` now has a unit test; `Session.symbol_at` is an + untested-but-documented alias of `symbols.resolve`. +* **Safety.** Probe conditions are whitelisted (`compile_condition`), and the + RSP/MCP surfaces never eval user text except through that whitelist. +* **Errors.** All library errors derive from `GreenEyeError`; `load_json` now + reports file/parse failures as `GreenEyeError` instead of leaking + `JSONDecodeError` through the CLI. +* **Gaps (deliberate).** No session rewind/replay API; TCG JSONL import into + sessions is still roadmap (R4). + +## 5. Plugin API purpose review + +* **Contract.** `register(ge)`; `ge` exposes `session`, `memory`, `symbols`, + `recorder`, `hook`, `watch`, `on_event`, `add_command`, `log` + (`greeneye/plugins.py:36`, `plugins/README.md`). A raising plugin is + recorded as `plugin_error` and cannot break the session. +* **Discovery order.** `--plugin PATH` → `GREENEYE_PLUGINS` → bundled + `plugins/`. Documented in `plugins/README.md` and 04. +* **Bundled plugins.** + * `example_plugin.py` — authoring reference; loaded in this audit. + * `mcp_server.py` — the AI/agent surface; tested by `tests/test_mcp.py`, + documented in 20. The old "MCP is planned/do not add it" notes in + `plugins/README.md`, 04 and 08 are now corrected to point at 20. + * `rmharness_plugin.py` — host oracle REPL commands; tested separately. +* **Gaps.** Plugins cannot yet declare tool capabilities for MCP discovery + beyond `add_command`; `run_command` is REPL-only. Noted, not blocking. + +## 6. Unused tools and decisions + +No `prune candidate` was found: every unreferenced item was a small, coherent +public helper. Three were cheaply wired into unit tests; one remains +`not used yet` with a docstring. Nothing was deleted. + +| item | decision | rationale | +|---|---|---| +| `greeneye.symbols.SymbolDB.by_subsystem` | **wired**: docstring + `test_core.test_by_subsystem` | natural read-only query alongside `names()` | +| `greeneye.elf.write_relocated_elf` | **wired**: `test_core.test_write_relocated_elf` verifies entry/PT_LOAD shift | complete ELF utility next to `write_flat_kernel` | +| `greeneye.ghidra.render_ghidra_command` | **wired**: `test_bridge.GhidraCommandTests` + cited in 05 §4 | renders the `MarkGreenEyeHits.java` command for scripts | +| `greeneye.session.Session.symbol_at` | `not used yet`: docstring only; kept | thin alias of `symbols.resolve`; external scripts may prefer the Session namespace | + +Nothing was deleted. + +## 7. Portability / extensibility / discoverability checks + +* **Portability.** Stdlib-only Python; `greeneye.sh` pins `PYTHONPATH` to the + tool root. Harness tools and `run_all.py` bootstrap their own `sys.path`. + QEMU is optional (integration tests skip cleanly); the native backend makes + the suite largely hardware-free. `qemu-plugin.h` is vendored so the TCG + plugin builds without a QEMU source tree (verified). +* **Extensibility.** Three documented extension axes with stable contracts: + Python scripts (`run`, doc 03), JSON probe specs (`probes`, doc 03 §9), and + plugins (`register(ge)`, docs 04/20). Device behaviour is data, not code + (`greeneye-device-map/1`, doc 24). +* **Discoverability.** `README.md` + `docs/00-OVERVIEW.md` doc maps were + completed for docs 17–27 (previously they stopped at 16); `plugins/` and + `harness/` are now listed in the README layout. `greeneye.sh --help` and + `plugins/mcp_server.py --help` are self-describing. +* **CI.** `.github/workflows/greeneye.yml` builds SDK+demo and runs the main + suite on Linux; `rmharness/tests` is the only suite the workflow misses. + +## 8. How to tell if a tool is misbehaving (symptom → check → fix) + +| tool | symptom | check | fix | +|---|---|---|---| +| `greeneye.sh` / CLI | `greeneye error: …` on a valid path | `./greeneye.sh info` shows resolved paths; `--help` for arguments | correct the path/arg; check `GREENEYE_QEMU`/`GREENEYE_DUMPS`; bad symbol DBs now fail with a clear message | +| `run` scripts | `NameError: __file__` (pre-fix) or names missing | `./greeneye.sh run` preloads `ge/session/s/memory/symbols/recorder/__file__`; run with `--backend native` to remove QEMU | keep scripts inside the tool tree and invoke through `greeneye.sh run`, not bare `python3` | +| hooks/watchpoints | callback never fires | hook an obviously-hit symbol (`rpc_sum`), `record` + `analyze`; check the session event counts | re-run demo to confirm firmware self-test; ensure the target is resumed (`run`) and the symbol exists (`symbols.get`) | +| `probe` | 0 faults reported | check `dumps/<run>/blobs/qemu.log` and `recorder.meta["qemu_fault_count"]` | expected for images that stay in mapped memory; use `--instructions` for a bounded step instead of `--duration` | +| native backend / trace | QEMU-vs-native diff fails | `python3 examples/scripts/sim_diff.py`; `analyze` on the trace blob | divergence means a real backend bug: capture both sessions and diff `exec`/`access` counts (see 16) | +| `inject` | service not found or call returns garbage | `make sdk`; check slot (`--slot 0..7`) and load address; hook `rpc_dispatch` | rebuild the SDK, restore the default slot, verify `dispatch` ABI (12 §) | +| harness mutation/portability | findings not reproducible | `--seed` must be fixed; compare `findings.jsonl` byte-for-byte | if a seed diverges, the target or environment changed: capture a session and diff the baseline | +| discovery / reach | everything "unreachable" | run `--surface demo` on the built demo first; check `--timeout/--settle` | raise settle time; confirm the stimulus hook matches the firmware's mailbox | +| version diff / CI release | huge spurious diff | check symbol biases/TSVs (`--*-symbols`, `--bias`) and labels | fix the bias first; use `--dry-run` to inspect the plan before writing artifacts | +| MCP server | client sees no tools / writes refused | `python3 plugins/mcp_server.py --help`; stdout must carry only protocol frames (logs go to stderr) | remove stdout prints from plugins; pass `--allow-write`/`--allow-inject` only when intended | +| `rmharness` wrappers | `--help` opens the device (pre-fix) or permission errors | `--help` is now device-free; `rmtool gpu list/topology` read `/proc`/sysfs only | run `rmtool.sh --help` to check the build; device-table queries need the driver's permission model (17 §Not implemented) | +| `qemu/greeneye-trace.so` | empty trace file | run `make -C qemu`; QEMU must reach the `start/end` window | widen `start/end`, set `exec=on`, and resume the target (plugin records only executed code) | +| device map | unexpected `unimplemented` read | `greeneye.device_map show <map>`; check `bias` and schema version | harvest from a `probe` session with the same bias; use `unknown_mmio="lenient"` for first-touch exploration | + +## 9. Provenance discipline + +Tracked tool-tree docs describe components and behaviour; no non-public +paths, filenames or source locations appear in them. The audit re-ran the +marker scan across this tree and found none. No further action. + +## 10. Summary + +| status | count | items | +|---|---:|---| +| `verified useful` | 57 | all 13 CLI commands (2 with a fixed gap); all 19 package modules; all `sim/`; all `harness/` incl. value demos; 3 plugins; QEMU plugin + launch helper; Ghidra scripts (static); all `rmharness/` (1 fixed gap); SDK, demo firmware; 5 example assets; tests | +| `not used yet` | 1 | `session.symbol_at` — docstring added, kept (section 6) | +| `needs improvement` | 5 | `run` `__file__` namespace (**fixed**), `symbols resolve --db` traceback (**fixed**), `rmq.sh --help` device touch (**fixed**), stale doc maps/MCP/status text in README/00/04/08/14 + `plugins/README` (**fixed**), `rmharness/tests` outside main suite/CI (**open**, documented) | +| `prune candidate` | 0 | nothing deleted | + +Files changed by this audit: + +* `greeneye/cli.py` — command docstring completed; `run` namespace sets + `__file__`/`__name__`. +* `greeneye/symbols.py` — `load_json` raises `GreenEyeError` and now handles + list payloads; docstrings for `by_subsystem`, `nearest`. +* `greeneye/session.py` — docstring for `symbol_at`. +* `greeneye/ghidra.py` — docstring for `render_ghidra_command`. +* `tests/test_core.py` — tests for list/bad JSON payloads, `by_subsystem`, + `write_relocated_elf`. +* `tests/test_bridge.py` — test for `render_ghidra_command`. +* `rmharness/rmq.sh` — device-free `--help`. +* `README.md`, `docs/00-OVERVIEW.md` — doc maps completed (17–27), layout + rows for `harness/`/`rmharness/`, status-table corrections. +* `docs/03-SCRIPTING.md` — documents `__file__`. +* `docs/04-PLUGINS.md`, `docs/08-ROADMAP.md`, `plugins/README.md` — MCP is + implemented, not planned; point at 20. +* `docs/05-GHIDRA-BRIDGE.md` — documents `render_ghidra_command`. +* `docs/14-ADVERSARIAL-INTEROP-GUIDE.md` — capability table updated to + implemented harness/device-map/MCP status. +* `docs/27-TOOL-AUDIT.md` — this document. + +Verification after the changes: 155/155 unit tests OK; docs-link check OK +(55 files); every smoke in section 0 re-run green. |
