posix.c (39321B)
1 /* POSIX-shared environment: file I/O, mkdir, sigint, exec_dual registry, 2 * single-mapping execmem, monotonic clock, stdin/edit, dlsym resolver, 3 * driver_env_init for hosts where the POSIX TUs are compiled (Mac, Linux, 4 * FreeBSD). Each function here behaves identically on those three; per-OS 5 * specifics are isolated in macos.c / linux.c / freebsd.c. */ 6 7 #include <dirent.h> 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <pthread.h> 11 #include <signal.h> 12 #include <stdint.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <sys/mman.h> 17 #include <sys/stat.h> 18 #include <sys/wait.h> 19 #include <termios.h> 20 #include <time.h> 21 #include <unistd.h> 22 23 #include "env_posix.h" 24 25 extern char** environ; 26 27 /* ---------------- exec memory: single-mapping core + registry ---------------- 28 */ 29 30 int kit_to_posix_prot(int prot) { 31 int p = 0; 32 if (prot & KIT_PROT_READ) p |= PROT_READ; 33 if (prot & KIT_PROT_WRITE) p |= PROT_WRITE; 34 if (prot & KIT_PROT_EXEC) p |= PROT_EXEC; 35 return p; 36 } 37 38 /* Registry of EXEC reservations with distinct write/runtime aliases. The 39 * dbg_os code_write_begin path uses this to translate a runtime address 40 * into the corresponding write alias on dual-mapping hosts. Single-mapping 41 * reservations (write == runtime) are not registered. JITs typically hold 42 * 1-2 reservations live so a linked list keeps the lookup trivial. */ 43 typedef struct ExecDualNode { 44 void* write_base; 45 void* runtime_base; 46 size_t size; 47 struct ExecDualNode* next; 48 } ExecDualNode; 49 50 static ExecDualNode* g_jit_dual_map; 51 static pthread_mutex_t g_jit_dual_map_mu = PTHREAD_MUTEX_INITIALIZER; 52 53 void exec_dual_register(void* write_base, void* runtime_base, size_t size) { 54 ExecDualNode* n; 55 if (write_base == runtime_base) return; 56 n = (ExecDualNode*)malloc(sizeof(*n)); 57 if (!n) return; /* registry is best-effort; lookup will fail open */ 58 n->write_base = write_base; 59 n->runtime_base = runtime_base; 60 n->size = size; 61 pthread_mutex_lock(&g_jit_dual_map_mu); 62 n->next = g_jit_dual_map; 63 g_jit_dual_map = n; 64 pthread_mutex_unlock(&g_jit_dual_map_mu); 65 } 66 67 void exec_dual_unregister(void* runtime_base) { 68 ExecDualNode** pp; 69 pthread_mutex_lock(&g_jit_dual_map_mu); 70 for (pp = &g_jit_dual_map; *pp; pp = &(*pp)->next) { 71 if ((*pp)->runtime_base == runtime_base) { 72 ExecDualNode* dead = *pp; 73 *pp = dead->next; 74 free(dead); 75 break; 76 } 77 } 78 pthread_mutex_unlock(&g_jit_dual_map_mu); 79 } 80 81 int exec_dual_lookup(void* runtime_addr, size_t n, void** write_out) { 82 ExecDualNode* cur; 83 uintptr_t a = (uintptr_t)runtime_addr; 84 pthread_mutex_lock(&g_jit_dual_map_mu); 85 for (cur = g_jit_dual_map; cur; cur = cur->next) { 86 uintptr_t base = (uintptr_t)cur->runtime_base; 87 if (a >= base && a + n <= base + cur->size) { 88 *write_out = (void*)((uintptr_t)cur->write_base + (a - base)); 89 pthread_mutex_unlock(&g_jit_dual_map_mu); 90 return 0; 91 } 92 } 93 pthread_mutex_unlock(&g_jit_dual_map_mu); 94 return 1; 95 } 96 97 KitStatus execmem_reserve_single(size_t size, KitExecMemRegion* out) { 98 void* p = 99 mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 100 if (p == MAP_FAILED) return KIT_NOMEM; 101 out->write = p; 102 out->runtime = p; 103 out->size = size; 104 out->token = NULL; /* munmap suffices on release */ 105 return KIT_OK; 106 } 107 108 static KitStatus execmem_reserve(void* user, size_t size, int prot, 109 KitExecMemRegion* out) { 110 (void)user; 111 if (!out || !size) return KIT_INVALID; 112 if (prot & KIT_PROT_EXEC) return os_execmem_reserve_exec(size, out); 113 return execmem_reserve_single(size, out); 114 } 115 116 static KitStatus execmem_protect(void* user, void* addr, size_t size, 117 int prot) { 118 (void)user; 119 return mprotect(addr, size, kit_to_posix_prot(prot)) == 0 ? KIT_OK : KIT_ERR; 120 } 121 122 static void execmem_release(void* user, KitExecMemRegion* region) { 123 (void)user; 124 if (!region || !region->size) return; 125 if (region->token) { 126 ExecMemToken* tok = (ExecMemToken*)region->token; 127 if (tok->runtime_addr && tok->runtime_addr != tok->write_addr) { 128 exec_dual_unregister(tok->runtime_addr); 129 munmap(tok->runtime_addr, tok->size); 130 } 131 if (tok->write_addr) munmap(tok->write_addr, tok->size); 132 free(tok); 133 } else if (region->write) { 134 munmap(region->write, region->size); 135 } 136 region->write = NULL; 137 region->runtime = NULL; 138 region->size = 0; 139 region->token = NULL; 140 } 141 142 static void execmem_flush_icache(void* user, void* addr, size_t size) { 143 (void)user; 144 env_flush_icache(addr, size); 145 } 146 147 size_t driver_host_page_size(void) { 148 long p = sysconf(_SC_PAGESIZE); 149 return (p > 0) ? (size_t)p : (size_t)0x4000; 150 } 151 152 KitExecMem g_execmem_posix; /* page_size set in driver_env_init */ 153 154 /* ---------------- fd writer ---------------- */ 155 156 typedef struct DriverFdWriter { 157 KitWriter base; /* must be first; libkit reads via this */ 158 KitHeap* heap; 159 int fd; 160 KitStatus status; 161 uint64_t pos; 162 } DriverFdWriter; 163 164 static KitStatus fdw_write(KitWriter* w, const void* data, size_t n) { 165 DriverFdWriter* fw = (DriverFdWriter*)w; 166 const unsigned char* p = (const unsigned char*)data; 167 if (fw->status != KIT_OK) return fw->status; 168 while (n > 0) { 169 ssize_t k = write(fw->fd, p, n); 170 if (k < 0) { 171 fw->status = KIT_IO; 172 return KIT_IO; 173 } 174 p += (size_t)k; 175 n -= (size_t)k; 176 fw->pos += (uint64_t)k; 177 } 178 return KIT_OK; 179 } 180 181 static KitStatus fdw_seek(KitWriter* w, uint64_t off) { 182 DriverFdWriter* fw = (DriverFdWriter*)w; 183 if (fw->status != KIT_OK) return fw->status; 184 if (lseek(fw->fd, (off_t)off, SEEK_SET) < 0) { 185 fw->status = KIT_IO; 186 return KIT_IO; 187 } 188 fw->pos = off; 189 return KIT_OK; 190 } 191 192 static uint64_t fdw_tell(KitWriter* w) { return ((DriverFdWriter*)w)->pos; } 193 static KitStatus fdw_status(KitWriter* w) { 194 return ((DriverFdWriter*)w)->status; 195 } 196 197 static void fdw_close(KitWriter* w) { 198 DriverFdWriter* fw = (DriverFdWriter*)w; 199 if (fw->fd >= 0) close(fw->fd); 200 fw->heap->free(fw->heap, fw, sizeof(*fw)); 201 } 202 203 static KitWriter* driver_writer_fd(KitHeap* h, int fd) { 204 DriverFdWriter* fw = 205 (DriverFdWriter*)h->alloc(h, sizeof(*fw), _Alignof(DriverFdWriter)); 206 if (!fw) return NULL; 207 fw->base.write = fdw_write; 208 fw->base.seek = fdw_seek; 209 fw->base.tell = fdw_tell; 210 fw->base.status = fdw_status; 211 fw->base.close = fdw_close; 212 fw->heap = h; 213 fw->fd = fd; 214 fw->status = KIT_OK; 215 fw->pos = 0; 216 return &fw->base; 217 } 218 219 /* Stdout writer routes through stdio so it shares libc's buffer with 220 * driver_printf. */ 221 typedef struct DriverStdioWriter { 222 KitWriter base; 223 KitHeap* heap; 224 FILE* fp; 225 KitStatus status; 226 } DriverStdioWriter; 227 228 static KitStatus stdio_w_write(KitWriter* w, const void* data, size_t n) { 229 DriverStdioWriter* sw = (DriverStdioWriter*)w; 230 if (n) { 231 size_t got = fwrite(data, 1, n, sw->fp); 232 if (got != n) { 233 sw->status = KIT_IO; 234 return KIT_IO; 235 } 236 } 237 return KIT_OK; 238 } 239 static KitStatus stdio_w_seek(KitWriter* w, uint64_t off) { 240 DriverStdioWriter* sw = (DriverStdioWriter*)w; 241 return fseek(sw->fp, (long)off, SEEK_SET) == 0 ? KIT_OK : KIT_IO; 242 } 243 static uint64_t stdio_w_tell(KitWriter* w) { 244 long t = ftell(((DriverStdioWriter*)w)->fp); 245 return t < 0 ? 0u : (uint64_t)t; 246 } 247 static KitStatus stdio_w_status(KitWriter* w) { 248 DriverStdioWriter* sw = (DriverStdioWriter*)w; 249 if (sw->status != KIT_OK) return sw->status; 250 return ferror(sw->fp) ? KIT_IO : KIT_OK; 251 } 252 static void stdio_w_close(KitWriter* w) { 253 DriverStdioWriter* sw = (DriverStdioWriter*)w; 254 fflush(sw->fp); /* flush but do not close the borrowed stdio stream */ 255 sw->heap->free(sw->heap, sw, sizeof(*sw)); 256 } 257 258 static KitWriter* driver_stdio_writer(DriverEnv* e, FILE* fp) { 259 DriverStdioWriter* sw = (DriverStdioWriter*)e->heap->alloc( 260 e->heap, sizeof(*sw), _Alignof(DriverStdioWriter)); 261 if (!sw) return NULL; 262 sw->base.write = stdio_w_write; 263 sw->base.seek = stdio_w_seek; 264 sw->base.tell = stdio_w_tell; 265 sw->base.status = stdio_w_status; 266 sw->base.close = stdio_w_close; 267 sw->heap = e->heap; 268 sw->fp = fp; 269 sw->status = KIT_OK; 270 return &sw->base; 271 } 272 273 KitWriter* driver_stdout_writer(DriverEnv* e) { 274 return driver_stdio_writer(e, stdout); 275 } 276 277 KitWriter* driver_stderr_writer(DriverEnv* e) { 278 return driver_stdio_writer(e, stderr); 279 } 280 281 const char* const* driver_environ(void) { 282 return (const char* const*)environ; 283 } 284 285 /* ---------------- file_io (POSIX open/read/write/stat) ---------------- */ 286 287 static KitStatus posix_read_all(void* user, const char* path, 288 KitFileData* out) { 289 DriverEnv* env = (DriverEnv*)user; 290 int fd; 291 struct stat sb; 292 size_t size; 293 size_t got; 294 void* buf; 295 296 fd = open(path, O_RDONLY); 297 if (fd < 0) return KIT_NOT_FOUND; 298 if (fstat(fd, &sb) < 0) { 299 close(fd); 300 return KIT_IO; 301 } 302 size = (size_t)sb.st_size; 303 buf = size ? env->heap->alloc(env->heap, size, 1) : NULL; 304 if (size && !buf) { 305 close(fd); 306 return KIT_NOMEM; 307 } 308 309 got = 0; 310 while (got < size) { 311 ssize_t n = read(fd, (unsigned char*)buf + got, size - got); 312 if (n <= 0) { 313 env->heap->free(env->heap, buf, size); 314 close(fd); 315 return KIT_IO; 316 } 317 got += (size_t)n; 318 } 319 close(fd); 320 321 out->data = (const uint8_t*)buf; 322 out->size = size; 323 out->token = buf; 324 return KIT_OK; 325 } 326 327 static void posix_release(void* user, KitFileData* d) { 328 DriverEnv* env = (DriverEnv*)user; 329 if (d->token) env->heap->free(env->heap, d->token, d->size); 330 d->data = NULL; 331 d->size = 0; 332 d->token = NULL; 333 } 334 335 static KitStatus posix_open_writer(void* user, const char* path, 336 KitWriter** out) { 337 DriverEnv* env = (DriverEnv*)user; 338 int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); 339 KitWriter* w; 340 if (fd < 0) return KIT_IO; 341 w = driver_writer_fd(env->heap, fd); 342 if (!w) { 343 close(fd); 344 return KIT_NOMEM; 345 } 346 *out = w; 347 return KIT_OK; 348 } 349 350 /* ---------------- path helpers ---------------- */ 351 352 int driver_path_exists(const char* path) { 353 struct stat sb; 354 if (!path) return 0; 355 return stat(path, &sb) == 0; 356 } 357 358 int driver_path_mtime_ns(const char* path, int64_t* out) { 359 struct stat sb; 360 if (!path || !out) return 1; 361 if (stat(path, &sb) != 0) return 1; 362 return os_stat_mtime_ns(&sb, out); 363 } 364 365 static uint8_t posix_mode_to_wasm_filetype(mode_t m) { 366 if (S_ISREG(m)) return 4; 367 if (S_ISDIR(m)) return 3; 368 if (S_ISLNK(m)) return 7; 369 if (S_ISBLK(m)) return 1; 370 if (S_ISCHR(m)) return 2; 371 if (S_ISSOCK(m)) return 6; 372 return 0; 373 } 374 375 int driver_path_stat(const char* path, uint64_t* out_size, 376 uint64_t* out_mtime_ns, uint8_t* out_filetype) { 377 struct stat sb; 378 int64_t mtime; 379 if (!path || stat(path, &sb) != 0) 380 return (errno == ENOENT || errno == ENOTDIR) ? 1 : 2; 381 *out_size = (uint64_t)sb.st_size; 382 *out_mtime_ns = os_stat_mtime_ns(&sb, &mtime) == 0 ? (uint64_t)mtime : 0u; 383 *out_filetype = posix_mode_to_wasm_filetype(sb.st_mode); 384 return 0; 385 } 386 387 typedef struct DriverDirEntryRec { 388 char* name; 389 size_t name_alloc; 390 uint32_t name_len; 391 uint64_t ino; 392 uint64_t size; 393 uint64_t mtime_ns; 394 uint8_t filetype; 395 } DriverDirEntryRec; 396 397 struct DriverDirHandle { 398 DriverEnv* env; 399 DriverDirEntryRec* entries; 400 size_t entries_alloc; 401 uint64_t count; 402 }; 403 404 DriverDirHandle* driver_open_dir(DriverEnv* env, const char* path) { 405 DIR* d; 406 struct dirent* ent; 407 DriverDirHandle* h; 408 uint64_t cap = 0; 409 uint64_t count = 0; 410 size_t plen; 411 int slash; 412 413 if (!env || !path) return NULL; 414 d = opendir(path); 415 if (!d) return NULL; 416 plen = kit_slice_cstr(path).len; 417 slash = plen && path[plen - 1u] != '/'; 418 419 h = (DriverDirHandle*)env->heap->alloc(env->heap, sizeof(*h), 420 _Alignof(DriverDirHandle)); 421 if (!h) { closedir(d); return NULL; } 422 memset(h, 0, sizeof(*h)); 423 h->env = env; 424 425 while ((ent = readdir(d)) != NULL) { 426 const char* name = ent->d_name; 427 size_t name_len; 428 DriverDirEntryRec* e; 429 size_t child_alloc; 430 char* child; 431 struct stat sb; 432 int64_t mtime; 433 434 if (driver_streq(name, ".") || driver_streq(name, "..")) continue; 435 name_len = kit_slice_cstr(name).len; 436 437 /* grow entry array */ 438 if (count >= cap) { 439 uint64_t new_cap = cap ? cap * 2u : 8u; 440 size_t new_alloc = (size_t)new_cap * sizeof(DriverDirEntryRec); 441 DriverDirEntryRec* nv = (DriverDirEntryRec*)env->heap->alloc( 442 env->heap, new_alloc, _Alignof(DriverDirEntryRec)); 443 if (!nv) goto fail; 444 if (h->entries) { 445 memcpy(nv, h->entries, (size_t)count * sizeof(DriverDirEntryRec)); 446 env->heap->free(env->heap, h->entries, h->entries_alloc); 447 } 448 h->entries = nv; 449 h->entries_alloc = new_alloc; 450 cap = new_cap; 451 } 452 453 e = &h->entries[count]; 454 memset(e, 0, sizeof(*e)); 455 e->name_alloc = name_len + 1u; 456 e->name = (char*)env->heap->alloc(env->heap, e->name_alloc, 1u); 457 if (!e->name) goto fail; 458 memcpy(e->name, name, name_len); 459 e->name[name_len] = '\0'; 460 e->name_len = (uint32_t)name_len; 461 462 /* lstat the entry to get metadata */ 463 child_alloc = plen + (size_t)slash + name_len + 1u; 464 child = (char*)driver_alloc(env, child_alloc); 465 if (child) { 466 size_t off = 0; 467 memcpy(child, path, plen); off += plen; 468 if (slash) child[off++] = '/'; 469 memcpy(child + off, name, name_len); 470 child[off + name_len] = '\0'; 471 if (lstat(child, &sb) == 0) { 472 e->ino = (uint64_t)sb.st_ino; 473 e->size = (uint64_t)sb.st_size; 474 if (os_stat_mtime_ns(&sb, &mtime) == 0) e->mtime_ns = (uint64_t)mtime; 475 e->filetype = posix_mode_to_wasm_filetype(sb.st_mode); 476 } 477 driver_free(env, child, child_alloc); 478 } 479 ++count; 480 } 481 482 closedir(d); 483 h->count = count; 484 return h; 485 486 fail: 487 closedir(d); 488 driver_close_dir(env, h); 489 return NULL; 490 } 491 492 int driver_read_dir_entry(DriverDirHandle* h, uint64_t index, 493 const char** out_name, uint32_t* out_name_len, 494 uint64_t* out_ino, uint64_t* out_size, 495 uint64_t* out_mtime_ns, uint8_t* out_filetype) { 496 DriverDirEntryRec* e; 497 if (!h || index >= h->count) return 1; 498 e = &h->entries[index]; 499 *out_name = e->name; 500 *out_name_len = e->name_len; 501 *out_ino = e->ino; 502 *out_size = e->size; 503 *out_mtime_ns = e->mtime_ns; 504 *out_filetype = e->filetype; 505 return 0; 506 } 507 508 void driver_close_dir(DriverEnv* env, DriverDirHandle* h) { 509 uint64_t i; 510 if (!h) return; 511 if (!env) env = h->env; 512 for (i = 0; i < h->count; ++i) { 513 DriverDirEntryRec* e = &h->entries[i]; 514 if (e->name) env->heap->free(env->heap, e->name, e->name_alloc); 515 } 516 if (h->entries) env->heap->free(env->heap, h->entries, h->entries_alloc); 517 env->heap->free(env->heap, h, sizeof(*h)); 518 } 519 520 int driver_mkdir_p(DriverEnv* env, const char* path) { 521 size_t len; 522 char* buf; 523 size_t i; 524 struct stat sb; 525 526 if (!path || !path[0]) return 1; 527 len = kit_slice_cstr(path).len; 528 buf = (char*)driver_alloc(env, len + 1); 529 if (!buf) return 1; 530 memcpy(buf, path, len + 1); 531 532 for (i = 1; i <= len; ++i) { 533 int at_end = (i == len); 534 if (!at_end && buf[i] != '/') continue; 535 if (!at_end) buf[i] = '\0'; 536 if (buf[0] != '\0' && !driver_streq(buf, ".")) { 537 if (mkdir(buf, 0755) != 0 && errno != EEXIST) { 538 driver_free(env, buf, len + 1); 539 return 1; 540 } 541 if (stat(buf, &sb) != 0 || !S_ISDIR(sb.st_mode)) { 542 driver_free(env, buf, len + 1); 543 return 1; 544 } 545 } 546 if (!at_end) buf[i] = '/'; 547 } 548 549 driver_free(env, buf, len + 1); 550 return 0; 551 } 552 553 int driver_mark_executable_output(const char* path) { 554 mode_t mask; 555 mode_t mode; 556 if (!path) return 1; 557 mask = umask(0); 558 (void)umask(mask); 559 mode = (mode_t)(0777 & ~mask); 560 return chmod(path, mode) == 0 ? 0 : 1; 561 } 562 563 /* ---------------- link helpers (install) ---------------- */ 564 565 int driver_create_symlink(const char* target, const char* link_path) { 566 if (!target || !link_path) return 1; 567 return symlink(target, link_path) == 0 ? 0 : 1; 568 } 569 570 int driver_create_hardlink(const char* target, const char* link_path) { 571 if (!target || !link_path) return 1; 572 return link(target, link_path) == 0 ? 0 : 1; 573 } 574 575 int driver_remove_file(const char* path) { 576 if (!path) return 1; 577 if (unlink(path) == 0) return 0; 578 return errno == ENOENT ? 0 : 1; /* already absent is success */ 579 } 580 581 int driver_path_lexists(const char* path) { 582 struct stat sb; 583 if (!path) return 0; 584 return lstat(path, &sb) == 0; 585 } 586 587 static char* driver_join_path(DriverEnv* env, const char* a, const char* b) { 588 size_t al = kit_slice_cstr(a).len; 589 size_t bl = kit_slice_cstr(b).len; 590 int slash = al > 0 && a[al - 1u] != '/'; 591 char* out = (char*)driver_alloc(env, al + (slash ? 1u : 0u) + bl + 1u); 592 if (!out) return NULL; 593 memcpy(out, a, al); 594 if (slash) out[al++] = '/'; 595 memcpy(out + al, b, bl); 596 out[al + bl] = '\0'; 597 return out; 598 } 599 600 static int driver_walk_regular_files_at(DriverEnv* env, const char* dir, 601 const char* rel, DriverWalkFileFn cb, 602 void* user) { 603 DIR* d; 604 struct dirent* ent; 605 int rc = 1; 606 d = opendir(dir); 607 if (!d) return 1; 608 while ((ent = readdir(d)) != NULL) { 609 const char* name = ent->d_name; 610 char* child; 611 char* child_rel; 612 struct stat sb; 613 int child_rc = 0; 614 if (driver_streq(name, ".") || driver_streq(name, "..")) continue; 615 child = driver_join_path(env, dir, name); 616 if (!child) goto out; 617 child_rel = rel && rel[0] ? driver_join_path(env, rel, name) 618 : driver_join_path(env, "", name); 619 if (!child_rel) { 620 driver_free(env, child, kit_slice_cstr(child).len + 1u); 621 goto out; 622 } 623 if (lstat(child, &sb) != 0) { 624 child_rc = 1; 625 } else if (S_ISDIR(sb.st_mode)) { 626 child_rc = driver_walk_regular_files_at(env, child, child_rel, cb, user); 627 } else if (S_ISREG(sb.st_mode)) { 628 int x = (sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0; 629 child_rc = cb(user, child, child_rel, x); 630 } else { 631 child_rc = 1; 632 } 633 driver_free(env, child_rel, kit_slice_cstr(child_rel).len + 1u); 634 driver_free(env, child, kit_slice_cstr(child).len + 1u); 635 if (child_rc) goto out; 636 } 637 rc = 0; 638 639 out: 640 closedir(d); 641 return rc; 642 } 643 644 int driver_walk_regular_files(DriverEnv* env, const char* root, 645 DriverWalkFileFn cb, void* user) { 646 if (!env || !root || !root[0] || !cb) return 1; 647 return driver_walk_regular_files_at(env, root, "", cb, user); 648 } 649 650 /* ---------------- time ---------------- */ 651 652 uint64_t driver_now_ns(void) { 653 struct timespec ts; 654 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) 655 return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec; 656 return 0; 657 } 658 659 int driver_random_bytes(uint8_t* out, size_t n) { 660 /* /dev/urandom is the most portable CSPRNG across darwin/linux/freebsd and 661 * avoids getentropy()'s per-platform header/feature-macro gymnastics. */ 662 size_t off = 0; 663 int fd; 664 if (!out) return 1; 665 fd = open("/dev/urandom", O_RDONLY); 666 if (fd < 0) return 1; 667 while (off < n) { 668 ssize_t r = read(fd, out + off, n - off); 669 if (r > 0) { 670 off += (size_t)r; 671 } else if (r < 0 && errno == EINTR) { 672 continue; 673 } else { 674 close(fd); 675 return 1; 676 } 677 } 678 close(fd); 679 return 0; 680 } 681 682 /* ---------------- load helpers ---------------- */ 683 684 int driver_load_bytes(const KitFileIO* io, const char* tool, const char* path, 685 DriverLoad* out, KitSlice* in) { 686 out->loaded = 0; 687 out->fd.data = NULL; 688 out->fd.size = 0; 689 out->fd.token = NULL; 690 if (!io || !io->read_all) { 691 driver_errf(tool, "host file I/O unavailable"); 692 return 1; 693 } 694 if (io->read_all(io->user, path, &out->fd) != KIT_OK) { 695 driver_errf(tool, "failed to read: %.*s", 696 KIT_SLICE_ARG(kit_slice_cstr(path))); 697 return 1; 698 } 699 out->loaded = 1; 700 in->data = out->fd.data; 701 in->len = out->fd.size; 702 return 0; 703 } 704 705 void driver_release_bytes(const KitFileIO* io, DriverLoad* lf) { 706 if (!lf || !lf->loaded) return; 707 if (io && io->release) io->release(io->user, &lf->fd); 708 lf->loaded = 0; 709 } 710 711 /* ---------------- stdin / edit_temp / read_line ---------------- */ 712 713 int driver_read_stdin(DriverEnv* e, uint8_t** out_data, size_t* out_size) { 714 size_t cap = 4096; 715 size_t len = 0; 716 uint8_t* buf = e->heap->alloc(e->heap, cap, 1); 717 if (!buf) return 0; 718 for (;;) { 719 ssize_t n; 720 if (len == cap) { 721 size_t newcap = cap * 2; 722 uint8_t* nb = e->heap->realloc(e->heap, buf, cap, newcap, 1); 723 if (!nb) { 724 e->heap->free(e->heap, buf, cap); 725 return 0; 726 } 727 buf = nb; 728 cap = newcap; 729 } 730 n = read(STDIN_FILENO, buf + len, cap - len); 731 if (n == 0) break; 732 if (n < 0) { 733 e->heap->free(e->heap, buf, cap); 734 return 0; 735 } 736 len += (size_t)n; 737 } 738 if (len < cap) { 739 uint8_t* shrunk = len ? e->heap->realloc(e->heap, buf, cap, len, 1) : NULL; 740 if (len && !shrunk) { 741 *out_data = buf; 742 *out_size = cap; 743 return 1; 744 } 745 if (!len) { 746 e->heap->free(e->heap, buf, cap); 747 buf = NULL; 748 } else { 749 buf = shrunk; 750 } 751 } 752 *out_data = buf; 753 *out_size = len; 754 return 1; 755 } 756 757 static int driver_write_fd_all(int fd, const uint8_t* data, size_t n) { 758 size_t off = 0; 759 while (off < n) { 760 ssize_t wr = write(fd, data + off, n - off); 761 if (wr < 0) { 762 if (errno == EINTR) continue; 763 return 0; 764 } 765 if (wr == 0) return 0; 766 off += (size_t)wr; 767 } 768 return 1; 769 } 770 771 static char* driver_shell_quote_path(DriverEnv* e, const char* path, 772 size_t path_len, size_t* quoted_len_out) { 773 size_t i; 774 size_t quoted_len = 2u; 775 char* out; 776 char* q; 777 for (i = 0; i < path_len; ++i) quoted_len += path[i] == '\'' ? 4u : 1u; 778 out = e->heap->alloc(e->heap, quoted_len + 1u, 1); 779 if (!out) return NULL; 780 q = out; 781 *q++ = '\''; 782 for (i = 0; i < path_len; ++i) { 783 if (path[i] == '\'') { 784 *q++ = '\''; 785 *q++ = '\\'; 786 *q++ = '\''; 787 *q++ = '\''; 788 } else { 789 *q++ = path[i]; 790 } 791 } 792 *q++ = '\''; 793 *q = '\0'; 794 if (quoted_len_out) *quoted_len_out = quoted_len; 795 return out; 796 } 797 798 int driver_edit_temp(DriverEnv* e, const char* suffix, const uint8_t* initial, 799 size_t initial_size, uint8_t** out_data, 800 size_t* out_size) { 801 const char* editor; 802 const char* tmpdir; 803 const char* base = "/kit-dbg-XXXXXX"; 804 size_t tmpdir_len; 805 size_t base_len; 806 size_t suffix_len; 807 size_t path_len; 808 char* path; 809 int fd = -1; 810 int ok = 0; 811 KitFileData fd_data; 812 813 if (!out_data || !out_size) return 0; 814 *out_data = NULL; 815 *out_size = 0; 816 suffix_len = suffix ? kit_slice_cstr(suffix).len : 0u; 817 tmpdir = getenv("TMPDIR"); 818 if (!tmpdir || !*tmpdir) tmpdir = "/tmp"; 819 tmpdir_len = kit_slice_cstr(tmpdir).len; 820 base_len = kit_slice_cstr(base).len; 821 path_len = tmpdir_len + base_len + suffix_len; 822 path = e->heap->alloc(e->heap, path_len + 1u, 1); 823 if (!path) return 0; 824 memcpy(path, tmpdir, tmpdir_len); 825 memcpy(path + tmpdir_len, base, base_len); 826 if (suffix_len) memcpy(path + tmpdir_len + base_len, suffix, suffix_len); 827 path[path_len] = '\0'; 828 829 fd = mkstemps(path, (int)suffix_len); 830 if (fd < 0) goto out; 831 if (initial_size && 832 !driver_write_fd_all(fd, initial ? initial : (const uint8_t*)"", 833 initial_size)) 834 goto out; 835 if (close(fd) != 0) { 836 fd = -1; 837 goto out; 838 } 839 fd = -1; 840 841 editor = getenv("VISUAL"); 842 if (!editor || !*editor) editor = getenv("EDITOR"); 843 if (!editor || !*editor) editor = "vi"; 844 { 845 size_t editor_len = kit_slice_cstr(editor).len; 846 size_t quoted_len = 0; 847 char* quoted = driver_shell_quote_path(e, path, path_len, "ed_len); 848 char* cmd; 849 int status; 850 pid_t pid; 851 if (!quoted) goto out; 852 cmd = e->heap->alloc(e->heap, editor_len + 1u + quoted_len + 1u, 1); 853 if (!cmd) { 854 e->heap->free(e->heap, quoted, quoted_len + 1u); 855 goto out; 856 } 857 memcpy(cmd, editor, editor_len); 858 cmd[editor_len] = ' '; 859 memcpy(cmd + editor_len + 1u, quoted, quoted_len + 1u); 860 e->heap->free(e->heap, quoted, quoted_len + 1u); 861 pid = fork(); 862 if (pid == 0) { 863 execl("/bin/sh", "sh", "-c", cmd, (char*)NULL); 864 _exit(127); 865 } 866 e->heap->free(e->heap, cmd, editor_len + 1u + quoted_len + 1u); 867 if (pid < 0) goto out; 868 do { 869 if (waitpid(pid, &status, 0) < 0) { 870 if (errno == EINTR) continue; 871 goto out; 872 } 873 break; 874 } while (1); 875 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) goto out; 876 } 877 878 fd_data.data = NULL; 879 fd_data.size = 0; 880 fd_data.token = NULL; 881 if (posix_read_all(e, path, &fd_data) != KIT_OK) goto out; 882 *out_data = (uint8_t*)fd_data.data; 883 *out_size = fd_data.size; 884 ok = 1; 885 886 out: 887 if (fd >= 0) close(fd); 888 if (path) { 889 unlink(path); 890 e->heap->free(e->heap, path, path_len + 1u); 891 } 892 return ok; 893 } 894 895 int driver_read_line(char* buf, size_t cap) { 896 size_t len = 0; 897 if (!buf || cap < 2) return -1; 898 for (;;) { 899 int c; 900 errno = 0; 901 c = fgetc(stdin); 902 if (c == EOF) { 903 buf[len] = '\0'; 904 if (errno == EINTR) { 905 clearerr(stdin); 906 return -2; 907 } 908 if (ferror(stdin)) return -1; 909 if (len == 0) return 0; 910 return (int)len; 911 } 912 if (c == '\n') { 913 buf[len] = '\0'; 914 return (int)len; 915 } 916 if (len + 1 < cap) buf[len++] = (char)c; 917 } 918 } 919 920 static void line_completion_list_fini(DriverLineCompletionList* l) { 921 uint32_t i; 922 if (!l || !l->env) return; 923 for (i = 0; i < l->count; ++i) { 924 if (l->items[i].text) 925 driver_free(l->env, l->items[i].text, l->items[i].size); 926 } 927 if (l->items) 928 driver_free(l->env, l->items, (size_t)l->cap * sizeof(*l->items)); 929 } 930 931 static int line_history_add(DriverEnv* env, DriverLineHistory* h, 932 const char* line, size_t len) { 933 char** ni; 934 size_t* ns; 935 char* copy; 936 uint32_t nc; 937 size_t old_items_size; 938 size_t new_items_size; 939 size_t old_sizes_size; 940 size_t new_sizes_size; 941 if (!env || !h || !line || len == 0) return 0; 942 if (h->count > 0 && h->items[h->count - 1] && 943 strlen(h->items[h->count - 1]) == len && 944 memcmp(h->items[h->count - 1], line, len) == 0) 945 return 0; 946 if (h->count == h->cap) { 947 nc = h->cap ? h->cap * 2u : 32u; 948 old_items_size = (size_t)h->cap * sizeof(*h->items); 949 new_items_size = (size_t)nc * sizeof(*h->items); 950 old_sizes_size = (size_t)h->cap * sizeof(*h->sizes); 951 new_sizes_size = (size_t)nc * sizeof(*h->sizes); 952 ni = (char**)env->heap->realloc(env->heap, h->items, old_items_size, 953 new_items_size, _Alignof(char*)); 954 if (!ni) return 1; 955 h->items = ni; 956 ns = (size_t*)env->heap->realloc(env->heap, h->sizes, old_sizes_size, 957 new_sizes_size, _Alignof(size_t)); 958 if (!ns) return 1; 959 h->sizes = ns; 960 h->cap = nc; 961 } 962 copy = (char*)driver_alloc(env, len + 1u); 963 if (!copy) return 1; 964 memcpy(copy, line, len); 965 copy[len] = '\0'; 966 h->items[h->count] = copy; 967 h->sizes[h->count] = len + 1u; 968 h->count++; 969 return 0; 970 } 971 972 static void line_redraw(const char* prompt, const char* buf, size_t len, 973 size_t cursor) { 974 size_t back = len - cursor; 975 fputc('\r', stdout); 976 fputs(prompt, stdout); 977 if (len) fwrite(buf, 1, len, stdout); 978 fputs("\033[K", stdout); 979 if (back) fprintf(stdout, "\033[%zuD", back); 980 fflush(stdout); 981 } 982 983 static void line_set(char* buf, size_t cap, size_t* len, size_t* cursor, 984 const char* src) { 985 size_t n = strlen(src); 986 if (n >= cap) n = cap - 1u; 987 memmove(buf, src, n); 988 buf[n] = '\0'; 989 *len = n; 990 *cursor = n; 991 } 992 993 static int line_replace(char* buf, size_t cap, size_t* len, size_t* cursor, 994 size_t start, size_t end, const char* rep, 995 size_t rep_len) { 996 size_t tail; 997 if (start > end || end > *len) return 1; 998 tail = *len - end; 999 if (start + rep_len + tail + 1u > cap) return 1; 1000 memmove(buf + start + rep_len, buf + end, tail + 1u); 1001 if (rep_len) memcpy(buf + start, rep, rep_len); 1002 *len = start + rep_len + tail; 1003 *cursor = start + rep_len; 1004 return 0; 1005 } 1006 1007 static size_t line_common_prefix(const DriverLineCompletionList* l) { 1008 size_t n; 1009 uint32_t i; 1010 if (!l || l->count == 0) return 0; 1011 n = strlen(l->items[0].text); 1012 for (i = 1; i < l->count; ++i) { 1013 size_t j = 0; 1014 const char* s = l->items[i].text; 1015 while (j < n && s[j] && s[j] == l->items[0].text[j]) ++j; 1016 n = j; 1017 } 1018 return n; 1019 } 1020 1021 static void line_default_complete_range(const char* buf, size_t cursor, 1022 size_t* start, size_t* end) { 1023 size_t s = cursor; 1024 while (s > 0 && buf[s - 1] != ' ' && buf[s - 1] != '\t') --s; 1025 *start = s; 1026 *end = cursor; 1027 } 1028 1029 static void line_complete(DriverEnv* env, char* buf, size_t cap, size_t* len, 1030 size_t* cursor, const char* prompt, 1031 DriverLineCompleteFn complete, void* complete_user) { 1032 DriverLineCompletionList list; 1033 size_t common; 1034 size_t cur_len; 1035 uint32_t i; 1036 if (!complete) return; 1037 { 1038 DriverLineCompletionList z = {0}; 1039 list = z; 1040 } 1041 list.env = env; 1042 line_default_complete_range(buf, *cursor, &list.replace_start, 1043 &list.replace_end); 1044 complete(complete_user, buf, *cursor, &list); 1045 if (list.replace_end > *len) list.replace_end = *len; 1046 if (list.replace_start > list.replace_end) 1047 list.replace_start = list.replace_end; 1048 if (list.count == 1) { 1049 size_t rn = strlen(list.items[0].text); 1050 if (line_replace(buf, cap, len, cursor, list.replace_start, 1051 list.replace_end, list.items[0].text, rn) != 0) 1052 fputc('\a', stdout); 1053 line_redraw(prompt, buf, *len, *cursor); 1054 line_completion_list_fini(&list); 1055 return; 1056 } 1057 if (list.count > 1) { 1058 common = line_common_prefix(&list); 1059 cur_len = *cursor > list.replace_start ? *cursor - list.replace_start : 0; 1060 if (common > cur_len) { 1061 if (line_replace(buf, cap, len, cursor, list.replace_start, 1062 list.replace_end, list.items[0].text, common) != 0) 1063 fputc('\a', stdout); 1064 line_redraw(prompt, buf, *len, *cursor); 1065 } else { 1066 fputc('\n', stdout); 1067 for (i = 0; i < list.count; ++i) 1068 fprintf(stdout, " %s\n", list.items[i].text); 1069 line_redraw(prompt, buf, *len, *cursor); 1070 } 1071 } else { 1072 fputc('\a', stdout); 1073 fflush(stdout); 1074 } 1075 line_completion_list_fini(&list); 1076 } 1077 1078 int driver_read_line_edit(DriverEnv* env, const char* prompt, char* buf, 1079 size_t cap, DriverLineHistory* hist, 1080 DriverLineCompleteFn complete, void* complete_user) { 1081 struct termios orig; 1082 struct termios raw; 1083 char* saved = NULL; 1084 size_t saved_size = 0; 1085 size_t len = 0; 1086 size_t cursor = 0; 1087 uint32_t hist_pos = 0; 1088 int have_saved = 0; 1089 int raw_enabled = 0; 1090 int out_rc = -1; 1091 1092 if (!buf || cap < 2) return -1; 1093 if (!prompt) prompt = ""; 1094 if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) { 1095 int n; 1096 fputs(prompt, stdout); 1097 fflush(stdout); 1098 n = driver_read_line(buf, cap); 1099 if (n > 0 && hist) (void)line_history_add(env, hist, buf, (size_t)n); 1100 return n; 1101 } 1102 1103 if (tcgetattr(STDIN_FILENO, &orig) != 0) goto out; 1104 raw = orig; 1105 raw.c_lflag &= (tcflag_t) ~(ICANON | ECHO | IEXTEN); 1106 raw.c_iflag &= (tcflag_t) ~(IXON); 1107 raw.c_cc[VMIN] = 1; 1108 raw.c_cc[VTIME] = 0; 1109 if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) != 0) goto out; 1110 raw_enabled = 1; 1111 1112 saved = (char*)driver_alloc(env, cap); 1113 if (!saved) goto out; 1114 saved_size = cap; 1115 hist_pos = hist ? hist->count : 0; 1116 buf[0] = '\0'; 1117 1118 fputs(prompt, stdout); 1119 fflush(stdout); 1120 for (;;) { 1121 unsigned char c; 1122 ssize_t r = read(STDIN_FILENO, &c, 1); 1123 if (r < 0) { 1124 if (errno == EINTR) { 1125 out_rc = -2; 1126 goto out; 1127 } 1128 out_rc = -1; 1129 goto out; 1130 } 1131 if (r == 0) { 1132 out_rc = len ? (int)len : 0; 1133 goto out; 1134 } 1135 if (c == '\r' || c == '\n') { 1136 buf[len] = '\0'; 1137 fputc('\n', stdout); 1138 if (hist) (void)line_history_add(env, hist, buf, len); 1139 out_rc = (int)len; 1140 goto out; 1141 } 1142 if (c == 4) { 1143 if (len == 0) { 1144 buf[0] = '\0'; 1145 out_rc = 0; 1146 goto out; 1147 } 1148 continue; 1149 } 1150 if (c == '\t') { 1151 buf[len] = '\0'; 1152 line_complete(env, buf, cap, &len, &cursor, prompt, complete, 1153 complete_user); 1154 continue; 1155 } 1156 if (c == 1) { 1157 cursor = 0; 1158 line_redraw(prompt, buf, len, cursor); 1159 continue; 1160 } 1161 if (c == 5) { 1162 cursor = len; 1163 line_redraw(prompt, buf, len, cursor); 1164 continue; 1165 } 1166 if (c == 11) { 1167 buf[cursor] = '\0'; 1168 len = cursor; 1169 line_redraw(prompt, buf, len, cursor); 1170 continue; 1171 } 1172 if (c == 127 || c == 8) { 1173 if (cursor == 0) { 1174 fputc('\a', stdout); 1175 fflush(stdout); 1176 continue; 1177 } 1178 memmove(buf + cursor - 1u, buf + cursor, len - cursor + 1u); 1179 --cursor; 1180 --len; 1181 line_redraw(prompt, buf, len, cursor); 1182 continue; 1183 } 1184 if (c == 27) { 1185 unsigned char seq[3]; 1186 ssize_t r1 = read(STDIN_FILENO, seq, 1); 1187 ssize_t r2 = read(STDIN_FILENO, seq + 1, 1); 1188 if (r1 != 1 || r2 != 1 || seq[0] != '[') continue; 1189 if (seq[1] == 'A') { 1190 if (hist && hist->count > 0 && hist_pos > 0) { 1191 if (!have_saved) { 1192 memcpy(saved, buf, len + 1u); 1193 have_saved = 1; 1194 } 1195 --hist_pos; 1196 line_set(buf, cap, &len, &cursor, hist->items[hist_pos]); 1197 line_redraw(prompt, buf, len, cursor); 1198 } 1199 } else if (seq[1] == 'B') { 1200 if (hist && have_saved && hist_pos < hist->count) { 1201 ++hist_pos; 1202 if (hist_pos == hist->count) 1203 line_set(buf, cap, &len, &cursor, saved); 1204 else 1205 line_set(buf, cap, &len, &cursor, hist->items[hist_pos]); 1206 line_redraw(prompt, buf, len, cursor); 1207 } 1208 } else if (seq[1] == 'C') { 1209 if (cursor < len) { 1210 ++cursor; 1211 line_redraw(prompt, buf, len, cursor); 1212 } 1213 } else if (seq[1] == 'D') { 1214 if (cursor > 0) { 1215 --cursor; 1216 line_redraw(prompt, buf, len, cursor); 1217 } 1218 } else if (seq[1] == 'H') { 1219 cursor = 0; 1220 line_redraw(prompt, buf, len, cursor); 1221 } else if (seq[1] == 'F') { 1222 cursor = len; 1223 line_redraw(prompt, buf, len, cursor); 1224 } else if (seq[1] >= '1' && seq[1] <= '9') { 1225 ssize_t r3 = read(STDIN_FILENO, seq + 2, 1); 1226 if (r3 == 1 && seq[1] == '3' && seq[2] == '~' && cursor < len) { 1227 memmove(buf + cursor, buf + cursor + 1u, len - cursor); 1228 --len; 1229 line_redraw(prompt, buf, len, cursor); 1230 } 1231 } 1232 continue; 1233 } 1234 if (c >= 32 && c != 127) { 1235 if (len + 1u >= cap) { 1236 fputc('\a', stdout); 1237 fflush(stdout); 1238 continue; 1239 } 1240 memmove(buf + cursor + 1u, buf + cursor, len - cursor + 1u); 1241 buf[cursor] = (char)c; 1242 ++cursor; 1243 ++len; 1244 line_redraw(prompt, buf, len, cursor); 1245 } 1246 } 1247 1248 out: 1249 if (raw_enabled) tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig); 1250 if (saved) driver_free(env, saved, saved_size); 1251 return out_rc; 1252 } 1253 1254 /* ---------------- dlsym resolver ---------------- */ 1255 1256 void* driver_dlsym_resolver(void* user, KitSlice name_s) { 1257 /* The linker hands us interned/pool slices that are NUL-terminated, so 1258 * we can pass .s straight through to the OS-specific os_dlsym. */ 1259 (void)user; 1260 if (!name_s.s || name_s.len == 0) return NULL; 1261 return os_dlsym(name_s.s); 1262 } 1263 1264 /* ---------------- SIGINT handler for the dbg REPL ---------------- */ 1265 1266 static void (*s_sigint_cb)(void*); 1267 static void* s_sigint_cb_user; 1268 1269 static void sigint_trampoline(int sig) { 1270 (void)sig; 1271 if (s_sigint_cb) s_sigint_cb(s_sigint_cb_user); 1272 } 1273 1274 int driver_install_sigint(void (*cb)(void*), void* user) { 1275 struct sigaction sa; 1276 s_sigint_cb = cb; 1277 s_sigint_cb_user = user; 1278 sa.sa_handler = sigint_trampoline; 1279 sigemptyset(&sa.sa_mask); 1280 sa.sa_flags = 0; /* no SA_RESTART: fgetc returns EINTR */ 1281 return sigaction(SIGINT, &sa, NULL) == 0 ? 0 : 1; 1282 } 1283 1284 void driver_restore_sigint(void) { 1285 struct sigaction sa; 1286 s_sigint_cb = NULL; 1287 s_sigint_cb_user = NULL; 1288 sa.sa_handler = SIG_DFL; 1289 sigemptyset(&sa.sa_mask); 1290 sa.sa_flags = 0; 1291 sigaction(SIGINT, &sa, NULL); 1292 } 1293 1294 /* ---------------- host target ---------------- */ 1295 1296 static KitArchKind host_arch_self(void) { 1297 #if defined(__x86_64__) 1298 return KIT_ARCH_X86_64; 1299 #elif defined(__aarch64__) 1300 return KIT_ARCH_ARM_64; 1301 #elif defined(__arm__) 1302 return KIT_ARCH_ARM_32; 1303 #elif defined(__i386__) 1304 return KIT_ARCH_X86_32; 1305 #elif defined(__riscv) && (__riscv_xlen == 64) 1306 return KIT_ARCH_RV64; 1307 #elif defined(__riscv) && (__riscv_xlen == 32) 1308 return KIT_ARCH_RV32; 1309 #elif defined(__wasm__) 1310 return KIT_ARCH_WASM; 1311 #else 1312 return KIT_ARCH_X86_64; 1313 #endif 1314 } 1315 1316 KitTargetSpec driver_host_target(void) { 1317 KitTargetSpec t; 1318 t.arch = host_arch_self(); 1319 os_host_target_fill(&t); 1320 t.ptr_size = (uint8_t)sizeof(void*); 1321 t.ptr_align = (uint8_t)sizeof(void*); 1322 t.big_endian = 0; 1323 t.pic = driver_default_pic(t.obj, t.os); 1324 t.code_model = KIT_CM_DEFAULT; 1325 return t; 1326 } 1327 1328 /* ---------------- env wiring (POSIX) ---------------- */ 1329 1330 char g_cache_dir[4096]; 1331 1332 void driver_env_init(DriverEnv* e) { 1333 e->heap = &g_heap_libc; 1334 e->diag = &g_diag_stderr; 1335 e->file_io.read_all = posix_read_all; 1336 e->file_io.release = posix_release; 1337 e->file_io.open_writer = posix_open_writer; 1338 e->file_io.user = e; 1339 1340 g_execmem_posix.page_size = driver_host_page_size(); 1341 g_execmem_posix.reserve = execmem_reserve; 1342 g_execmem_posix.protect = execmem_protect; 1343 g_execmem_posix.release = execmem_release; 1344 g_execmem_posix.flush_icache = execmem_flush_icache; 1345 g_execmem_posix.user = NULL; 1346 e->execmem = &g_execmem_posix; 1347 1348 e->dbg_os = &g_dbg_os_posix; 1349 e->metrics = NULL; 1350 1351 { 1352 const char* xdg = getenv("XDG_CACHE_HOME"); 1353 const char* home = getenv("HOME"); 1354 if (xdg && *xdg) { 1355 snprintf(g_cache_dir, sizeof(g_cache_dir), "%s/kit", xdg); 1356 } else if (home && *home) { 1357 snprintf(g_cache_dir, sizeof(g_cache_dir), "%s/.cache/kit", home); 1358 } else { 1359 snprintf(g_cache_dir, sizeof(g_cache_dir), "build/kit-cache"); 1360 } 1361 e->cache_dir = g_cache_dir; 1362 } 1363 1364 /* Reproducible-build precedent: SOURCE_DATE_EPOCH wins over wall clock. */ 1365 { 1366 const char* sde = getenv("SOURCE_DATE_EPOCH"); 1367 if (sde && *sde) { 1368 char* endp = NULL; 1369 long long v = strtoll(sde, &endp, 10); 1370 e->now = (endp != sde && v >= 0) ? (int64_t)v : (int64_t)-1; 1371 } else { 1372 time_t t = time(NULL); 1373 e->now = (t == (time_t)-1) ? (int64_t)-1 : (int64_t)t; 1374 } 1375 } 1376 } 1377 1378 void driver_env_fini(DriverEnv* e) { 1379 /* Singletons; nothing to release. */ 1380 (void)e; 1381 } 1382 1383 KitContext driver_env_to_context(const DriverEnv* e) { 1384 KitContext c; 1385 c.heap = e->heap; 1386 c.file_io = &e->file_io; 1387 c.diag = e->diag; 1388 c.metrics = e->metrics; 1389 c.now = e->now; 1390 return c; 1391 } 1392 1393 KitJitHost driver_env_to_jit_host(const DriverEnv* e) { 1394 KitJitHost h; 1395 h.execmem = e->execmem; 1396 return h; 1397 } 1398 1399 KitDbgHost driver_env_to_dbg_host(const DriverEnv* e) { 1400 KitDbgHost h; 1401 h.os = e->dbg_os; 1402 return h; 1403 }