kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 }