kit

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

kit-roundtrip-macho.c (4288B)


      1 /* kit-roundtrip-macho: read a Mach-O object via libkit's public object
      2  * reader, then re-emit via the public object builder API. Round-trip oracle
      3  * for the Mach-O writer.
      4  *
      5  * Usage: kit-roundtrip-macho <in.o> <out.o>
      6  *
      7  * Behavior: kit_obj_open detects and parses the input into a KitObjFile;
      8  * kit_obj_file_builder exposes the already-finalized builder; and
      9  * kit_obj_builder_emit writes the canonical re-emit to out.o. Diagnostics
     10  * go to stderr via the libc heap + stderr diag sink. */
     11 
     12 #include <fcntl.h>
     13 #include <kit/core.h>
     14 #include <kit/object.h>
     15 #include <stdarg.h>
     16 #include <stdio.h>
     17 #include <stdlib.h>
     18 #include <string.h>
     19 #include <sys/stat.h>
     20 #include <unistd.h>
     21 
     22 static void* heap_alloc(KitHeap* h, size_t n, size_t a) {
     23   (void)h;
     24   (void)a;
     25   return n ? malloc(n) : NULL;
     26 }
     27 static void* heap_realloc(KitHeap* h, void* p, size_t o, size_t n, size_t a) {
     28   (void)h;
     29   (void)o;
     30   (void)a;
     31   return realloc(p, n);
     32 }
     33 static void heap_free(KitHeap* h, void* p, size_t n) {
     34   (void)h;
     35   (void)n;
     36   free(p);
     37 }
     38 static KitHeap g_heap = {heap_alloc, heap_realloc, heap_free, NULL};
     39 
     40 static void diag_emit(KitDiagSink* s, KitDiagKind k, KitSrcLoc loc,
     41                       const char* fmt, va_list ap) {
     42   static const char* names[] = {"note", "warning", "error", "fatal"};
     43   (void)s;
     44   (void)loc;
     45   fprintf(stderr, "%s: ", names[k]);
     46   vfprintf(stderr, fmt, ap);
     47   fputc('\n', stderr);
     48 }
     49 static KitDiagSink g_diag = {diag_emit, NULL, 0, 0};
     50 
     51 static int read_file(const char* path, uint8_t** data_out, size_t* len_out) {
     52   int fd = open(path, O_RDONLY);
     53   if (fd < 0) return -1;
     54 
     55   struct stat sb;
     56   if (fstat(fd, &sb) < 0) {
     57     close(fd);
     58     return -1;
     59   }
     60   size_t n = (size_t)sb.st_size;
     61 
     62   uint8_t* buf = (uint8_t*)malloc(n ? n : 1);
     63   if (!buf) {
     64     close(fd);
     65     return -1;
     66   }
     67 
     68   size_t got = 0;
     69   while (got < n) {
     70     ssize_t k = read(fd, buf + got, n - got);
     71     if (k <= 0) {
     72       free(buf);
     73       close(fd);
     74       return -1;
     75     }
     76     got += (size_t)k;
     77   }
     78   close(fd);
     79 
     80   *data_out = buf;
     81   *len_out = n;
     82   return 0;
     83 }
     84 
     85 static int write_file(const char* path, const uint8_t* data, size_t len) {
     86   int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
     87   if (fd < 0) return -1;
     88   size_t off = 0;
     89   while (off < len) {
     90     ssize_t k = write(fd, data + off, len - off);
     91     if (k < 0) {
     92       close(fd);
     93       return -1;
     94     }
     95     off += (size_t)k;
     96   }
     97   close(fd);
     98   return 0;
     99 }
    100 
    101 int main(int argc, char** argv) {
    102   if (argc != 3) {
    103     fprintf(stderr, "usage: kit-roundtrip-macho <in.o> <out.o>\n");
    104     return 2;
    105   }
    106   const char* in_path = argv[1];
    107   const char* out_path = argv[2];
    108 
    109   uint8_t* in_data = NULL;
    110   size_t in_len = 0;
    111   if (read_file(in_path, &in_data, &in_len) != 0) {
    112     fprintf(stderr, "error: cannot read %s\n", in_path);
    113     return 1;
    114   }
    115 
    116   KitTargetSpec target;
    117   if (kit_detect_target(in_data, in_len, &target) != KIT_OK ||
    118       target.obj != KIT_OBJ_MACHO) {
    119     fprintf(stderr, "error: %s: not a recognized Mach-O object file\n",
    120             in_path);
    121     free(in_data);
    122     return 1;
    123   }
    124 
    125   KitContext ctx;
    126   memset(&ctx, 0, sizeof ctx);
    127   ctx.heap = &g_heap;
    128   ctx.diag = &g_diag;
    129   ctx.now = -1;
    130 
    131   KitObjFile* obj = NULL;
    132   KitSlice name = kit_slice_cstr(in_path);
    133   KitSlice input = {.data = in_data, .len = in_len};
    134   KitStatus st = kit_obj_open(&ctx, name, &input, &obj);
    135   if (st != KIT_OK || !obj) {
    136     free(in_data);
    137     return 2;
    138   }
    139 
    140   KitObjBuilder* ob = kit_obj_file_builder(obj);
    141   if (!ob) {
    142     fprintf(stderr, "error: kit_obj_file_builder failed\n");
    143     kit_obj_free(obj);
    144     free(in_data);
    145     return 1;
    146   }
    147 
    148   KitWriter* w = NULL;
    149   if (kit_writer_mem(&g_heap, &w) != KIT_OK || !w) {
    150     fprintf(stderr, "error: kit_writer_mem failed\n");
    151     kit_obj_free(obj);
    152     free(in_data);
    153     return 1;
    154   }
    155 
    156   st = kit_obj_builder_emit(ob, w);
    157   if (st != KIT_OK) {
    158     fprintf(stderr, "error: kit_obj_builder_emit failed\n");
    159     kit_writer_close(w);
    160     kit_obj_free(obj);
    161     free(in_data);
    162     return 1;
    163   }
    164 
    165   size_t out_len = 0;
    166   const uint8_t* out_data = kit_writer_mem_bytes(w, &out_len);
    167 
    168   int rc = write_file(out_path, out_data, out_len);
    169   if (rc != 0) fprintf(stderr, "error: cannot write %s\n", out_path);
    170 
    171   kit_writer_close(w);
    172   kit_obj_free(obj);
    173   free(in_data);
    174   return rc == 0 ? 0 : 1;
    175 }