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 }