mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
99d2d7ad22
Share bounded ELF section-name decoding across native and note readers; retain read-only ranges and coverage reasons when names are unknown. Preserve ELF symbol-version bytes, dyld-bound method uncertainty, partial gRPC-Web trailers, and per-parent model identity checks. Compare GPU signatures as bytes and require a PTX module header. Share selected-path errno classification across EVM and BEAM. Validation: 397 shared-parser tests passed (one existing skip), 5 MCP schema tests passed, 14 EVM error-mapping tests passed, and 23 protobuf CLI/MCP matrix cases passed across focused runs. Build, typecheck/lint, docs, formatting, and 2134-file discovery passed. Full EVM provider workflow remains locally unverified on Darwin arm64; format controls are synthetic. Fixes #6738 Fixes #6737 Fixes #6745 Fixes #6740 Fixes #6749 Fixes #6747 Fixes #6739
136 lines
4.1 KiB
TypeScript
136 lines
4.1 KiB
TypeScript
import {
|
|
declaredFileRange,
|
|
BinaryFormatFailure,
|
|
BinaryReader,
|
|
type BinaryContainer,
|
|
type FileMapping,
|
|
type ImageSection,
|
|
type LoadRegion,
|
|
type ZeroFillMapping,
|
|
} from "./BinaryContainer.js";
|
|
import { elfArchitecture } from "../../domain/elfFixedHeader.js";
|
|
import { readNativeDirectoryFromBuffer } from "./NativeSectionDirectory.js";
|
|
|
|
/** Read ELF sections and file-backed program mappings without interpreting language metadata. */
|
|
export const readElfImage = (bytes: Buffer): BinaryContainer => {
|
|
const directory = readNativeDirectoryFromBuffer(bytes, "elf");
|
|
const {
|
|
bits,
|
|
program_offset: phOffset,
|
|
program_count: phCount,
|
|
program_width: phWidth,
|
|
} = directory;
|
|
const reader = new BinaryReader(bytes, directory.little);
|
|
const wide = bits === 64;
|
|
const phStart = reader.table(
|
|
phOffset,
|
|
phCount,
|
|
phWidth,
|
|
"ELF program headers",
|
|
);
|
|
const mappings: FileMapping[] = [];
|
|
const loadRegions: LoadRegion[] = [];
|
|
const executableMappings: FileMapping[] = [];
|
|
const zeroFills: ZeroFillMapping[] = [];
|
|
const sections: ImageSection[] = [];
|
|
for (let index = 0; index < phCount; index++) {
|
|
const offset = phStart + index * phWidth;
|
|
if (reader.u32(offset) !== 1) continue;
|
|
const flags = reader.u32(offset + (wide ? 4 : 24));
|
|
const fileOffset = reader.word(offset + (wide ? 8 : 4), bits);
|
|
const address = reader.word(offset + (wide ? 16 : 8), bits);
|
|
const size = reader.word(offset + (wide ? 32 : 16), bits);
|
|
const memorySize = reader.word(offset + (wide ? 40 : 20), bits);
|
|
if (size > memorySize || address + memorySize > 1n << BigInt(bits))
|
|
throw new BinaryFormatFailure(
|
|
"malformed",
|
|
"ELF load segment sizes or addresses are invalid",
|
|
);
|
|
const mapping = {
|
|
...(size === 0n
|
|
? { offset: 0, size: 0 }
|
|
: reader.fileRange(fileOffset, size, "ELF load segment")),
|
|
address,
|
|
};
|
|
if (mapping.size !== 0) {
|
|
mappings.push(mapping);
|
|
loadRegions.push({
|
|
mapping,
|
|
memory_size: memorySize,
|
|
read: (flags & 4) !== 0,
|
|
write: (flags & 2) !== 0,
|
|
execute: (flags & 1) !== 0,
|
|
});
|
|
if ((flags & 1) !== 0) executableMappings.push(mapping);
|
|
}
|
|
if (memorySize > size)
|
|
zeroFills.push({ address: address + size, size: memorySize - size });
|
|
}
|
|
for (const section of directory.sections) {
|
|
if (section.name === "") continue;
|
|
const range = declaredFileRange(bytes.length, section.offset, section.size);
|
|
const file_backed = section.type !== 8 && range.file_backed;
|
|
const compressed = (section.flags & 0x800n) !== 0n;
|
|
const read_only =
|
|
section.type === 1 &&
|
|
file_backed &&
|
|
!compressed &&
|
|
(section.flags & 1n) === 0n &&
|
|
(section.flags & 4n) === 0n &&
|
|
(section.flags & 2n) !== 0n;
|
|
if (section.name === null && !read_only) continue;
|
|
sections.push({
|
|
format: "elf",
|
|
name: section.name,
|
|
type: section.type,
|
|
address: section.address,
|
|
declared_range: { offset: section.offset, size: section.size },
|
|
...range,
|
|
file_backed,
|
|
compressed,
|
|
read_only,
|
|
});
|
|
}
|
|
return {
|
|
format: "elf",
|
|
architecture: architectureForElfMachine(directory.machine),
|
|
bits,
|
|
byte_order: reader.little ? "little" : "big",
|
|
mappings,
|
|
load_regions: loadRegions,
|
|
executable_mappings: executableMappings,
|
|
zero_fills: zeroFills,
|
|
sections,
|
|
...(directory.section_names_limitation === undefined
|
|
? {}
|
|
: { section_names_limitation: directory.section_names_limitation }),
|
|
};
|
|
};
|
|
|
|
/** Map ELF machine identifiers to stable architecture names. */
|
|
export const architectureForElfMachine = (machine: number): string => {
|
|
const architecture = elfArchitecture(machine);
|
|
if (architecture !== undefined) {
|
|
switch (architecture) {
|
|
case "x86":
|
|
return "386";
|
|
case "x86_64":
|
|
return "amd64";
|
|
case "powerpc":
|
|
return "ppc";
|
|
default:
|
|
return architecture;
|
|
}
|
|
}
|
|
switch (machine) {
|
|
case 21:
|
|
return "ppc64";
|
|
case 22:
|
|
return "s390";
|
|
case 258:
|
|
return "loongarch";
|
|
default:
|
|
return `elf-machine-${machine}`;
|
|
}
|
|
};
|