Files
reverse-engineering-anything/tests/conformance/ghidra/ppc-fixture.mjs
T
Ariel Fikru Avicennaandmorluto c86b09a109 feat(ghidra): admit 32-bit big-endian PowerPC ELF (#1747)
* feat(ghidra): admit 32-bit big-endian PowerPC ELF

Recognize EM_PPC as a provider-neutral `powerpc` family that keeps its ELF
class, byte order, type and flags, and admit ELF32 big-endian ET_EXEC through
a bounded Ghidra lane. ELF64, little-endian, relocatable/shared objects and
EF_PPC_EMB are refused with a specific reason; Hopper and IDA do not gain
PowerPC support, and Windows Ghidra P0 is unchanged.

Ghidra's ELF loader selects PowerPC:BE:32:e500:default for a plain EM_PPC
header, which misreads 750-family code. The lane binds
PowerPC:BE:32:default/default in the profile (language_selection
"admitted-lane-v1"), imports with it and checks the reported language. A
language set through REA_GHIDRA_LANGUAGE_ID still replaces the lane default.

Add a source-owned fixture, fixed-encoding probe, GNU readelf cross-check and
the optional `verify:ghidra:ppc` real-provider lane, plus docs/ghidra-ppc.md.

Refs #1741

* style(ghidra): format shared PowerPC profile integration

* fix(ghidra): preserve caller-selected PowerPC languages

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-14 06:35:55 +08:00

63 lines
1.9 KiB
JavaScript

import { execFile } from "node:child_process";
import { createHash } from "node:crypto";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { promisify } from "node:util";
const execute = promisify(execFile);
/** Build a source-owned freestanding ELF; never execute its target code. */
export async function buildPowerPcFixture(directory) {
const compiler = process.env.REA_PPC_CLANG ?? "clang";
const target = "powerpc-unknown-linux-gnu";
const source = fileURLToPath(new URL("../c/ppc.c", import.meta.url));
const probe = fileURLToPath(new URL("./ppc-probe.S", import.meta.url));
const path = join(directory, `${target}.elf`);
const args = [
`--target=${target}`,
// A 750-family core with the classic FPU, unlike the e500 SPE variant.
"-mcpu=750",
"-fno-pic",
"-fuse-ld=lld",
"-nostdlib",
"-static",
"-O0",
"-g",
"-Wl,-e,rea_ppc_entry",
"-Wl,--build-id=none",
source,
probe,
"-o",
path,
];
const version = await execute(compiler, ["--version"], { timeout: 10000 });
await execute(compiler, args, { timeout: 60000 });
const bytes = await readFile(path);
if (
bytes.length < 52 ||
bytes.toString("hex", 0, 4) !== "7f454c46" ||
bytes[4] !== 1 ||
bytes[5] !== 2 ||
bytes.readUInt16BE(16) !== 2 ||
bytes.readUInt16BE(18) !== 20 ||
bytes.readUInt32BE(36) !== 0
)
throw new Error(
"Compiler did not produce the declared ELF32 big-endian PowerPC fixture",
);
return {
path,
flags: bytes.readUInt32BE(36),
sha256: createHash("sha256").update(bytes).digest("hex"),
source_sha256: createHash("sha256")
.update(await readFile(source))
.digest("hex"),
probe_sha256: createHash("sha256")
.update(await readFile(probe))
.digest("hex"),
compiler: version.stdout.trim(),
arguments: args,
};
}