rea/tests/conformance
The one -Niu 0baad58e60
feat(ghidra): admit RISC-V ELF analysis through a pinned generic lane (#2151)
* feat(ghidra): admit RISC-V ELF analysis through a pinned generic lane

Refs #2063.

Recognize `EM_RISCV` (243) as a provider-neutral family that carries its own ELF
facts, and bound the first Ghidra lane to little-endian `ET_EXEC` images that
declare the double-float ABI, pinned to `RISCV:LE:32:default` or
`RISCV:LE:64:default` with the `gcc` compiler specification.

Ghidra 12.1.4 is not reliable without the pin: its `riscv.opinion` pins
`variant="default"` for the 64-bit constraint and leaves the 32-bit constraint
with the comment that the loader "must choose between 'default' and 'AndeStar'
variants". Measured on the installed release tree, a source-owned generic RV32
ELF with no Andes declaration imports as `RISCV:LE:32:AndeStar_v5:gcc`, while
RV64 resolves to `RISCV:LE:64:default:gcc`. The lane therefore states the
language per width and refuses any caller-selected processor outside it instead
of inheriting the header guess.

Refusals name the declaration rather than falling back to a guessed profile:
big-endian images (Ghidra 12.1.4 ships no big-endian RISC-V language),
non-`ET_EXEC` images, `EF_RISCV_RVE`, `EF_RISCV_TSO`, and every float ABI other
than double, which the pinned generic compiler specifications model. The raw
e_flags bits stay in Evidence as declarations, not as instruction semantics.

Family recognition now has one owner for the ELF-metadata families:
`ELF_METADATA_ARCHITECTURES`, `isElfMetadataArchitecture`, and
`HeaderArchitecture` replace ten `Exclude<BinaryArchitecture, "mips">` sites that
would each have needed a second hand-edited member. `ghidraPinnedLanguage` is
that owner for the import commitment: the session readback previously re-derived
only the MIPS pin, so a profile committing any second pinned language failed with
a language-mismatch error before the bridge started.

Hopper and IDA refuse RISC-V by name, matching the MIPS wording. Caller-supplied
raw-binary entry keeps its existing four-family list; this lane is ELF-header
admission only.

Verification on macOS 15.7.7 arm64, Node 24.18.0, Ghidra 12.1.4 PUBLIC and JDK
21.0.12.1, with the host decompiler built from the release sources for
`os/mac_arm_64`: `npm run check` passes; `npm run test:fast` passes 396 test
files; `npm run verify:test-discovery` discovers all 917 test files exactly once.
Source-owned RV32 and RV64 double-float `ET_EXEC` fixtures complete
`rea analyze --provider ghidra` and `rea decompile rea_riscv_entry`, committing
`RISCV:LE:32:default` and `RISCV:LE:64:default` with `language_selection:
provider-pinned-v1`; the soft-float RV64 shape is refused with the named
float-ABI reason, and the full refusal matrix including the RV32 and
width-mismatch shapes is covered by unit tests. No `verify:ghidra:riscv` lane
script is included in this change; the runs above were performed manually against
the installed engine. Fork pull requests receive no CI check runs, so the
real-provider scope above is the evidence available for review.

* fix(ghidra): bound the RISC-V lane by declared flags and document it

Address review feedback on #2151.

`e_flags` bits outside `EF_RISCV_RVC | EF_RISCV_FLOAT_ABI` are now refused with
the offending value named, so a reserved or newer producer declaration cannot
enter the verified generic lane by falling through the RVE, TSO and float-ABI
checks.

Admission reads `e_type` only, so the refusal text no longer calls `ET_EXEC`
static: a fixed-address declaration does not establish static linkage, and
`PT_INTERP` and dynamic dependencies are not inspected. The session records that
boundary as a limitation rather than inferring a load model.

Add `docs/ghidra-riscv.md` in the shape of the MIPS lane guide (admission
boundary, refusal table, why the language is pinned per class, Evidence fields,
and what the fixtures do not establish), and correct
`docs/firmware-analysis.md`, which still told users that MIPS and RISC-V
decompilation had not been added.

Verification after the change: `npm run check` and `npm run docs:check` pass; the
RISC-V module tests pass (17 lane cases plus 9 parser cases); on Ghidra 12.1.4
with JDK 21.0.12.1 the RV32 and RV64 double-float fixtures still analyze and
decompile with `RISCV:LE:32:default` / `RISCV:LE:64:default` and
`language_selection: provider-pinned-v1`, the soft-float fixture is still refused
by name, and the new linkage limitation appears in the emitted Evidence.

* fix(ghidra): align RISC-V pinning with admission

Reuse the complete lane admission boundary when selecting a language, retain unsigned unsupported flag bits in diagnostics, and derive float ABI metadata from the source declaration.

* test(ghidra): verify RISC-V CLI and MCP workflows

Build source-owned RV32/RV64 fixtures with Clang and LLD, establish independent ELF and symbol facts with LLVM readelf, and verify real provider evidence, instruction bytes, calls, decompilation, schema projections, snapshot replay, refusal diagnostics, source immutability and cleanup.

Verified on macOS ARM64 with Ghidra 12.1.4, JDK 21 and LLVM/LLD 23.1.2. Dynamic linkage, big-endian, Andes and RVE/TSO workflows remain unverified; ISA attributes are not inspected.

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 00:11:35 +08:00
..
android fix(android): preserve executable static initializer evidence (#1876) 2026-10-11 23:40:42 +08:00
c feat(ghidra): admit RISC-V ELF analysis through a pinned generic lane (#2151) 2026-10-13 00:11:35 +08:00
contracts perf(mcp): keep Playwright and type-only imports off MCP startup (#1691) 2026-10-10 21:04:05 -07:00
ghidra feat(ghidra): admit RISC-V ELF analysis through a pinned generic lane (#2151) 2026-10-13 00:11:35 +08:00
ida fix(ida): declare GUI navigation for attached legacy analysis (#1764) 2026-10-11 01:36:56 -07:00
inspector refactor: give Inspector its own capability directory (#869) 2026-10-07 13:53:25 +08:00
interface-builder feat(native): add investigation features (#486) 2026-09-30 00:41:05 +08:00
napi test: add source-built Hopper conformance fixtures 2026-07-12 19:32:29 +08:00
native refactor: consolidate boundary semantics and prune redundant tests 2026-10-10 05:56:01 +08:00
objc fix(hopper): preserve typed string values and verify real searches 2026-10-09 05:12:36 +08:00
providers refactor: remove forwarding exports and redundant aliases 2026-10-09 22:46:09 +08:00
psp feat(ghidra): admit bounded PSP ELF through installed Allegrex (#1599) 2026-10-11 19:47:33 +08:00
readiness feat(electron): add autonomous Electron runtime analysis (#464) 2026-08-05 19:07:46 +08:00
swift fix(ghidra): classify modern Swift manglings in swift type analysis (#1208) 2026-10-09 16:10:55 +08:00
versions test: add source-built Hopper conformance fixtures 2026-07-12 19:32:29 +08:00
README.md docs: correct drift and reorganize English guides (#2207) 2026-10-12 22:14:25 +08:00
readmeConsistency.test.ts docs: align the Indonesian README with the other translations (#1512) 2026-10-10 16:26:52 +08:00
releaseConfiguration.test.ts test: consolidate redundant assertions into boundary workflows 2026-10-09 20:26:46 +08:00

README.md

Source-built conformance fixtures

These sources are deliberately small semantic oracles for REA providers. Run npm run verify:fixtures on macOS or Linux to compile them into the ignored build/conformance/ directory, emit a hash-and-toolchain manifest, and verify their platform-native symbols and strings with local command-line tools. The portable C, version, and large-inventory fixtures build as Mach-O on macOS and ELF on Linux; Objective-C, Swift, and N-API-like fixtures remain macOS-only.

Only source files are versioned. Generated binaries, generated large-fixture source, debug information, and manifests must remain under build/.

ghidra/inventory.c is also compiled into temporary Linux ELF debug and stripped variants by npm run verify:ghidra. It fixes local functions, external puts linkage, defined strings, and writable/executable memory needed to prove the read-only Ghidra inventory contracts without committing a binary.

scripts/create-ghidra-windows-fixture.mjs separately emits a deterministic, ignored native x86-64 PE application for the controlled Windows Ghidra P0 lane. The generator and fixed SHA-256 are versioned; the .exe is never committed or executed. npm run verify:ghidra:windows uses it to verify the admitted read-only operation inventory, digest linkage, transport, and cleanup on the self-hosted real-Ghidra runner.

The C fixture fixes a known call chain and strings. The version pair fixes an added symbol, changed string, and changed call relationship. The generated large fixture contains 1,205 uniquely named functions and strings to verify that providers return complete inventories. Objective-C, Swift, and N-API-like fixtures provide metadata-oriented inputs without package or network dependencies.

readiness/ adds source-only generated JavaScript CLI and Electron fixtures for the repository's reconstruction-readiness verifier. npm run verify:readiness combines them with the compiled native fixtures, exercises CLI and MCP parity for real analysis operations, and checks the internal machine-readable report documented in docs/reconstruction-readiness.md.