object_detect.c (3698B)
1 /* Binary format and target detection from object header bytes. */ 2 3 #include <kit/object.h> 4 5 #include "core/core.h" 6 #include "obj/format.h" 7 8 /* COFF Machine numbers recognized as the COFF *binary* format by 9 * kit_detect_fmt. This is format membership only — the arch mapping (in the 10 * COFF detector) routes through the registry's coff_machine reverse map. 11 * 12 * The set here is intentionally broader than the registry's coff_machine 13 * ops (which models only the link/codegen-supported AMD64 / ARM64): a COFF 14 * header for any of these machines should still be classified as COFF so 15 * the reader/target paths report the precise reason it cannot be consumed. 16 * ARM64EC (0xA641) is plain AArch64 (same encoding, differing ABI); the 17 * registry aliases it to ARM64 before lookup (coff.h). */ 18 static const u16 COFF_MACHINES[] = { 19 0x8664, /* AMD64 */ 20 0x014C, /* I386 */ 21 0xAA64, /* ARM64 */ 22 0xA641, /* ARM64EC */ 23 0x01C4, /* ARMNT */ 24 0x5032, /* RISCV32 */ 25 0x5064, /* RISCV64 */ 26 }; 27 28 /* Is `machine` a COFF Machine number we classify as the COFF format? */ 29 static int coff_machine_known(u16 machine) { 30 size_t i; 31 for (i = 0; i < sizeof COFF_MACHINES / sizeof COFF_MACHINES[0]; i++) { 32 if (COFF_MACHINES[i] == machine) return 1; 33 } 34 return 0; 35 } 36 37 KitBinFmt kit_detect_fmt(const uint8_t* data, size_t len) { 38 u32 m; 39 u16 coff_machine; 40 41 if (!data) return KIT_BIN_UNKNOWN; 42 if (len >= 8 && data[0] == '!' && data[1] == '<' && data[2] == 'a' && 43 data[3] == 'r' && data[4] == 'c' && data[5] == 'h' && data[6] == '>' && 44 data[7] == '\n') { 45 return KIT_BIN_AR; 46 } 47 if (len >= 4 && data[0] == 0x7f && data[1] == 'E' && data[2] == 'L' && 48 data[3] == 'F') { 49 return KIT_BIN_ELF; 50 } 51 if (len >= 4 && data[0] == 0x00 && data[1] == 'a' && data[2] == 's' && 52 data[3] == 'm') { 53 return KIT_BIN_WASM; 54 } 55 if (len >= 4) { 56 m = (u32)data[0] | ((u32)data[1] << 8) | ((u32)data[2] << 16) | 57 ((u32)data[3] << 24); 58 if (m == 0xFEEDFACEu || m == 0xFEEDFACFu || m == 0xCEFAEDFEu || 59 m == 0xCFFAEDFEu || m == 0xCAFEBABEu) { 60 return KIT_BIN_MACHO; 61 } 62 } 63 if (len >= 2 && data[0] == 'M' && data[1] == 'Z') { 64 return KIT_BIN_PE; 65 } 66 if (len >= 2) { 67 coff_machine = (u16)data[0] | ((u16)data[1] << 8); 68 if (coff_machine_known(coff_machine)) return KIT_BIN_COFF; 69 } 70 /* Microsoft "short import" record: Sig1=0, Sig2=0xFFFF. Routed 71 * through read_coff (which dispatches to read_coff_short_import). 72 * The header continues with a Machine word, which we also sanity- 73 * check so a stray 00 00 FF FF prefix on some other format does 74 * not mis-route. */ 75 if (len >= 8 && data[0] == 0x00 && data[1] == 0x00 && data[2] == 0xFF && 76 data[3] == 0xFF) { 77 u16 mach = (u16)data[6] | ((u16)data[7] << 8); 78 if (coff_machine_known(mach)) return KIT_BIN_COFF; 79 } 80 return KIT_BIN_UNKNOWN; 81 } 82 83 KitStatus kit_detect_target(const uint8_t* data, size_t len, 84 KitTargetSpec* out) { 85 KitBinFmt bin; 86 const ObjFormatImpl* fmt; 87 if (!data || !out) return KIT_INVALID; 88 bin = kit_detect_fmt(data, len); 89 /* A PE image classifies as KIT_BIN_PE but is read (and detected) by the 90 * COFF format; every other binary maps straight through. The per-format 91 * detector lives in the obj format vtable and is compiled out with its 92 * format, so a disabled format resolves to NULL here -> KIT_UNSUPPORTED 93 * (matching the AR / UNKNOWN cases). */ 94 fmt = (bin == KIT_BIN_PE) ? obj_format_lookup(KIT_OBJ_COFF) 95 : obj_format_lookup_bin(bin); 96 if (!fmt || !fmt->detect_target) return KIT_UNSUPPORTED; 97 return fmt->detect_target(data, len, out); 98 }