From 6c3fd5df61ff2f5cb8833ead6c05eaff9fdc92bf Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Tue, 6 Oct 2026 19:28:39 -0400 Subject: risc-v-gsp-rm-debugger: land docs 45-53 + harness/sim tool set with tests rm_capture (chunked decode), launch_audit, state_seed/state_decode, valprobe, rehost, contracts+run_contracts, host_traffic, gmmu_walk, msgq_attach, libos_port, log_decode, server_snapshot; doc index updates in the tool overview, operations pages and the repo README. --- debug/risc-v-gsp-rm-vm/harness/server_snapshot.py | 698 ++++++++++++++++++++++ 1 file changed, 698 insertions(+) create mode 100644 debug/risc-v-gsp-rm-vm/harness/server_snapshot.py (limited to 'debug/risc-v-gsp-rm-vm/harness/server_snapshot.py') diff --git a/debug/risc-v-gsp-rm-vm/harness/server_snapshot.py b/debug/risc-v-gsp-rm-vm/harness/server_snapshot.py new file mode 100644 index 0000000..1099fb0 --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/harness/server_snapshot.py @@ -0,0 +1,698 @@ +#!/usr/bin/env python3 +"""Collect a canonical server-state snapshot from cycle evidence directories. + +The differential loop (live run vs emulated run, run N vs run N+1) needs one +machine-readable view of the server state a cycle produced. Cycles already +write that state as text: labelled field variables (``LABEL[offset]=0xVALUE``), +labelled hexdump blocks (an ``INSTANCE[0000]: w w w w``-style row, or a header +line naming the label followed by ``OFFSET: w w w w`` rows -- e.g. +``LOGINIT-raw`` / ``LOGRM-raw`` raw task-log dumps), and ``vgsp-nocat`` record +lines carrying ``recType=`` / ``errorCode=``. This harness discovers those +files under evidence/session directories, normalizes every dump to +little-endian u32 words, and emits one JSON snapshot that two runs can be +compared with ``diff``. + +Schemas +------- + +``greeneye-server-snapshot/1``:: + + {"schema": "greeneye-server-snapshot/1", + "source": "", + "created": "", + "chunks": [{"label": "INSTANCE", "base": "0x0", + "words": ["0x00000000", ...]}], + "records": [{"kind": "record", "raw": "...", + "rec_type": 5, "error_code": 0x57f1344, + "source_name": "ASSERT"}]} + +``greeneye-server-snapshot-diff/1``:: + + {"schema": "greeneye-server-snapshot-diff/1", + "a": {"source": ..., "created": ...}, "b": {...}, + "chunks": [{"label": "INSTANCE", "status": "changed|added|removed|unchanged", + "base": {"a": "0x0", "b": "0x0"}, + "words": {"a": 1024, "b": 1024}, + "added": [{"index": 8, "value": "0x00000000"}], + "removed": [{"index": 8, "value": "0x00000001"}], + "changed": [{"index": 8, "a": "0x...", "b": "0x..."}]}], + "records": {"added": [...], "removed": [...]}, + "summary": {"identical": false, "chunks_added": 0, ...}} + +Normalization rules (the consumer depends on them): + +* words are 8-hex-digit lowercase strings of little-endian u32 values; +* a ``LABEL[offset]=0xVALUE`` value wider than 32 bits becomes two words + (low word first); its offset orders the entries and selects ``base``, and + the values are appended in offset order (the offset is a table index there, + not a byte address); +* hexdump rows are placed by byte offset (``(offset - base) // 4``) when + 4-byte aligned, so a row missing in one run still aligns the rest; +* ``base`` is the smallest offset seen for the chunk (``0x0`` when none); +* chunks are sorted by label; a repeated label is merged only when its base + and word list are byte-identical, otherwise it is kept as ``LABEL#2``, + ``LABEL#3`` ... and the collision is reported in the run stats; +* non-empty records are deduplicated by raw line and sorted by raw line; +* ``created`` is the only variable field: pin it with ``--created`` or + ``SOURCE_DATE_EPOCH`` for deterministic output. + +Honesty: this is an evidence normalizer, not a state oracle. It preserves +what the cycle wrote -- offsets are honoured, identical duplicates are merged, +differing duplicates are renamed, and dump-looking lines that fail to parse +are counted (``unparsed``) instead of being silently dropped. It never +executes anything, touches no GPU and reads only files given on the command +line. +""" +from __future__ import annotations + +import argparse +import fnmatch +import json +import os +import re +import sys +import tempfile +import time +from typing import Any, Iterable + +TOOL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +if TOOL_ROOT not in sys.path: + sys.path.insert(0, TOOL_ROOT) + +SNAPSHOT_FORMAT = "greeneye-server-snapshot/1" +DIFF_FORMAT = "greeneye-server-snapshot-diff/1" +DEMO_FORMAT = "greeneye-server-snapshot-demo/1" + +#: File-name globs discovered under each ``--dir`` unless extended with +#: ``--include``. fnmatch's ``*`` matches leading dots, so the rolling host +#: dmesg captures (``.dmesg-*.rolling``) are covered by ``*.rolling``. +DEFAULT_INCLUDES = ("*.txt", "*.log", "*.rolling") + +#: ``INSTANCE[0000]: w w w w`` -- one labelled dump row inside an arbitrary +#: prefix (dmesg timestamp, subsystem, case id). Offsets are hexadecimal. +_INLINE_ROW_RE = re.compile( + r"(?P