mirror of
https://github.com/morluto/rea.git
synced 2026-11-12 17:59:08 +00:00
* fix(elf): keep compressed storage out of decoded metadata facts * fix(elf): preserve virtual relocation identity Keep linked initializer backing and relocation values in their owning virtual or ET_REL section coordinates. Replace the IL2CPP physical-copy materializer with compact virtual value facts while preserving file-backed capacity. Reuse initializer repairs and original regressions from ShuaixinHuang PRs repair retains independent alias values instead of blanket alias refusal. Co-authored-by: 帅鑫 Huang <1836656514@qq.com> * fix(elf): admit compressed string tables the profile does not read SHF_COMPRESSED string tables are rejected only when they name sections or symbols. An unreferenced string table is not decoded, so it no longer makes an otherwise analyzable ELF unsupported. * fix(il2cpp): admit virtual pointer workspace before retention * fix(elf): reject null relocation target sections * fix(il2cpp): avoid decoding unrelated Mach-O words * fix(il2cpp): preserve uncertainty in candidate scans * fix(il2cpp): bound uncertain array candidates * fix(il2cpp): preserve unknown registration candidates * fix(il2cpp): classify type kinds before bound data * fix(il2cpp): bind candidate counts to matching names --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: 帅鑫 Huang <1836656514@qq.com>
157 lines
5.0 KiB
TypeScript
157 lines
5.0 KiB
TypeScript
import { readFile, writeFile } from "node:fs/promises";
|
|
import { createHash } from "node:crypto";
|
|
import { join } from "node:path";
|
|
import { expect } from "vitest";
|
|
import { toolContract } from "../../src/contracts/toolContracts.js";
|
|
import {
|
|
elfRelocatableCtors,
|
|
elf64AliasedInitializers,
|
|
elfUnmappedInitializerTargets,
|
|
machoArm64Initializers,
|
|
} from "../../src/native/initializers/NativeInitializers.fixture.js";
|
|
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
|
|
import { cliTest } from "../support/cli/cliFixture.js";
|
|
|
|
const contract = toolContract("inspect_native_initializers");
|
|
|
|
cliTest(
|
|
"keeps an unrelocated ELF alias's value and source identity through the CLI",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-native-init-alias-cli-");
|
|
const path = join(root, "program");
|
|
const bytes = elf64AliasedInitializers();
|
|
await writeFile(path, bytes);
|
|
const result = await cli.run({
|
|
arguments: ["inspect-native-initializers", path, "--json"],
|
|
});
|
|
expect(result.exitCode, result.stderr).toBe(0);
|
|
const report = contract.outputSchema.parse(result.json).normalized_result;
|
|
expect(report.status).toBe("parsed");
|
|
expect(report.artifact).toMatchObject({
|
|
path,
|
|
sha256: createHash("sha256").update(bytes).digest("hex"),
|
|
bytes: bytes.length,
|
|
});
|
|
expect(
|
|
report.entries.find((entry) => entry.kind === "preinit_array"),
|
|
).toMatchObject({
|
|
slot_va: "0x200",
|
|
slot_file_offset: 0x200,
|
|
value_va: "0x100",
|
|
resolution: "relative_addend",
|
|
});
|
|
expect(
|
|
report.entries.find((entry) => entry.kind === "init_array"),
|
|
).toMatchObject({
|
|
slot_va: "0x1200",
|
|
slot_file_offset: 0x200,
|
|
value_va: "0x0",
|
|
symbol: null,
|
|
resolution: "raw",
|
|
});
|
|
expect((await readFile(path)).equals(bytes)).toBe(true);
|
|
},
|
|
);
|
|
|
|
cliTest(
|
|
"lists Mach-O initializers and finalizers through the public CLI",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-native-init-cli-");
|
|
const path = join(root, "program");
|
|
await writeFile(path, machoArm64Initializers());
|
|
const result = await cli.run({
|
|
arguments: ["inspect-native-initializers", path, "--json"],
|
|
});
|
|
expect(result.exitCode, result.stderr).toBe(0);
|
|
const evidence = contract.outputSchema.parse(result.json);
|
|
expect(
|
|
evidence.normalized_result.entries.map((entry) => [
|
|
entry.kind,
|
|
entry.value_va,
|
|
entry.symbol?.name,
|
|
]),
|
|
).toEqual([
|
|
["mod_init", "0x100001000", "_init"],
|
|
["init_offsets", "0x100001000", "_init"],
|
|
["mod_term", "0x100001100", "_term"],
|
|
]);
|
|
},
|
|
);
|
|
|
|
cliTest(
|
|
"pages relocatable-object constructors with decimal options",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-native-init-cli-page-");
|
|
const path = join(root, "object.o");
|
|
await writeFile(path, elfRelocatableCtors());
|
|
const result = await cli.run({
|
|
arguments: [
|
|
"inspect-native-initializers",
|
|
path,
|
|
"--offset",
|
|
"1",
|
|
"--limit",
|
|
"1",
|
|
"--json",
|
|
],
|
|
});
|
|
expect(result.exitCode, result.stderr).toBe(0);
|
|
const evidence = contract.outputSchema.parse(result.json);
|
|
expect(evidence.normalized_result.coverage).toMatchObject({
|
|
// Every slot read counts, including the two omitted .ctors sentinels.
|
|
examined_entries: 4,
|
|
total_entries: 2,
|
|
returned_entries: 1,
|
|
offset: 1,
|
|
});
|
|
expect(evidence.normalized_result.entries[0]).toMatchObject({
|
|
index: 1,
|
|
kind: "ctors",
|
|
symbol: { name: "ctor" },
|
|
resolution: "symbol_addend",
|
|
});
|
|
},
|
|
);
|
|
|
|
cliTest("reports a truncated image as invalid input", async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-native-init-cli-bad-");
|
|
const path = join(root, "broken");
|
|
await writeFile(path, Buffer.from("\x7fELF"));
|
|
const result = await cli.run({
|
|
arguments: ["inspect-native-initializers", path, "--json"],
|
|
});
|
|
expect(result.exitCode).toBe(1);
|
|
expect(result.json).toMatchObject({
|
|
code: "invalid_request",
|
|
details: { operation: "inspect_native_initializers" },
|
|
});
|
|
});
|
|
|
|
cliTest(
|
|
"keeps unmapped ELF target locations null in public CLI Evidence",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-native-init-unmapped-cli-");
|
|
const path = join(root, "program");
|
|
await writeFile(path, elfUnmappedInitializerTargets());
|
|
const result = await cli.run({
|
|
arguments: ["inspect-native-initializers", path, "--json"],
|
|
});
|
|
expect(result.exitCode, result.stderr).toBe(0);
|
|
const evidence = contract.outputSchema.parse(result.json);
|
|
expect(
|
|
evidence.normalized_result.entries.map((entry) => [
|
|
entry.value_va,
|
|
entry.value_file_offset,
|
|
]),
|
|
).toEqual([
|
|
["0x0", null],
|
|
["0x10", null],
|
|
["0x401000", 0x100],
|
|
]);
|
|
expect(evidence.normalized_result.coverage).toMatchObject({
|
|
examined_entries: 3,
|
|
total_entries: 3,
|
|
});
|
|
},
|
|
);
|