tooling/core/src/platform/detection/executable.luau

92 lines
2.6 KiB
Text

local process = require("@lune/process")
type Arch = process.Arch | "arm" | "x86"
export type ExecutableDetectionResult = {
os: process.OS?,
arch: Arch?,
}
return function(binaryContents: buffer): ExecutableDetectionResult?
-- Windows PE
do
local DOS_HEADER = "MZ"
local PE_HEADER_OFFSET = 0x3c
local PE_MAGIC_SIGNATURE = "PE\x00\x00"
local PE_MACHINE_TYPES: { [number]: Arch } = {
[0x8664] = "x86_64",
[0x01c0] = "arm",
[0xaa64] = "aarch64",
[0x014c] = "x86",
}
if buffer.readstring(binaryContents, 0, 2) == DOS_HEADER then
-- File was a DOS executable, jump to PE header to get the magic offset
local signatureOffset = buffer.readu8(binaryContents, PE_HEADER_OFFSET)
-- Check if the value at the magic offset was the PE magic signature
if buffer.readstring(binaryContents, signatureOffset, 4) == PE_MAGIC_SIGNATURE then
-- After the first 4 magic bytes, the next 2 bytes are architecture information
local machineType = buffer.readu16(binaryContents, signatureOffset + 4)
return {
os = "windows",
arch = PE_MACHINE_TYPES[machineType],
}
end
end
end
-- Linux ELF
do
local ELF_MAGIC_START = 0x7f
local ELF_MAGIC_SIGNATURE = "ELF"
local ELF_MACHINE_TYPES: { [number]: Arch } = {
[0x3e] = "x86_64",
[0x28] = "arm",
[0xb7] = "aarch64",
[0x03] = "x86",
}
-- ELF files have a magic signature of [0x7f, 'E', 'L', 'F']
if
buffer.readu8(binaryContents, 0) == ELF_MAGIC_START
and buffer.readstring(binaryContents, 1, 3) == ELF_MAGIC_SIGNATURE
then
-- Machine type is located after 16 bytes of ident and 2 bytes of type
local machineType = buffer.readu16(binaryContents, 18)
return {
os = "linux",
arch = ELF_MACHINE_TYPES[machineType],
}
end
end
-- macOS Mach-O
do
local MACHO_MAGIC_32 = 0xFEEDFACE
local MACHO_MAGIC_64 = 0xFEEDFACF
local MACHO_CPU_TYPES = {
x86 = 0x7,
arm = 0xc,
}
-- First 4 bytes are the magic depending on 32 or 64 bit
-- Next 2 bytes are the CPU type
local headerStart = buffer.readu32(binaryContents, 0)
local cpuType = buffer.readu16(binaryContents, 4)
local is64bit = headerStart == MACHO_MAGIC_64
local is32bit = headerStart == MACHO_MAGIC_32
return {
os = "macos",
--stylua: ignore
arch = (
if is64bit and cpuType == MACHO_CPU_TYPES.x86 then "x86_64"
elseif is64bit and cpuType == MACHO_CPU_TYPES.arm then "aarch64"
elseif is32bit and cpuType == MACHO_CPU_TYPES.x86 then "x86"
elseif is32bit and cpuType == MACHO_CPU_TYPES.arm then "arm"
else nil
),
}
end
end