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 }