Skip to content

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

Draft
jgranie wants to merge 4 commits into
morluto:mainfrom
jgranie:codex/cortex-m-raw
Draft

jgranie wants to merge 4 commits into
morluto:mainfrom
jgranie:codex/cortex-m-raw

Conversation

@jgranie

@jgranie jgranie commented Oct 18, 2026 •

Copy link
Copy Markdown

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 [Design] Caller-selected Ghidra language and base address for raw-binary imports #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 branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant