mirror of
https://github.com/morluto/rea
synced 2026-10-27 14:42:18 -04:00
9c14999efd
* feat(ghidra): admit raw NMOS 6502 analysis * test(ghidra): require verified POSIX verifier cleanup * test(ghidra): verify 6502 low-memory raw imports * docs(skill): document raw NMOS 6502 support * fix(ghidra): preserve requested Windows raw source paths * docs(ghidra): include raw 6502 in Windows installation scope * test(ghidra): verify Windows raw junction rejection through CLI and MCP * fix(validation): make fixtures portable and preserve explicit Codex home * fix(ghidra): attest raw mapping state and address space * fix(ghidra): align diagnostics and regression groups * fix(ghidra): bind raw attestation to language address space * chore(ghidra): avoid verifier insertion conflict * docs(ghidra): align linked raw admission guides * fix(ghidra): retain 6502 verifier workspace on failure * test(ghidra): isolate Windows authority doctor fixture * fix(binary): re-admit Windows raw paths on session reopen * test(binary): require fresh provider execution after path change * Constrain 6502 to raw lifecycle and snapshot targets * Bypass saved reads for unadmitted Windows paths * Guard direct CLI snapshot replay on Windows paths * fix(snapshot): gate Windows Ghidra replay on native admission * fix(snapshot): constrain nested 6502 subjects to raw images * test: make dyld slice fixtures portable
106 lines
6.3 KiB
Markdown
106 lines
6.3 KiB
Markdown
# RISC-V ELF analysis through Ghidra
|
||
|
||
This lane extends native ELF analysis for `EM_RISCV` targets. It does not
|
||
execute RISC-V code, emulate a boot sequence, or rehost firmware. It addresses
|
||
[#2063](https://github.com/morluto/rea/issues/2063) and follows the same
|
||
lane shape as [generic MIPS support](ghidra-mips.md).
|
||
|
||
## Admission boundary
|
||
|
||
ELF `EM_RISCV` (243) is retained as the provider-neutral `riscv` family. The
|
||
target also retains the raw ELF declarations that decide a lane: class, byte
|
||
order, `e_type`, and `e_flags`. Recognition does not mean every provider or
|
||
RISC-V variant is supported. Existing PE, managed and Mach-O architecture sets
|
||
are unchanged. Headerless inputs use the separate [raw-binary admission
|
||
boundary](raw-binary.md); raw RISC-V images are not supported.
|
||
|
||
The Ghidra lane admits little-endian ELF32 and ELF64 `ET_EXEC` images that
|
||
declare `EF_RISCV_FLOAT_ABI_DOUBLE` in `e_flags`, with no `EF_RISCV_RVE`,
|
||
`EF_RISCV_TSO`, or any bit outside `EF_RISCV_RVC | EF_RISCV_FLOAT_ABI`. These are
|
||
header declarations, not proof that every instruction conforms to that ISA.
|
||
|
||
Provider selection returns the specific unsupported constraint rather than
|
||
guessing a compatible profile:
|
||
|
||
| Declaration | Outcome |
|
||
| ----------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
||
| Little-endian ELF64 `ET_EXEC`, double-float ABI | admitted, `RISCV:LE:64:default` + `gcc` |
|
||
| Little-endian ELF32 `ET_EXEC`, double-float ABI | admitted, `RISCV:LE:32:default` + `gcc` |
|
||
| Big-endian | refused; Ghidra 12.1.4 ships no big-endian RISC-V language |
|
||
| `ET_REL`, `ET_DYN`, other `e_type` | refused with the declared value |
|
||
| `EF_RISCV_RVE` | refused; the embedded 16-register profile (x0–x15) needs its own processor specification |
|
||
| `EF_RISCV_TSO` | refused; the total-store-order memory model is unverified here |
|
||
| Soft, single, or quad float ABI | refused; the pinned generic compiler specification models double-float |
|
||
| Reserved or newer `e_flags` bits | refused with the offending bits named |
|
||
|
||
`e_type` is the only load-shape declaration this lane reads. A fixed-address
|
||
`ET_EXEC` declaration does **not** establish static linkage: `PT_INTERP` and
|
||
dynamic dependencies are not inspected, and the session records that boundary as
|
||
a limitation rather than inferring a load model.
|
||
|
||
## Why the language is pinned
|
||
|
||
Ghidra's header-based selection is not reliable for RV32. The 12.1.4
|
||
`riscv.opinion` pins `variant="default"` for the 64-bit constraint and leaves the
|
||
32-bit constraint unpinned with the comment that the loader "must choose between
|
||
'default' and 'AndeStar' variants". Measured against the installed release tree:
|
||
|
||
| Fixture | Ghidra auto-selection |
|
||
| ----------------------------------------------- | ----------------------------- |
|
||
| RV64 ELF, `e_flags 0x5` (RVC, double-float ABI) | `RISCV:LE:64:default:gcc` |
|
||
| RV32 ELF, `e_flags 0x5`, no Andes declaration | `RISCV:LE:32:AndeStar_v5:gcc` |
|
||
|
||
So an ordinary RV32 image lands on an Andes processor model unless the language
|
||
is stated. REA therefore pins `RISCV:LE:32:default` or `RISCV:LE:64:default`
|
||
with the `gcc` compiler specification per class, records
|
||
`language_selection: provider-pinned-v1`, and refuses a caller-selected
|
||
`REA_GHIDRA_LANGUAGE_ID` or `REA_GHIDRA_COMPILER_SPEC_ID` that disagrees with the
|
||
pin without changing the requested override. An override that matches the pin is
|
||
accepted and recorded as `configured-v1`.
|
||
|
||
## Evidence
|
||
|
||
The lane identity is `elf32-exec-le-double-float-generic-v1` or
|
||
`elf64-exec-le-double-float-generic-v1`, and `riscv_elf` retains `elf_class`,
|
||
`byte_order`, `type`, and the raw `flags` alongside the read-only booleans
|
||
`float_abi_double`, `rvc_declared`, `rve_declared`, and `tso_declared`. Those
|
||
fields report declarations the header makes; none of them is evidence of the
|
||
original compiler, of instruction conformance, or of a floating-point calling
|
||
convention beyond the ABI the pinned language models.
|
||
|
||
## Verification and limits
|
||
|
||
Ghidra 12.1.4 PUBLIC with a 64-bit JDK 21+ is required, and on macOS the release
|
||
tree ships no host decompiler binary, so `Decompiler/os/<platform>/decompile` and
|
||
`sleigh` must come from your own build; see
|
||
[installation](installation.md#ghidra).
|
||
|
||
Run `npm run verify:ghidra:riscv` with an existing Ghidra 12.1.4 installation,
|
||
JDK 21+, and a RISC-V-capable Clang, LLD and LLVM readelf. The verifier acquires
|
||
no tools and never executes target code. Select installed tools explicitly when
|
||
they are not on `PATH`:
|
||
|
||
```sh
|
||
GHIDRA_INSTALL_DIR=/path/to/ghidra_12.1.4_PUBLIC \
|
||
JAVA_HOME=/path/to/jdk-21 \
|
||
REA_RISCV_CLANG=/path/to/llvm/bin/clang \
|
||
REA_RISCV_LLD=/path/to/lld/bin/ld.lld \
|
||
REA_RISCV_READELF=/path/to/llvm/bin/llvm-readelf \
|
||
npm run verify:ghidra:riscv
|
||
```
|
||
|
||
The lane builds the committed freestanding C and assembly sources into RV32 and
|
||
RV64 `ET_EXEC` fixtures. Independent LLVM readelf observations establish ELF
|
||
declarations and symbol addresses. Public CLI and stdio MCP workflows verify
|
||
function enumeration, decompilation, pinned language/compiler identity, decoded
|
||
probe bytes, global data, and direct calls. It validates advertised MCP output
|
||
schemas and both JSON representations, saves and reopens snapshots, rejects
|
||
header-mutated soft-float and unsupported high-bit declarations, and checks
|
||
unchanged source bytes and owned cleanup. Failures retain the diagnostic
|
||
workspace; successful runs remove it and report the observed process lineage.
|
||
|
||
Module tests cover admission and malformed headers. Call-graph completeness,
|
||
string inventories, dynamic linkage, Andes or RVE/TSO images, and big-endian
|
||
targets are **not** established by this lane. `.riscv.attributes` ISA extensions
|
||
are not inspected; the generic language pin remains an analysis convention.
|