Files
Ariel Fikru Avicennaandgensokyo-dev cab78de506 feat(ghidra): analyze GameCube/Wii DOL executables through Ghidra (#6240)
* feat(domain): parse and validate GameCube/Wii DOL headers

Add a pure parser for the 0x100-byte DOL header (7 text and 11 data
slots, BSS, entry point). Used slots must lie after the header and
inside the file and the 0x80000000..0x81800000 load window; text slots
are 4-byte aligned; sections may not overlap in memory or in the file;
the entry point must be inside a text section. BSS may overlap data
sections, as .sdata/.sdata2 do in shipped DOLs.

Refs #1741

* feat(binary): admit caller-selected GameCube/Wii DOL targets

* feat(ghidra): import GameCube/Wii DOL targets through a section-map pre-script

* test(ghidra): cover DOL launcher arguments, attestation and raw profile digests

* test(ghidra): add the real verify:ghidra:dol lane and DOL docs

* fix(ghidra): read only the DOL header and section ranges instead of the whole file

* test(ghidra): derive DOL lane addresses from readelf and admit Gekko from the install catalog

* fix(ghidra): attest DOL block permissions, space, overlay and load state

* fix(ghidra): keep load-image permissions optional for older inspections

* fix(contracts): accept DOL targets in binary_session output

* fix(ghidra): adapt the DOL lane to the current upstream address schema

Validate DOL load-image coordinates with the upstream observed-address
schema, drop a duplicate import left by the rebase, and re-pin the raw
profile digests to the unmodified upstream resolver.

* fix(ghidra): preserve bridge inventory symbol provenance

* fix(ghidra): align DOL verification with shared workflow contracts

* feat(domain): parse and validate GameCube/Wii DOL headers

Add a pure parser for the 0x100-byte DOL header (7 text and 11 data
slots, BSS, entry point). Used slots must lie after the header and
inside the file and the 0x80000000..0x81800000 load window; text slots
are 4-byte aligned; sections may not overlap in memory or in the file;
the entry point must be inside a text section. BSS may overlap data
sections, as .sdata/.sdata2 do in shipped DOLs.

Refs #1741

* feat(binary): admit caller-selected GameCube/Wii DOL targets

* feat(ghidra): import GameCube/Wii DOL targets through a section-map pre-script

* test(ghidra): cover DOL launcher arguments, attestation and raw profile digests

* test(ghidra): add the real verify:ghidra:dol lane and DOL docs

* fix(ghidra): read only the DOL header and section ranges instead of the whole file

* test(ghidra): derive DOL lane addresses from readelf and admit Gekko from the install catalog

* fix(ghidra): attest DOL block permissions, space, overlay and load state

* fix(ghidra): keep load-image permissions optional for older inspections

* fix(contracts): accept DOL targets in binary_session output

* fix(ghidra): adapt the DOL lane to the current upstream address schema

Validate DOL load-image coordinates with the upstream observed-address
schema, drop a duplicate import left by the rebase, and re-pin the raw
profile digests to the unmodified upstream resolver.

* docs(ghidra): qualify the DOL memory window

* refactor(ghidra): own DOL BSS ranges in the parsed header

* docs(ghidra): record real DOL workflows and task costs

* docs(ghidra): record final DOL integration verification

* fix(mcp): share the native procedure search row contract

* docs(ghidra): record public procedure search verification

---------

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-10-24 17:56:31 +08:00

5.5 KiB

GameCube DOL analysis through Ghidra

This lane imports 32-bit big-endian PowerPC GameCube/Wii DOL images through Ghidra. It does not execute the image. DOL is a headerless format with no magic number, so REA never detects it: the caller must select it explicitly.

Only the cached MEM1 window 0x80000000..0x81800000 is admitted. Wii MEM2 and uncached aliases are outside this lane.

Not covered: small-data anchors (r2/r13), REL, RPX, and IDA or Hopper support. See Not supported yet.

Select the format

CLI:

rea inspect /absolute/path/to/main.dol --target-format gamecube-dol --provider ghidra --json
rea function /absolute/path/to/main.dol 0x80003130 --target-format gamecube-dol --provider ghidra --json

MCP, with the existing open_binary tool:

{
  "path": "/absolute/path/to/main.dol",
  "provider_id": "ghidra",
  "format": "gamecube-dol"
}

The architecture comes from the DOL header (powerpc). Do not pass architecture with gamecube-dol; it is rejected. entry_point is optional, and if given it must equal the header entry.

Omitting format never imports a file as a DOL. Detection does not run for DOL.

What the import does

REA reads the 256-byte DOL header at admission. It checks every section's file range and load address. It records BSS/data overlaps and computes the exact uninitialized BSS gaps once. Malformed headers are refused before Ghidra starts.

Ghidra then runs in two steps:

  1. The standard BinaryLoader maps the whole file at base 0x0, with -processor and -cspec taken from the language selection below.
  2. The pre-script bridge/ghidra/ReaGhidraPrepareDol.java reads a section file that REA wrote from the parsed header, with versioned collection counts. It creates one initialized block per used text and data section at its load address, with file bytes from the section's file offset. The whole-file block is removed before the section blocks are created. Text is read-execute and data is read-write. It sets the entry point and labels the entry __start.

Sections that the header marks unused are not mapped. The 256-byte header and any bytes between sections are not mapped either.

BSS

A DOL has one BSS range, and it is not always disjoint from the data sections. The domain parser computes the parts of BSS that no data section covers. Both the pre-script and load-image attestation consume those parsed ranges. The pre-script creates uninitialized read-write blocks only in those gaps. Where BSS overlaps a data slot, that slot keeps its file bytes. Overlapping slot indexes are reported by the parser.

Bound language

The default language is PowerPC:BE:32:default with compiler spec default, which ships with Ghidra. The load-image attestation checks the language Ghidra reports, not only the requested one.

Optional Gekko/Broadway override

REA_GHIDRA_LANGUAGE_ID=PowerPC:BE:32:Gekko_Broadway selects the Gekko/Broadway variant. The language is not in stock Ghidra. It comes from the GameCubeLoader extension, by Cuyler, licensed under Apache-2.0. The extension ships ppc_gekko_broadway.ldefs under its data/languages directory and must be installed in the Ghidra installation's Ghidra/Extensions directory. The stock lane never requires it.

Any other language id must start with PowerPC:BE:32:. Other languages are refused with a specific constraint.

Paired-single limitation

The stock PowerPC:BE:32:default language does not decode the paired-single instructions that Gekko and Broadway add. Those words decode as bad or undefined instructions. Use the Gekko override to decode them.

Verification

The source-owned fixture is built from tests/conformance/c/ppc.c, tests/conformance/c/dol.c, tests/conformance/ghidra/ppc-probe.S and the linker script tests/conformance/ghidra/dol-fixture.ld. It is converted to a DOL by tests/conformance/ghidra/dol-fixture.mjs. Its text is at 0x80003100, and its single BSS range overlaps data slot 1 and leaves a gap. The fixture is never executed. The real GameCube or Wii game images are never used.

GHIDRA_INSTALL_DIR=/absolute/path/to/ghidra npm run verify:ghidra:dol

The lane needs the same toolchain as the PowerPC ELF lane: REA_PPC_CLANG, REA_PPC_READELF and LLD. An independent DOL header reader and GNU readelf (run on the source ELF) check the section table, file bytes, entry and BSS gap before Ghidra starts. The checks never use REA's parser.

After import, the lane checks the load-image attestation (verified), the bound language, the __start entry procedure, a direct call to the leaf function, decompilation, and bytes at the data, tail, marker and BSS-gap addresses. It also checks CLI identity.

The Gekko pass runs only when PowerPC:BE:32:Gekko_Broadway is in the Ghidra installation's language catalog, the same catalog REA uses to admit REA_GHIDRA_LANGUAGE_ID. A language that exists only in a user extension under ~/Library/ghidra is not admitted, so the lane prints skipped: PowerPC:BE:32:Gekko_Broadway (not in the Ghidra installation catalog that REA admits); stock lane still verified and still succeeds on the stock checks.

The ELF lane (npm run verify:ghidra:ppc) is separate. See PowerPC ELF analysis through Ghidra.

Not supported yet

  • Small-data anchors: r2 and r13 are not seeded from the DOL header.
  • REL (relocatable modules) and RPX (Wii U) are not admitted.
  • IDA and Hopper refuse gamecube-dol. Ghidra is the only provider.
  • Disc images (ISO/GCM) are not supported. Pass an extracted DOL file.