[PR #4927] feat(ghidra): support Cortex-M raw images with separate load base #6679

Open
opened 2026-11-01 21:42:15 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/4927
Author: @jgranie
Created: 10/18/2026
Status: 🔄 Open

Base: main ← Head: codex/cortex-m-raw


📝 Commits (5)

  • 36a90bc feat(native): separate raw load base from code entry
  • 1cda9f8 feat(ghidra): add explicit Cortex-M raw analysis
  • ed0d837 chore: integrate upstream main and resolve Cortex-M conflicts
  • ebb58a2 chore: retain upstream files outside Cortex-M scope
  • 14cba92 docs(raw-binary): separate processor_variant column in language table

📊 Changes

36 files changed (+1157 additions, -81 deletions)

View changed files

📝 .agents/skills/reverse-engineer-anything/references/native-and-artifacts.md (+8 -2)
📝 bridge/ghidra/ReaGhidraBridge.java (+4 -1)
📝 bridge/ghidra/ReaGhidraPrepareRaw.java (+19 -6)
📝 docs/raw-binary.md (+75 -16)
📝 docs/testing.md (+9 -0)
📝 package.json (+1 -0)
➕ scripts/verify-real-ghidra-cortex-m.mjs (+260 -0)
📝 scripts/verify-real-ghidra-raw.mjs (+80 -1)
📝 src/application/BinaryTargetResolver.ts (+20 -5)
📝 src/application/DirectAnalysis.ts (+40 -1)
📝 src/application/binary/BinarySessionOpen.ts (+12 -1)
📝 src/application/binary/BinarySessionPort.ts (+3 -0)
📝 src/application/binary/BinaryTargetSummary.ts (+11 -1)
📝 src/cli/coreBinaryCommands.ts (+4 -0)
📝 src/cli/options.ts (+29 -2)
📝 src/contracts/sessionLifecycleInputs.test.ts (+42 -0)
📝 src/contracts/sessionLifecycleInputs.ts (+30 -8)
📝 src/contracts/sessionToolContracts.ts (+1 -1)
📝 src/contracts/toolOutputSchemaGroups.ts (+9 -1)
📝 src/domain/analysisSnapshot.test.ts (+21 -0)

...and 16 more files

📄 Description

Summary

Raw Cortex-M firmware images can now be imported without treating their vector data as the code entry. Add an optional independent load base and an explicit Cortex/Thumb profile to the existing Ghidra raw-binary workflow.

Refs #4246. This draft offers a bounded, real-provider-verified Cortex-M use case for that discussion; it does not presume a maintainer decision on generic language passthrough.

Problem and expected behavior

The existing raw import maps file offset zero at entry_point and seeds a function there. This misinterprets images with leading data, while the generic ARM language is unsuitable for a Thumb-only Cortex-M image. The source-owned fixture here has vector data before its entry and an absolute data pointer.

base_address / --base-address now selects the file mapping independently. Omission preserves the previous entry-based mapping. processor_variant: "cortex-m" / --processor-variant cortex-m explicitly selects ARM:LE:32:Cortex; omitting the variant preserves generic ARM. Code entries must be even; odd Thumb function pointers are rejected rather than silently modified.

Change and scope

Two commits separate the prerequisite load-address change from Cortex-M support. Admission owns validation/canonicalization; sessions, snapshots, profiles, CLI/MCP results and load-image attestation carry the same interpretation. Ghidra checks Thumb context before disassembly and reports it for independent attestation.

  • Semantic owner and earliest changed stage: src/domain/rawBinary.ts, before provider selection.
  • CLI/MCP contract: additive optional base and processor-variant inputs; raw load-image entry offsets may be nonzero.
  • Compatibility: existing calls remain valid. The raw analysis-profile revision intentionally invalidates older raw snapshots. Base or variant changes partition sessions/snapshots; equivalent base spellings reuse them.
  • Provider/authority: existing static Ghidra provider, Linux/macOS lane. Windows P0 remains raw-6502-only. No new provider, target execution, device access, arbitrary script interface, or mutation of original input bytes.
  • Scope decision: existing static-analysis authority; no new runtime/injection/protection-recovery capability. API design feedback remains welcome in #4246 and this draft.
  • Package/setup: one development verifier command and source-owned fixture; no dependency, engine installation, client configuration or release-version change.

Expected effects:

  • Read existing files or captured data.
  • Launch analysis processes (Ghidra/JVM).
  • Run fixed internal analysis scripts in the temporary Ghidra database; no target execution.
  • Write owned temporary analysis/cache files; original input bytes remain unchanged.
  • Contact network services as part of the analysis capability.
  • Recover protected code or work around protections.

Evidence and regression coverage

Executed on macOS arm64, Ghidra 12.1.2, full JDK 21, pinned Node 24.18.0/npm 11.16.0:

  • Focused suite: 345 passed, 5 platform-specific skips, across 11 files: admission, target resolution, snapshots, load-image attestation, provider/launcher, CLI/MCP boundaries, verifier prerequisites and XML parsing.
  • npm run verify:ghidra:raw — passed with real CLI/MCP, independent base/entry mappings, canonical reuse, different-base partitioning, ARM/x86/x86-64 controls, unchanged source bytes and complete cleanup.
  • npm run verify:ghidra:cortex-m — passed with real CLI/MCP at zero and nonzero bases: Thumb context, call references, decompilation, source-offset lookup, odd-pointer rejection preserving the active session, generic ARM profile preservation, unchanged sources and complete cleanup.
  • Cortex verifier summary: ok:true, mocked:false, cli_mcp_load_image_parity:true, thumb_context_verified:true, decompilation:true, cleanup:"complete". Both inputs are 100-byte source-owned Cortex-M0 fixtures; no vendor firmware is included.

The base control reproduces the former import assumption; the implementation no longer seeds code at the mapping base when the caller selects a different entry. Missing or wrong observed Thumb context produces a load-image mismatch.

Validation performed

Revalidated on 2026-10-22 after merging upstream b6007e0:

  • npm run check and npm run check:ci — passed, including full formatting, typecheck, lint, knip, metadata, architecture guards, duplicate/TODO checks, discovery and 91 Python tests.
  • npm run docs:check — passed, including 9 README consistency tests.
  • npm run verify:test-discovery — 1,997 test files discovered exactly once.
  • Both real Ghidra verifiers above were rerun successfully after the merge. Sources remained unchanged; cleanup completed with no live descendants.

Upstream synchronization and prior CI failures

The two conflicts in DirectAnalysis.ts and cli/options.ts are resolved by retaining upstream cancellation handling and the simplified CLI mapping, while forwarding the independent base and Cortex-M variant. A merge commit preserves the two existing contribution commits for ongoing human review.

The earlier CI failures were the XML test formatting issue and a Linux prerequisite test whose restricted PATH hid ps. Both upstream fixes are included via #4930 (1accac2). The prerequisite boundary test now passes locally; Linux Actions results remain separate evidence. No CI gate, assertion, timeout or workflow was weakened. At head ebb58a2, the new CI run reports action_required with no jobs started; upstream approval is still required. Current-head Linux Actions results are unverified.

Compatibility and remaining proof gaps

Linux real-provider execution, Windows and Ghidra 12.1.4 were not exercised here. The fixture covers Cortex-M0 instructions, not every Cortex-M ISA variant, floating-point ABI or TrustZone. No reset/peripheral emulation, device memory-map discovery or automatic vector-table discovery is added. The caller supplies the load base and even code entry. This draft is not a claim that vendor firmware behavior or a physical device has been qualified.

Author readiness

Human owner: @jgranie

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

🔄 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/4927 **Author:** [@jgranie](https://github.com/jgranie) **Created:** 10/18/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `codex/cortex-m-raw` --- ### 📝 Commits (5) - [`36a90bc`](https://github.com/morluto/rea/commit/36a90bc9b8bde654a92786dd8f94edc6c6a71572) feat(native): separate raw load base from code entry - [`1cda9f8`](https://github.com/morluto/rea/commit/1cda9f8f311d7aa9f3c53d398c21d7a7c845a265) feat(ghidra): add explicit Cortex-M raw analysis - [`ed0d837`](https://github.com/morluto/rea/commit/ed0d837949482e2c5c5abb4944773a883db4355c) chore: integrate upstream main and resolve Cortex-M conflicts - [`ebb58a2`](https://github.com/morluto/rea/commit/ebb58a22d2101596a4afb0280b125ca51b4ccb8f) chore: retain upstream files outside Cortex-M scope - [`14cba92`](https://github.com/morluto/rea/commit/14cba92db98aa5a5aa15299b6ed2b24b06a64272) docs(raw-binary): separate processor_variant column in language table ### 📊 Changes **36 files changed** (+1157 additions, -81 deletions) <details> <summary>View changed files</summary> 📝 `.agents/skills/reverse-engineer-anything/references/native-and-artifacts.md` (+8 -2) 📝 `bridge/ghidra/ReaGhidraBridge.java` (+4 -1) 📝 `bridge/ghidra/ReaGhidraPrepareRaw.java` (+19 -6) 📝 `docs/raw-binary.md` (+75 -16) 📝 `docs/testing.md` (+9 -0) 📝 `package.json` (+1 -0) ➕ `scripts/verify-real-ghidra-cortex-m.mjs` (+260 -0) 📝 `scripts/verify-real-ghidra-raw.mjs` (+80 -1) 📝 `src/application/BinaryTargetResolver.ts` (+20 -5) 📝 `src/application/DirectAnalysis.ts` (+40 -1) 📝 `src/application/binary/BinarySessionOpen.ts` (+12 -1) 📝 `src/application/binary/BinarySessionPort.ts` (+3 -0) 📝 `src/application/binary/BinaryTargetSummary.ts` (+11 -1) 📝 `src/cli/coreBinaryCommands.ts` (+4 -0) 📝 `src/cli/options.ts` (+29 -2) 📝 `src/contracts/sessionLifecycleInputs.test.ts` (+42 -0) 📝 `src/contracts/sessionLifecycleInputs.ts` (+30 -8) 📝 `src/contracts/sessionToolContracts.ts` (+1 -1) 📝 `src/contracts/toolOutputSchemaGroups.ts` (+9 -1) 📝 `src/domain/analysisSnapshot.test.ts` (+21 -0) _...and 16 more files_ </details> ### 📄 Description ## Summary Raw Cortex-M firmware images can now be imported without treating their vector data as the code entry. Add an optional independent load base and an explicit Cortex/Thumb profile to the existing Ghidra raw-binary workflow. Refs #4246. This draft offers a bounded, real-provider-verified Cortex-M use case for that discussion; it does not presume a maintainer decision on generic language passthrough. ## Problem and expected behavior The existing raw import maps file offset zero at `entry_point` and seeds a function there. This misinterprets images with leading data, while the generic ARM language is unsuitable for a Thumb-only Cortex-M image. The source-owned fixture here has vector data before its entry and an absolute data pointer. `base_address` / `--base-address` now selects the file mapping independently. Omission preserves the previous entry-based mapping. `processor_variant: "cortex-m"` / `--processor-variant cortex-m` explicitly selects `ARM:LE:32:Cortex`; omitting the variant preserves generic ARM. Code entries must be even; odd Thumb function pointers are rejected rather than silently modified. ## Change and scope Two commits separate the prerequisite load-address change from Cortex-M support. Admission owns validation/canonicalization; sessions, snapshots, profiles, CLI/MCP results and load-image attestation carry the same interpretation. Ghidra checks Thumb context before disassembly and reports it for independent attestation. - Semantic owner and earliest changed stage: `src/domain/rawBinary.ts`, before provider selection. - CLI/MCP contract: additive optional base and processor-variant inputs; raw load-image entry offsets may be nonzero. - Compatibility: existing calls remain valid. The raw analysis-profile revision intentionally invalidates older raw snapshots. Base or variant changes partition sessions/snapshots; equivalent base spellings reuse them. - Provider/authority: existing static Ghidra provider, Linux/macOS lane. Windows P0 remains raw-6502-only. No new provider, target execution, device access, arbitrary script interface, or mutation of original input bytes. - Scope decision: existing static-analysis authority; no new runtime/injection/protection-recovery capability. API design feedback remains welcome in #4246 and this draft. - Package/setup: one development verifier command and source-owned fixture; no dependency, engine installation, client configuration or release-version change. Expected effects: - [x] Read existing files or captured data. - [x] Launch analysis processes (Ghidra/JVM). - [x] Run fixed internal analysis scripts in the temporary Ghidra database; no target execution. - [x] Write owned temporary analysis/cache files; original input bytes remain unchanged. - [ ] Contact network services as part of the analysis capability. - [ ] Recover protected code or work around protections. ## Evidence and regression coverage Executed on macOS arm64, Ghidra 12.1.2, full JDK 21, pinned Node 24.18.0/npm 11.16.0: - Focused suite: **345 passed, 5 platform-specific skips**, across 11 files: admission, target resolution, snapshots, load-image attestation, provider/launcher, CLI/MCP boundaries, verifier prerequisites and XML parsing. - `npm run verify:ghidra:raw` — passed with real CLI/MCP, independent base/entry mappings, canonical reuse, different-base partitioning, ARM/x86/x86-64 controls, unchanged source bytes and complete cleanup. - `npm run verify:ghidra:cortex-m` — passed with real CLI/MCP at zero and nonzero bases: Thumb context, call references, decompilation, source-offset lookup, odd-pointer rejection preserving the active session, generic ARM profile preservation, unchanged sources and complete cleanup. - Cortex verifier summary: `ok:true`, `mocked:false`, `cli_mcp_load_image_parity:true`, `thumb_context_verified:true`, `decompilation:true`, `cleanup:"complete"`. Both inputs are 100-byte source-owned Cortex-M0 fixtures; no vendor firmware is included. The base control reproduces the former import assumption; the implementation no longer seeds code at the mapping base when the caller selects a different entry. Missing or wrong observed Thumb context produces a load-image mismatch. ## Validation performed Revalidated on 2026-10-22 after merging upstream `b6007e0`: - `npm run check` and `npm run check:ci` — passed, including full formatting, typecheck, lint, knip, metadata, architecture guards, duplicate/TODO checks, discovery and 91 Python tests. - `npm run docs:check` — passed, including 9 README consistency tests. - `npm run verify:test-discovery` — 1,997 test files discovered exactly once. - Both real Ghidra verifiers above were rerun successfully after the merge. Sources remained unchanged; cleanup completed with no live descendants. ## Upstream synchronization and prior CI failures The two conflicts in `DirectAnalysis.ts` and `cli/options.ts` are resolved by retaining upstream cancellation handling and the simplified CLI mapping, while forwarding the independent base and Cortex-M variant. A merge commit preserves the two existing contribution commits for ongoing human review. The earlier CI failures were the XML test formatting issue and a Linux prerequisite test whose restricted PATH hid `ps`. Both upstream fixes are included via #4930 (`1accac2`). The prerequisite boundary test now passes locally; Linux Actions results remain separate evidence. No CI gate, assertion, timeout or workflow was weakened. At head `ebb58a2`, the new [CI run](https://github.com/morluto/rea/actions/runs/39745393683) reports `action_required` with no jobs started; upstream approval is still required. Current-head Linux Actions results are unverified. ## Compatibility and remaining proof gaps Linux real-provider execution, Windows and Ghidra 12.1.4 were not exercised here. The fixture covers Cortex-M0 instructions, not every Cortex-M ISA variant, floating-point ABI or TrustZone. No reset/peripheral emulation, device memory-map discovery or automatic vector-table discovery is added. The caller supplies the load base and even code entry. This draft is not a claim that vendor firmware behavior or a physical device has been qualified. ## Author readiness Human owner: @jgranie - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [ ] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [ ] I declare this PR ready for initial maintainer review. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
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#6679
No description provided.