[PR #1362] [MERGED] feat(native): admit bounded MIPS ELF analysis through Ghidra #2829

Closed
opened 2026-10-17 21:10:45 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1362
Author: @jaelliot
Created: 10/9/2026
Status: ✅ Merged
Merged: 10/10/2026
Merged by: @morluto

Base: main ← Head: feat/mips-elf-ghidra


📝 Commits (8)

  • f64ece0 feat(native): admit bounded MIPS ELF analysis through Ghidra
  • f749833 fix(ghidra): bound MIPS floating-point mode admission
  • e064d84 fix(native): validate MIPS ABI records before Ghidra admission
  • b0438d9 fix(native): repair MIPS integration boundaries and test resolver behavior
  • 03d82b7 fix(test): honor caller-selected JDK in real MIPS verification
  • adf1cda test(native): strengthen MIPS Ghidra conformance
  • 2b7f958 chore: synchronize MIPS contribution with upstream 81cdafc
  • eeeada5 fix(ghidra): preserve native-tool architecture checks after MIPS integration

📊 Changes

32 files changed (+2028 additions, -35 deletions)

View changed files

➕ docs/ghidra-mips.md (+100 -0)
📝 package.json (+1 -0)
➕ scripts/verify-real-ghidra-mips.mjs (+279 -0)
📝 src/application/BinaryTargetResolver.ts (+16 -1)
➕ src/application/MipsElfAbiFlags.ts (+153 -0)
📝 src/application/managed/ManagedApplicationGraphService.ts (+6 -9)
📝 src/contracts/toolOutputSchemaGroups.ts (+3 -2)
📝 src/domain/analysisSnapshot.ts (+5 -2)
➕ src/domain/binaryTarget.mips.test.ts (+79 -0)
📝 src/domain/binaryTarget.ts (+43 -8)
📝 src/domain/binaryTargetTypes.ts (+47 -3)
📝 src/domain/evidence.ts (+7 -3)
📝 src/ghidra/GhidraAnalysisProfile.ts (+20 -1)
📝 src/ghidra/GhidraInstallation.test.ts (+13 -0)
📝 src/ghidra/GhidraInstallation.ts (+3 -1)
➕ src/ghidra/GhidraMipsProfile.test.ts (+142 -0)
➕ src/ghidra/GhidraMipsProfile.ts (+86 -0)
📝 src/ghidra/GhidraProvider.behavior.test.ts (+2 -2)
📝 src/ghidra/GhidraProvider.ts (+17 -2)
📝 src/hopper/HopperAnalysisProfile.ts (+11 -1)

...and 12 more files

📄 Description

Scope

Advances the generic MIPS ELF follow-up in #718, not the whole firmware roadmap. PSP/Allegrex remains separate in #1330. This PR remains draft and unmerged; maintainer review of the bounded admission policy is still requested.

Current source head: eeeada5663fcb58e21f9a642bbac50ef70d16310.
Upstream revision incorporated and tested: 81cdafc132c7ba3bd6e12b1169f9e3687025d07b.

Contribution

  • Recognize ELF EM_MIPS as mips, preserving class, byte order, type, flags and ABI records separately from architecture-family identity.
  • Bound Ghidra admission to ELF32 ET_EXEC, explicit o32/MIPS32r2, either byte order and compatible version-0 ABI declarations. Missing or incompatible declarations are not guessed.
  • Read PT_MIPS_ABIFLAGS / SHT_MIPS_ABIFLAGS through the existing target handle, including beyond the initial probe; preserve cancellation and reject malformed, duplicate or conflicting records.
  • Carry architecture/profile identity through public schemas, Evidence and snapshots. Preserve unsupported Hopper/IDA and Windows P0 boundaries.
  • Add source-owned fixtures, production-boundary regressions and npm run verify:ghidra:mips. The verifier independently compares ELF/ABI/symbol observations with GNU readelf and checks observed Ghidra configuration, selected instruction/data facts, CLI/MCP consistency, snapshot reopening, input preservation and cleanup.

No emulator, commercial fixture, new MCP tool, automatic product installer or Allegrex implementation is added. PSP/PRX, MIPS64, n32/n64, MIPS16/microMIPS, vendor variants, relocatable/shared objects and unverified floating-point modes remain outside this verified profile. See docs/ghidra-mips.md for exact prerequisites and limitations.

Upstream synchronization and observed repair

2b7f9586d4f5aad0b4220de2f8971aac5d1c00ae is a real merge with parents adf1cda29859ffcc063f40418b8ba39a0eac4fab and the pinned upstream 81cdafc.... There were no textual merge conflicts, but initial integration run 38022127678 failed TypeScript compilation in the upstream-added native decompiler check.

The shared architecture union made availableArchitectures.includes(expectedArchitecture) require a never argument on a union of array types. eeeada5 uses equality-based .some(...) membership without casts or changing accepted hosts. It adds one case to the existing native-decompiler rejection table: a MIPS executable at the Linux x64 decompiler path must be rejected.

Upstream regular-file acquisition/stability checks, target-scoped snapshot validation, package/lockfile changes and architecture guards are retained. No production gate, threshold or ignore rule was relaxed.

The integrated commit was tested on temporary branches before a non-force, expected-head-checked update of the existing feature branch. Neither main branch nor either PR's draft/merge state was changed. Fork-only orchestration remains outside this contribution diff.

Verification on the integrated source

Integration verification run 38022307570, verification job 114125761674, completed successfully and explicitly checked out eeeada5663fcb58e21f9a642bbac50ef70d16310. Its orchestration commit c36f1e9c8b5b0a0fbdbf845784f86f37f2d0568e is not the tested source SHA.

Gate Observed result
Locked dependencies and package build PASS; Node 24.18.0 / npm 11.16.0
Actual focused Vitest 130 passed, 0 failed, 0 skipped, eight suites
npm run check:ci PASS; eight tasks plus current architecture guards
Architecture guards PASS across 1,806 source files; repository-design checks, not ISA proof
Test discovery PASS; all 688 current test files assigned exactly once
npm run docs:check PASS
Real Ghidra public CLI/MCP, little endian PASS
Real Ghidra public CLI/MCP, big endian PASS
Source preservation / final owned-process cleanup PASS; no live descendants

The focused total includes the existing 100 affected tests plus 30 installation tests; only one new rejection test was added during synchronization. Upstream's current test inventory differs from the earlier 700-file checkout; no suite was removed by this integration fix.

Real-provider environment: Linux x64; checksum-verified Ghidra 12.1.4, Temurin 21.0.12.1+1, Clang/LLD 18.1.3, GNU readelf 2.42. Both byte orders passed independent ELF/ABI/symbol checks, effective language/compiler and input-hash observations, fixed instruction bytes/immediate/branch destination, global value and marker, known direct call, Evidence/profile binding, snapshot reopening and equivalent CLI analysis. Neither MIPS executable was run.

New ordinary PR CI: run 38022753836 was triggered by the source-branch update and is pending at this report checkpoint. The full deterministic/coverage/platform matrix is not yet claimed as passing on the integrated source. Earlier green counts are not carried forward.

Historical evidence

At adf1cda..., ordinary CI 38002231653 passed all 19 jobs. Its merged log reports 6,254 passed and 89 skipped tests, 689 passed and 11 skipped test files (700 total), not the previously misreported 4,162/2. That run used fork test-merge e9b8bfabfdcb2c48057dad1d0299ed3fd779aa4c with the older fork base. Real-provider run 38002495944 explicitly tested adf1cda....

Another contributor's Fedora/Clang 22/readelf 2.46 report also concerns adf1cda..., not this integration. It is retained as third-party corroboration rather than a substitute for current-source validation.

Reader agreement and selected decoded properties do not prove full execution, delay-slot or floating-point equivalence. Pseudocode presence is a liveness check. Additional hosts and PSP remain separate verification claims.

Remaining gates

  • Incorporate pinned upstream without rewriting published commits.
  • Fix the observed integration failure and run affected/static/documentation gates.
  • Repeat real-Ghidra MIPS CLI/MCP verification in both byte orders.
  • Complete ordinary integrated-source PR CI.
  • Maintainer review of the proposed ABI support boundary and profile selection.

Fork development PR #1 tracks the same source branch, but its deliberately unchanged fork-main base also displays incorporated upstream commits. This upstream PR is the focused contribution diff. No request to merge automatically, close #718 or implement #1330 is implied.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1362 **Author:** [@jaelliot](https://github.com/jaelliot) **Created:** 10/9/2026 **Status:** ✅ Merged **Merged:** 10/10/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `feat/mips-elf-ghidra` --- ### 📝 Commits (8) - [`f64ece0`](https://github.com/morluto/rea/commit/f64ece01263e12d1b7373ef68ac77cac06874e65) feat(native): admit bounded MIPS ELF analysis through Ghidra - [`f749833`](https://github.com/morluto/rea/commit/f7498333c56192ce5e7bc150e5955eafabc32133) fix(ghidra): bound MIPS floating-point mode admission - [`e064d84`](https://github.com/morluto/rea/commit/e064d8473f80695332c81aa66a8bafd667e1db6d) fix(native): validate MIPS ABI records before Ghidra admission - [`b0438d9`](https://github.com/morluto/rea/commit/b0438d9037d2dee4b2dd5ee569bf0991eb04ab3b) fix(native): repair MIPS integration boundaries and test resolver behavior - [`03d82b7`](https://github.com/morluto/rea/commit/03d82b75558f355702d0c8b01aa06552f30d73f5) fix(test): honor caller-selected JDK in real MIPS verification - [`adf1cda`](https://github.com/morluto/rea/commit/adf1cda29859ffcc063f40418b8ba39a0eac4fab) test(native): strengthen MIPS Ghidra conformance - [`2b7f958`](https://github.com/morluto/rea/commit/2b7f9586d4f5aad0b4220de2f8971aac5d1c00ae) chore: synchronize MIPS contribution with upstream 81cdafc - [`eeeada5`](https://github.com/morluto/rea/commit/eeeada5663fcb58e21f9a642bbac50ef70d16310) fix(ghidra): preserve native-tool architecture checks after MIPS integration ### 📊 Changes **32 files changed** (+2028 additions, -35 deletions) <details> <summary>View changed files</summary> ➕ `docs/ghidra-mips.md` (+100 -0) 📝 `package.json` (+1 -0) ➕ `scripts/verify-real-ghidra-mips.mjs` (+279 -0) 📝 `src/application/BinaryTargetResolver.ts` (+16 -1) ➕ `src/application/MipsElfAbiFlags.ts` (+153 -0) 📝 `src/application/managed/ManagedApplicationGraphService.ts` (+6 -9) 📝 `src/contracts/toolOutputSchemaGroups.ts` (+3 -2) 📝 `src/domain/analysisSnapshot.ts` (+5 -2) ➕ `src/domain/binaryTarget.mips.test.ts` (+79 -0) 📝 `src/domain/binaryTarget.ts` (+43 -8) 📝 `src/domain/binaryTargetTypes.ts` (+47 -3) 📝 `src/domain/evidence.ts` (+7 -3) 📝 `src/ghidra/GhidraAnalysisProfile.ts` (+20 -1) 📝 `src/ghidra/GhidraInstallation.test.ts` (+13 -0) 📝 `src/ghidra/GhidraInstallation.ts` (+3 -1) ➕ `src/ghidra/GhidraMipsProfile.test.ts` (+142 -0) ➕ `src/ghidra/GhidraMipsProfile.ts` (+86 -0) 📝 `src/ghidra/GhidraProvider.behavior.test.ts` (+2 -2) 📝 `src/ghidra/GhidraProvider.ts` (+17 -2) 📝 `src/hopper/HopperAnalysisProfile.ts` (+11 -1) _...and 12 more files_ </details> ### 📄 Description ## Scope Advances the generic MIPS ELF follow-up in #718, **not** the whole firmware roadmap. PSP/Allegrex remains separate in #1330. This PR remains **draft and unmerged**; maintainer review of the bounded admission policy is still requested. **Current source head:** `eeeada5663fcb58e21f9a642bbac50ef70d16310`. **Upstream revision incorporated and tested:** `81cdafc132c7ba3bd6e12b1169f9e3687025d07b`. ## Contribution - Recognize ELF `EM_MIPS` as `mips`, preserving class, byte order, type, flags and ABI records separately from architecture-family identity. - Bound Ghidra admission to ELF32 ET_EXEC, explicit o32/MIPS32r2, either byte order and compatible version-0 ABI declarations. Missing or incompatible declarations are not guessed. - Read `PT_MIPS_ABIFLAGS` / `SHT_MIPS_ABIFLAGS` through the existing target handle, including beyond the initial probe; preserve cancellation and reject malformed, duplicate or conflicting records. - Carry architecture/profile identity through public schemas, Evidence and snapshots. Preserve unsupported Hopper/IDA and Windows P0 boundaries. - Add source-owned fixtures, production-boundary regressions and `npm run verify:ghidra:mips`. The verifier independently compares ELF/ABI/symbol observations with GNU readelf and checks observed Ghidra configuration, selected instruction/data facts, CLI/MCP consistency, snapshot reopening, input preservation and cleanup. No emulator, commercial fixture, new MCP tool, automatic product installer or Allegrex implementation is added. PSP/PRX, MIPS64, n32/n64, MIPS16/microMIPS, vendor variants, relocatable/shared objects and unverified floating-point modes remain outside this verified profile. See `docs/ghidra-mips.md` for exact prerequisites and limitations. ## Upstream synchronization and observed repair `2b7f9586d4f5aad0b4220de2f8971aac5d1c00ae` is a real merge with parents `adf1cda29859ffcc063f40418b8ba39a0eac4fab` and the pinned upstream `81cdafc...`. There were no textual merge conflicts, but [initial integration run 38022127678](https://github.com/jaelliot/rea/actions/runs/38022127678) failed TypeScript compilation in the upstream-added native decompiler check. The shared architecture union made `availableArchitectures.includes(expectedArchitecture)` require a `never` argument on a union of array types. `eeeada5` uses equality-based `.some(...)` membership without casts or changing accepted hosts. It adds one case to the existing native-decompiler rejection table: a MIPS executable at the Linux x64 decompiler path must be rejected. Upstream regular-file acquisition/stability checks, target-scoped snapshot validation, package/lockfile changes and architecture guards are retained. No production gate, threshold or ignore rule was relaxed. The integrated commit was tested on temporary branches before a non-force, expected-head-checked update of the existing feature branch. Neither main branch nor either PR's draft/merge state was changed. Fork-only orchestration remains outside this contribution diff. ## Verification on the integrated source [Integration verification run 38022307570](https://github.com/jaelliot/rea/actions/runs/38022307570), [verification job 114125761674](https://github.com/jaelliot/rea/actions/runs/38022307570/job/114125761674), completed **successfully** and explicitly checked out **`eeeada5663fcb58e21f9a642bbac50ef70d16310`**. Its orchestration commit `c36f1e9c8b5b0a0fbdbf845784f86f37f2d0568e` is not the tested source SHA. | Gate | Observed result | |---|---| | Locked dependencies and package build | PASS; Node 24.18.0 / npm 11.16.0 | | Actual focused Vitest | **130 passed, 0 failed, 0 skipped, eight suites** | | `npm run check:ci` | PASS; eight tasks plus current architecture guards | | Architecture guards | PASS across 1,806 source files; repository-design checks, not ISA proof | | Test discovery | PASS; all 688 current test files assigned exactly once | | `npm run docs:check` | PASS | | Real Ghidra public CLI/MCP, little endian | PASS | | Real Ghidra public CLI/MCP, big endian | PASS | | Source preservation / final owned-process cleanup | PASS; no live descendants | The focused total includes the existing 100 affected tests plus 30 installation tests; **only one new rejection test** was added during synchronization. Upstream's current test inventory differs from the earlier 700-file checkout; no suite was removed by this integration fix. Real-provider environment: Linux x64; checksum-verified Ghidra **12.1.4**, Temurin **21.0.12.1+1**, Clang/LLD **18.1.3**, GNU readelf **2.42**. Both byte orders passed independent ELF/ABI/symbol checks, effective language/compiler and input-hash observations, fixed instruction bytes/immediate/branch destination, global value and marker, known direct call, Evidence/profile binding, snapshot reopening and equivalent CLI analysis. Neither MIPS executable was run. **New ordinary PR CI:** [run 38022753836](https://github.com/jaelliot/rea/actions/runs/38022753836) was triggered by the source-branch update and is pending at this report checkpoint. The full deterministic/coverage/platform matrix is **not yet claimed as passing on the integrated source**. Earlier green counts are not carried forward. ## Historical evidence At `adf1cda...`, [ordinary CI 38002231653](https://github.com/jaelliot/rea/actions/runs/38002231653) passed all 19 jobs. Its merged log reports **6,254 passed and 89 skipped tests**, 689 passed and 11 skipped test files (700 total), not the previously misreported 4,162/2. That run used fork test-merge `e9b8bfabfdcb2c48057dad1d0299ed3fd779aa4c` with the older fork base. [Real-provider run 38002495944](https://github.com/jaelliot/rea/actions/runs/38002495944) explicitly tested `adf1cda...`. [Another contributor's Fedora/Clang 22/readelf 2.46 report](https://github.com/morluto/rea/pull/1362#issuecomment-6091610189) also concerns `adf1cda...`, not this integration. It is retained as third-party corroboration rather than a substitute for current-source validation. Reader agreement and selected decoded properties do not prove full execution, delay-slot or floating-point equivalence. Pseudocode presence is a liveness check. Additional hosts and PSP remain separate verification claims. ## Remaining gates - [x] Incorporate pinned upstream without rewriting published commits. - [x] Fix the observed integration failure and run affected/static/documentation gates. - [x] Repeat real-Ghidra MIPS CLI/MCP verification in both byte orders. - [ ] Complete ordinary integrated-source PR CI. - [ ] Maintainer review of the proposed ABI support boundary and profile selection. [Fork development PR #1](https://github.com/jaelliot/rea/pull/1) tracks the same source branch, but its deliberately unchanged fork-main base also displays incorporated upstream commits. This upstream PR is the focused contribution diff. No request to merge automatically, close #718 or implement #1330 is implied. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-17 21:10:45 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#2829
No description provided.