kit

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

kit-roundtrip.c (4462B)


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