diff options
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/harness/version_diff.py')
| -rw-r--r-- | debug/risc-v-gsp-rm-vm/harness/version_diff.py | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/debug/risc-v-gsp-rm-vm/harness/version_diff.py b/debug/risc-v-gsp-rm-vm/harness/version_diff.py index a95f244..ccc6a15 100644 --- a/debug/risc-v-gsp-rm-vm/harness/version_diff.py +++ b/debug/risc-v-gsp-rm-vm/harness/version_diff.py @@ -8,7 +8,7 @@ of aborting the report: 1. image/shape -- entry, PT_LOAD layout, ELF section sizes, hashes, span; 2. symbol inventory -- ELF ``.symtab`` plus Ghidra names/index/exports TSVs (including the 3-column ``ExportForGreenEye`` form) and - green-eye JSON DBs; added/removed/moved/resized with + risc-v-gsp-rm-debugger JSON DBs; added/removed/moved/resized with the anonymous-shift matching discipline of ``userspace/cuda/tools/diff_corpus.py``; 3. decompiled hints -- a corpus diff over two ``decompiled_index.tsv`` files, @@ -27,11 +27,15 @@ Everything is local and stdlib-only: nothing is downloaded. The RM 610 gate Run from the tool root: python3 harness/version_diff.py --old old.elf --new new.elf --out dumps/vdiff + +``--dry-run`` prints the plan (and enforces the RM 610 gate) without opening +any target or creating ``--out``. """ from __future__ import annotations import argparse import contextlib +import json import os import re import shutil @@ -102,6 +106,7 @@ from greeneye.symbols import Symbol # noqa: E402 from greeneye.target import QemuTarget # noqa: E402 FORMAT = "greeneye-version-diff/1" +PLAN_FORMAT = "greeneye-version-diff-plan/1" RM610_DOC = "docs/23-RM610-READINESS.md" RM610_TOKEN = "RM610-APPROVED" RM610_ENV = "GREENEYE_RM610_APPROVED" @@ -1218,7 +1223,7 @@ def _hex(value) -> str: def render_markdown(report: dict, options: VersionDiffOptions) -> str: old, new = report["old"], report["new"] lines = [ - "# green-eye version diff", + "# risc-v-gsp-rm-debugger version diff", "", "> **# TOOL IN DEVELOPMENT - NOT READY YET!** Generated by `harness/version_diff.py`.", "", @@ -1413,7 +1418,7 @@ def _short_json(value, limit: int = 72) -> str: def _add_side_symbols(parser: argparse.ArgumentParser, side: str) -> None: - parser.add_argument(f"--{side}-symbols", help="green-eye symbol DB JSON for the %s target" % side) + parser.add_argument(f"--{side}-symbols", help="risc-v-gsp-rm-debugger symbol DB JSON for the %s target" % side) parser.add_argument(f"--{side}-ghidra-names", help="Ghidra names.tsv for the %s target" % side) parser.add_argument(f"--{side}-ghidra-index", help="Ghidra decompiled_index.tsv for the %s target" % side) parser.add_argument( @@ -1428,7 +1433,8 @@ def build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(prog="version_diff", description=__doc__.splitlines()[0]) parser.add_argument("--old", required=True, help="old target (RISC-V ELF or raw .fwimage)") parser.add_argument("--new", required=True, help="new target (RISC-V ELF or raw .fwimage)") - parser.add_argument("--out", required=True, help="output directory for the report, sessions and DBs") + parser.add_argument("--out", help="output directory for the report, sessions and DBs (required unless --dry-run)") + parser.add_argument("--dry-run", action="store_true", help="print the plan and exit without opening targets or creating --out") parser.add_argument("--old-label", help="report label for the old target (default: file stem)") parser.add_argument("--new-label", help="report label for the new target (default: file stem)") parser.add_argument("--release", help="release label; an rm610 release is gated by docs/23") @@ -1438,7 +1444,7 @@ def build_parser() -> argparse.ArgumentParser: parser.add_argument("--corpus-diff", nargs=2, metavar=("OLD_TSV", "NEW_TSV"), help="diff two decompiled_index.tsv corpus exports") parser.add_argument("--corpus-report", help="attach a previously produced corpus diff report") - parser.add_argument("--stimulus", help="green-eye script replacing the builtin demo scenario") + parser.add_argument("--stimulus", help="risc-v-gsp-rm-debugger script replacing the builtin demo scenario") parser.add_argument("--probe-instructions", type=int, default=2000, help="probe step budget (0 = wall-clock --probe-duration)") parser.add_argument("--probe-duration", type=float, default=0.5, @@ -1456,7 +1462,7 @@ def options_from_args(args: argparse.Namespace) -> VersionDiffOptions: return VersionDiffOptions( old=args.old, new=args.new, - out=os.path.abspath(args.out), + out=os.path.abspath(args.out) if args.out else "", old_label=args.old_label, new_label=args.new_label, release=args.release, @@ -1483,9 +1489,39 @@ def options_from_args(args: argparse.Namespace) -> VersionDiffOptions: ) +def build_plan(options: VersionDiffOptions) -> dict: + """Dry-run plan: gate + targets + output layout, nothing opened.""" + check_rm610_gate(options.labels(), approval_token=options.approval_token) + return { + "format": PLAN_FORMAT, + "tool": "harness/version_diff.py", + "dry_run": True, + "status": "planned", + "rm610_gate": {"status": "passed", "labels": sorted(set(options.labels()))}, + "old": {"label": options.label_for("old"), "path": options.old}, + "new": {"label": options.label_for("new"), "path": options.new}, + "out": os.path.abspath(options.out) if options.out else "<out>", + "sections": ["image", "symbols", "corpus", "probe", "behavior"], + "corpus_diff": list(options.corpus_diff) if options.corpus_diff else None, + "reports": {"json": "version-diff.json", "markdown": "version-diff.md"}, + } + + def main(argv: list[str] | None = None) -> int: parser = build_parser() args = parser.parse_args(argv) + if args.dry_run: + options = options_from_args(args) + try: + plan = build_plan(options) + except Rm610GateError as exc: + print(f"[version-diff] RM610 gate refused: {exc}", file=sys.stderr) + return 3 + print(json.dumps(plan, indent=2, sort_keys=True)) + print("[version-diff] dry-run: no target opened, nothing written") + return 0 + if not args.out: + parser.error("--out is required unless --dry-run is used") options = options_from_args(args) try: report = run_version_diff(options) |
