Files
reverse-engineering-anything/src/domain/binaryTarget.powerpc.test.ts
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

59 lines
1.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { parseExecutableHeader } from "./binaryTarget.js";
const header = (little: boolean, bits: 32 | 64 = 32, machine = 20): Buffer => {
const bytes = Buffer.alloc(bits === 32 ? 52 : 64);
bytes.set([0x7f, 0x45, 0x4c, 0x46, bits === 32 ? 1 : 2, little ? 1 : 2, 1]);
if (little) {
bytes.writeUInt16LE(2, 16);
bytes.writeUInt16LE(machine, 18);
bytes.writeUInt32LE(1, 20);
bytes.writeUInt16LE(bytes.length, bits === 32 ? 40 : 52);
} else {
bytes.writeUInt16BE(2, 16);
bytes.writeUInt16BE(machine, 18);
bytes.writeUInt32BE(1, 20);
bytes.writeUInt16BE(bytes.length, bits === 32 ? 40 : 52);
}
return bytes;
};
describe("PowerPC ELF header boundaries", () => {
it.each([false, true])(
"retains source endian and flags (little=%s)",
(little) => {
const parsed = parseExecutableHeader(header(little), "x64");
if (!parsed.ok) throw new Error(parsed.error);
expect(parsed.value).toEqual({
format: "elf",
architecture: "powerpc",
availableArchitectures: ["powerpc"],
powerpc: {
elfClass: 32,
byteOrder: little ? "little" : "big",
type: 2,
flags: 0,
},
});
},
);
it("reads ELF64 flags at their own offset without claiming support", () => {
const bytes = header(false, 64);
bytes.writeUInt32BE(0x80000000, 48);
const parsed = parseExecutableHeader(bytes, "x64");
if (!parsed.ok) throw new Error(parsed.error);
expect(parsed.value).toMatchObject({
architecture: "powerpc",
powerpc: { elfClass: 64, byteOrder: "big", flags: 0x80000000 },
});
});
it("does not recognize EM_PPC64 as the 32-bit family", () => {
expect(parseExecutableHeader(header(false, 64, 21), "x64")).toEqual({
ok: false,
error: "unsupported ELF architecture",
});
});
});