Validate ELF identification/header versions and declared header bounds at the shared owner. Reuse parsed facts in target selection, Go, Dart and MIPS readers while preserving their stricter format policies and x32 support. Repair synthetic ELF fixtures and remove a superseded Go error-text assertion. Validation: 74 source tests, 202 filesystem/Go/MIPS boundary tests, typecheck and lint. No new real-provider claims.
104 lines
3.6 KiB
TypeScript
104 lines
3.6 KiB
TypeScript
/** Build a minimal ELF header for binary-target parser tests. */
|
|
export const elf = (
|
|
class_: number,
|
|
endian: number,
|
|
machine: number,
|
|
): Buffer => {
|
|
const bytes = Buffer.alloc(class_ === 1 ? 52 : 64);
|
|
bytes.set([0x7f, 0x45, 0x4c, 0x46, class_, endian, 1]);
|
|
if (endian === 1) {
|
|
bytes.writeUInt16LE(machine, 18);
|
|
bytes.writeUInt32LE(1, 20);
|
|
bytes.writeUInt16LE(class_ === 1 ? 52 : 64, class_ === 1 ? 40 : 52);
|
|
} else {
|
|
bytes.writeUInt16BE(machine, 18);
|
|
bytes.writeUInt32BE(1, 20);
|
|
bytes.writeUInt16BE(class_ === 1 ? 52 : 64, class_ === 1 ? 40 : 52);
|
|
}
|
|
return bytes;
|
|
};
|
|
|
|
/** Build a minimal thin Mach-O header for binary-target parser tests. */
|
|
export const thinMach = (magic: number, cpu: number): Buffer => {
|
|
const bytes = Buffer.alloc(
|
|
magic === 0xfeedfacf || magic === 0xcffaedfe ? 32 : 28,
|
|
);
|
|
bytes.writeUInt32BE(magic, 0);
|
|
if (magic === 0xcefaedfe || magic === 0xcffaedfe) bytes.writeUInt32LE(cpu, 4);
|
|
else bytes.writeUInt32BE(cpu, 4);
|
|
return bytes;
|
|
};
|
|
|
|
/** Build a FAT Mach-O with in-bounds thin slices, or an explicitly truncated table. */
|
|
export const fat = (
|
|
cpus: readonly number[],
|
|
declared = cpus.length,
|
|
): Buffer => {
|
|
const tableSize = 8 + cpus.length * 20;
|
|
const slices = cpus.map((cpu) => {
|
|
const bytes = thinMach(0xfeedfacf, cpu);
|
|
bytes.writeUInt32BE(2, 12);
|
|
return bytes;
|
|
});
|
|
const sliceStart = Math.ceil(tableSize / 16) * 16;
|
|
const bytes = Buffer.alloc(
|
|
declared === cpus.length ? sliceStart + cpus.length * 32 : tableSize,
|
|
);
|
|
bytes.writeUInt32BE(0xcafebabe, 0);
|
|
bytes.writeUInt32BE(declared, 4);
|
|
cpus.forEach((cpu, index) => {
|
|
const entry = 8 + index * 20;
|
|
const offset = sliceStart + index * 32;
|
|
bytes.writeUInt32BE(cpu, entry);
|
|
bytes.writeUInt32BE(offset, entry + 8);
|
|
bytes.writeUInt32BE(32, entry + 12);
|
|
bytes.writeUInt32BE(4, entry + 16);
|
|
if (declared === cpus.length) slices[index]?.copy(bytes, offset);
|
|
});
|
|
return bytes;
|
|
};
|
|
|
|
/** Build a bounded PE image with optional managed metadata. */
|
|
export const pe = (
|
|
machine: number,
|
|
offset = 64,
|
|
characteristics = 0x0002,
|
|
managed = false,
|
|
): Buffer => {
|
|
const optionalHeaderSize =
|
|
machine === 0x014c || machine === 0x01c0 ? 224 : 240;
|
|
const bytes = Buffer.alloc(Math.max(512, offset + 24 + optionalHeaderSize));
|
|
bytes.write("MZ", 0, "ascii");
|
|
bytes.writeUInt32LE(offset, 0x3c);
|
|
bytes.write("PE\0\0", offset, "binary");
|
|
bytes.writeUInt16LE(machine, offset + 4);
|
|
bytes.writeUInt16LE(optionalHeaderSize, offset + 20);
|
|
bytes.writeUInt16LE(characteristics, offset + 22);
|
|
const optionalHeader = offset + 24;
|
|
const pe32 = machine === 0x014c || machine === 0x01c0;
|
|
bytes.writeUInt16LE(pe32 ? 0x10b : 0x20b, optionalHeader);
|
|
const directoryOffset = pe32 ? 96 : 112;
|
|
bytes.writeUInt32LE(16, optionalHeader + directoryOffset - 4);
|
|
if (managed) {
|
|
bytes.writeUInt32LE(0x2000, optionalHeader + directoryOffset + 14 * 8);
|
|
bytes.writeUInt32LE(72, optionalHeader + directoryOffset + 14 * 8 + 4);
|
|
}
|
|
return bytes;
|
|
};
|
|
|
|
/** Build a DOS MZ image with a 32-byte header and a 16-bit entry point. */
|
|
export const dosMz = (moduleSize = 128): Buffer => {
|
|
const size = 32 + moduleSize;
|
|
const bytes = Buffer.alloc(size);
|
|
bytes.write("MZ", 0, "ascii");
|
|
bytes.writeUInt16LE(size % 512, 2);
|
|
bytes.writeUInt16LE(Math.ceil(size / 512), 4);
|
|
bytes.writeUInt16LE(2, 8);
|
|
bytes.writeUInt16LE(0xffff, 12);
|
|
bytes.writeUInt16LE(28, 24);
|
|
bytes.set([0xb8, 0x00, 0x4c, 0xcd, 0x21], 32);
|
|
// This is module data, not an e_lfanew field in a Windows DOS stub.
|
|
if (size >= 64) bytes.writeUInt32LE(0xfedcba98, 60);
|
|
return bytes;
|
|
};
|