env.h (24195B)
1 #ifndef KIT_DRIVER_ENV_H 2 #define KIT_DRIVER_ENV_H 3 4 #include <kit/compile.h> 5 #include <kit/core.h> 6 #include <kit/dbg.h> 7 #include <kit/exec.h> 8 #include <kit/jit.h> 9 #include <kit/os.h> 10 #include <stdarg.h> 11 #include <stddef.h> 12 #include <stdint.h> 13 14 /* Shared host environment used by every tool that calls into libkit. 15 * driver_env_init wires up the libc-backed heap, the stderr diag sink, and 16 * a POSIX file_io implementation (open/read/write on real paths). It is 17 * the single piece of glue that turns "the host" into a KitContext. 18 * 19 * The execmem / dbg_os vtables that used to live on KitEnv now live on 20 * KitJitHost / KitDbgHost. They are still constructed here so that one 21 * DriverEnv covers every libkit-using tool, but they're handed to libkit 22 * per-call via the appropriate host struct. */ 23 typedef struct DriverEnv { 24 KitHeap* heap; 25 KitDiagSink* diag; 26 KitFileIO file_io; 27 const KitExecMem* execmem; 28 const KitDbgOs* dbg_os; /* NULL unless `kit dbg` paths run */ 29 KitProfiler* profiler; /* optional low-overhead profiling storage */ 30 int64_t now; /* unix seconds; -1 = unknown */ 31 const char* cache_dir; /* base cache dir, e.g. ~/.cache/kit */ 32 } DriverEnv; 33 34 void driver_env_init(DriverEnv*); 35 void driver_env_fini(DriverEnv*); 36 37 /* Build a KitContext value pointing at the DriverEnv's heap/diag/file_io 38 * vtables. The returned value can be passed by const-pointer to any 39 * libkit entry that takes `const KitContext *`. */ 40 KitContext driver_env_to_context(const DriverEnv*); 41 42 /* Build a KitJitHost from the DriverEnv (execmem). The returned struct 43 * holds a borrowed pointer to the vtable owned by g_execmem_posix; 44 * callers must not outlive driver_env_fini. */ 45 KitJitHost driver_env_to_jit_host(const DriverEnv*); 46 47 /* Build a KitDbgHost from the DriverEnv (dbg_os). */ 48 KitDbgHost driver_env_to_dbg_host(const DriverEnv*); 49 50 /* Tells the stderr diag sink which compiler to use when resolving 51 * SrcLoc.file_id to a path. The driver_compiler_{new,free} helpers 52 * below already manage this; call this directly only when you hand a 53 * KitCompiler from outside those helpers (none today). */ 54 void driver_diag_set_compiler(KitCompiler*); 55 56 /* Lifecycle helpers around kit_compiler_{new,free}. Identical to the raw 57 * entries except they register the active compiler with the stderr diag sink 58 * so diagnostics resolve loc.file_id to its registered path. The compiler 59 * borrows `target`; callers own it and must free it after driver_compiler_free. 60 * Returns KIT_OK on success; on failure *out is NULL. */ 61 KitStatus driver_compiler_new(const KitTarget*, const KitContext*, 62 KitCompiler** out); 63 void driver_compiler_free(KitCompiler*); 64 65 /* Driver-level post-compile diagnostic gate, enforcing the warning policies the 66 * C frontend does not yet honor from KitDiagnosticOptions. Call once after a 67 * compile/link run completes. When `warnings_are_errors` is set and libkit's 68 * diag sink recorded any warnings, emits an error and returns nonzero so the 69 * caller can fail the tool (-Werror). When `max_errors` is nonzero, emits a 70 * single note that -fmax-errors is unimplemented (the frontend does not bound 71 * the error count). Returns 0 when the run should be considered successful. */ 72 int driver_diag_finish(DriverEnv* env, const char* tool, 73 int warnings_are_errors, uint32_t max_errors); 74 75 /* Default target used by tools that don't expose a target-selection flag 76 * yet. v1: native-looking host target (chosen at compile time). */ 77 KitTargetSpec driver_host_target(void); 78 79 /* ---------------------------------------------------------------------- 80 * Hosted-libc search directories 81 * 82 * The hosted-libc resolver needs two sets of directories: include roots to add 83 * as system header search paths, and library roots to search for the C runtime 84 * objects and libc. They come from one of two producers -- expanding an 85 * explicit --sysroot/KIT_SYSROOT (portable, in driver/lib/hosted.c) or probing 86 * the live host (driver_default_hosted_dirs, below). The resolver copies what 87 * it needs into its plan, then releases the whole set with 88 * driver_hosted_dirs_fini; the strings stored here are transient scratch. 89 * 90 * DRIVER_HOSTED_MAX_INCDIRS must stay >= the plan's DRIVER_HOSTED_MAX_INCLUDES 91 * (driver/lib/hosted.h): every emitted incdir becomes one owned plan include. 92 * ---------------------------------------------------------------------- */ 93 #define DRIVER_HOSTED_MAX_INCDIRS KIT_OS_HOSTED_MAX_INCDIRS 94 #define DRIVER_HOSTED_MAX_LIBDIRS KIT_OS_HOSTED_MAX_LIBDIRS 95 96 typedef KitOsHostedDirs DriverHostedDirs; 97 98 /* Append an include/library directory, heap-duplicated from `dir`. The _join 99 * forms join `base` + `sub` with a single '/' separator first. A NULL/empty dir 100 * is a successful no-op; returns nonzero on allocation failure or when the list 101 * is full (loud overflow -- never a silent drop). dirs->env must be set. */ 102 int driver_hosted_dirs_add_inc(DriverHostedDirs* dirs, const char* dir); 103 int driver_hosted_dirs_add_lib(DriverHostedDirs* dirs, const char* dir); 104 int driver_hosted_dirs_add_inc_join(DriverHostedDirs* dirs, const char* base, 105 const char* sub); 106 int driver_hosted_dirs_add_lib_join(DriverHostedDirs* dirs, const char* base, 107 const char* sub); 108 /* Free all stored dir strings and zero the lists. Idempotent. */ 109 void driver_hosted_dirs_fini(DriverHostedDirs* dirs); 110 111 /* Probe the live host for hosted include/library dirs for `target`, used when 112 * no --sysroot/KIT_SYSROOT was given. Only the host's own platform is probed 113 * (the caller additionally gates on target-OS == host-OS) -- never for cross- 114 * compiles. Fills `out`, which the caller zero-inits with out->env set. Returns 115 * 0 when it produced at least one library dir, nonzero otherwise (out left 116 * empty). macOS resolves the SDK (the canonical Command Line Tools / Xcode 117 * roots; no subprocess, no env var) into <sdk>/usr/{include,lib}; Linux 118 * enumerates the multiarch dirs; FreeBSD the base dirs; Windows produces 119 * nothing (its MinGW sysroot comes from --sysroot/KIT_SYSROOT in the cc 120 * driver). The single env-var override, KIT_SYSROOT, is consulted by the 121 * caller, not here. */ 122 int driver_default_hosted_dirs(DriverEnv* env, KitTargetSpec target, 123 DriverHostedDirs* out); 124 125 /* ---------------------------------------------------------------------- 126 * Host-shim helpers 127 * 128 * driver/env.c is the only TU in the driver allowed to depend on libc 129 * facilities that issue syscalls or touch host state -- host stdio, malloc, 130 * POSIX I/O, environment, time. Other driver TUs are compiled freestanding 131 * against rt/include plus libkit's public headers. The shims below exist 132 * primarily for the syscall-shaped surface; other TUs may also call them for 133 * consistency. 134 * ---------------------------------------------------------------------- */ 135 136 /* String predicates and lookups. driver_streq / driver_strneq return 137 * non-zero when the strings (or first n bytes) match -- sense-flipped 138 * from libc's strcmp so call sites read naturally. */ 139 int driver_streq(const char* a, const char* b); 140 int driver_strneq(const char* a, const char* b, size_t n); 141 size_t driver_strlen(const char* s); 142 const char* driver_strchr(const char* s, int c); 143 const char* driver_basename(const char* path); 144 int driver_has_suffix(const char* s, const char* suffix); 145 146 /* Memory. Allocations route through DriverEnv.heap; release returns the 147 * size used at allocation (so the heap implementation can track usage). */ 148 void* driver_alloc(DriverEnv*, size_t); 149 void* driver_alloc_zeroed(DriverEnv*, size_t); 150 void driver_free(DriverEnv*, void* p, size_t); 151 void driver_memcpy(void* dst, const void* src, size_t n); 152 153 /* Opens a Writer that writes to stdout. close frees the struct but does 154 * not close stdout. */ 155 KitWriter* driver_stdout_writer(DriverEnv*); 156 157 /* Opens a Writer that writes to stderr. close frees the struct but does 158 * not close stderr. */ 159 KitWriter* driver_stderr_writer(DriverEnv*); 160 161 /* Test whether `path` names an existing filesystem entry (any type). 162 * Returns nonzero on existence, zero otherwise. Used by library-path 163 * resolution; intentionally distinct from read_all so candidate-search 164 * loops don't slurp file contents on a hit. */ 165 int driver_path_exists(const char* path); 166 167 /* Read a path's last modification time in nanoseconds since the Unix epoch. 168 * Returns 0 on success, nonzero on stat failure. */ 169 int driver_path_mtime_ns(const char* path, int64_t* out); 170 171 /* Stat a host path. Fills *out_size, *out_mtime_ns, and *out_filetype using 172 * the KIT_WASM_FILETYPE_* constants (0=unknown 1=block 2=char 3=dir 173 * 4=regular 5=dgram 6=stream 7=symlink). Returns 0 on success, 1 if the 174 * path does not exist, 2 on any other error. Does not require a DriverEnv. */ 175 int driver_path_stat(const char* path, uint64_t* out_size, 176 uint64_t* out_mtime_ns, uint8_t* out_filetype); 177 178 /* Like driver_path_stat but does NOT follow a terminal symlink (lstat) and 179 * additionally reports whether the entry is an executable regular file (any 180 * execute bit set). *out_executable is 0 for non-regular entries and on hosts 181 * without an executable bit (Windows). Fills *out_size and *out_filetype with 182 * the same KIT_WASM_FILETYPE_* coding as driver_path_stat. Returns 0 on 183 * success, 1 if the path does not exist, 2 on any other error. Used by 184 * `cpio -o` to classify operands without dereferencing symlinks and to carry 185 * the source executable bit into the archived mode. */ 186 int driver_path_lstat(const char* path, uint64_t* out_size, 187 uint8_t* out_filetype, int* out_executable); 188 189 /* Opaque directory-enumeration handle. Holds a snapshot of all entries 190 * (excluding "." and "..") taken at driver_open_dir time. */ 191 typedef struct DriverDirHandle DriverDirHandle; 192 193 /* Open a directory and snapshot its entries. Returns NULL on failure. */ 194 DriverDirHandle* driver_open_dir(DriverEnv*, const char* path); 195 196 /* Read the entry at zero-based index. Sets *out_name to a pointer borrowed 197 * from the handle (valid until driver_close_dir), *out_name_len to its byte 198 * length (not NUL-terminated), and fills *out_ino, *out_size, *out_mtime_ns, 199 * *out_filetype. Returns 0 on success, 1 when index >= entry count. */ 200 int driver_read_dir_entry(DriverDirHandle*, uint64_t index, 201 const char** out_name, uint32_t* out_name_len, 202 uint64_t* out_ino, uint64_t* out_size, 203 uint64_t* out_mtime_ns, uint8_t* out_filetype); 204 205 /* Free a directory handle. Safe to call with NULL. */ 206 void driver_close_dir(DriverEnv*, DriverDirHandle*); 207 208 /* Create a directory and any missing parents. Returns 0 on success. */ 209 int driver_mkdir_p(DriverEnv*, const char* path); 210 211 /* Resolve the absolute path of the running kit executable into a freshly 212 * heap-allocated, NUL-terminated buffer (*out / *out_size); free it with 213 * driver_free(env, *out, *out_size). Returns 0 on success, nonzero on 214 * failure (out untouched). Per-OS: /proc/self/exe (Linux), _NSGetExecutablePath 215 * + realpath (macOS), KERN_PROC_PATHNAME sysctl (FreeBSD), GetModuleFileNameW 216 * (Windows). Used by `install` to point freshly created links at the binary. */ 217 int driver_self_exe_path(DriverEnv*, char** out, size_t* out_size); 218 219 /* Resolve an existing host path to a normalized absolute path in a fresh 220 * DriverEnv allocation. POSIX uses realpath; Windows uses GetFullPathNameW. 221 * Returns 0 on success, nonzero for an invalid/missing path or allocation 222 * failure. This is the normalization boundary for support/sysroot discovery; 223 * callers free *out with driver_free(env, *out, *out_size). */ 224 int driver_path_canonicalize(DriverEnv*, const char* path, char** out, 225 size_t* out_size); 226 227 /* Create a symbolic link named `link_path` that resolves to `target`. Returns 228 * 0 on success. POSIX uses symlink(2); Windows uses CreateSymbolicLinkW, which 229 * may require privilege or Developer Mode (so `install` defaults to hard links 230 * on Windows). */ 231 int driver_create_symlink(const char* target, const char* link_path); 232 233 /* Read the target of the symbolic link at `path` into `buf` (capacity `cap`, 234 * including room for the terminating NUL), NUL-terminating it. Returns 0 on 235 * success, nonzero on failure or when the target does not fit in `cap`. POSIX 236 * uses readlink(2); Windows is best-effort and may always fail (initramfs 237 * symlinks are a Linux artifact), in which case the caller diagnoses. */ 238 int driver_readlink(const char* path, char* buf, size_t cap); 239 240 /* Create a hard link named `link_path` referring to the same file as `target`. 241 * Returns 0 on success. POSIX uses link(2); Windows uses CreateHardLinkW. Both 242 * require `target` and `link_path` to live on the same filesystem/volume. */ 243 int driver_create_hardlink(const char* target, const char* link_path); 244 245 /* Mark a DriverEnv-created writer as failed before close. Atomic file writers 246 * will remove their temp file and skip the final rename. Borrowed stdio writers 247 * just record a failed status; already-written stdout/stderr bytes cannot be 248 * recalled. */ 249 void driver_writer_abort(KitWriter* writer); 250 251 /* Remove the file or symlink at `path`. Returns 0 when the entry was removed or 252 * was already absent, nonzero on any other failure. POSIX unlink(2) / Windows 253 * DeleteFileW. */ 254 int driver_remove_file(const char* path); 255 256 /* Test whether a name exists at `path` WITHOUT following symlinks, so a 257 * dangling symlink still counts as existing. Returns nonzero on existence. 258 * POSIX lstat / Windows GetFileAttributesW. */ 259 int driver_path_lexists(const char* path); 260 261 /* Rename/move `from` to `to`, replacing any existing entry at `to`. Within one 262 * filesystem this is atomic, which `kit update` relies on for the version dir 263 * move and the `current` pointer flip. Returns 0 on success, nonzero on 264 * failure. POSIX rename(2); Windows MoveFileExW(MOVEFILE_REPLACE_EXISTING). */ 265 int driver_rename(const char* from, const char* to); 266 267 /* Recursively remove `path` and everything beneath it (a file, symlink, or 268 * directory tree). Used by `kit update` to clear a scratch unpack dir, replace 269 * a reinstalled version, and prune old versions. Does NOT follow symlinks (it 270 * unlinks the link itself). Returns 0 on success or when `path` is already 271 * absent, nonzero on any other failure. */ 272 int driver_remove_tree(const char* path); 273 274 /* Resolve the single-root kit home directory into `buf` (capacity `cap`, 275 * NUL-terminated, no trailing slash): `$KIT_HOME`, else `$XDG_DATA_HOME/kit`, 276 * else `$HOME/.local/share/kit` on POSIX (`%LOCALAPPDATA%\kit` on Windows). 277 * Used by `kit update` for versions/, current, bin/, config/, cache/. Returns 0 278 * on success, nonzero when no home could be determined or it does not fit. */ 279 int driver_kit_home(char* buf, size_t cap); 280 281 /* Fetch `url` to the local file `dest`, overwriting it. The transport is 282 * UNTRUSTED — the caller verifies a signature/content-id over the bytes. file:// 283 * URLs are copied internally; other schemes use curl on POSIX or curl.exe on 284 * Windows, with the URL passed as a distinct argv element (no shell and no 285 * downloader fallback). Returns 0 on success, nonzero on any failure. */ 286 int driver_fetch_url(const char* url, const char* dest); 287 288 /* Set a linked binary output's final mode according to the active umask. 289 * Returns 0 on success, nonzero on chmod failure. */ 290 int driver_mark_executable_output(const char* path); 291 292 /* Capture and restore the permission mode of a regular output. POSIX carries 293 * all permission/special bits accepted by chmod; Windows returns an opaque 294 * zero mode and treats restoration as a successful no-op because execution is 295 * extension/ACL based there. These helpers let transactional rewrites preserve 296 * an input's mode even though the atomic writer replaces its inode. */ 297 int driver_path_mode_get(const char* path, uint32_t* mode_out); 298 int driver_path_mode_set(const char* path, uint32_t mode); 299 300 /* Walk regular files below `root`, reporting tree-relative paths with '/' 301 * separators. The callback returns nonzero to abort the walk. Unsupported 302 * filesystem entries cause a nonzero return from the walk helper. */ 303 typedef int (*DriverWalkFileFn)(void* user, const char* source_path, 304 const char* tree_path, int executable); 305 int driver_walk_regular_files(DriverEnv*, const char* root, DriverWalkFileFn, 306 void* user); 307 308 /* Diagnostic printing to host stderr. Format is `"<tool>: <fmt>\n"`. */ 309 void driver_errf(const char* tool, const char* fmt, ...); 310 void driver_verrf(const char* tool, const char* fmt, va_list ap); 311 312 /* Raw hosted stderr log. Used by optional metrics/profiling output so libkit 313 * stays free of hosted I/O. */ 314 void driver_logf(const char* fmt, ...); 315 316 /* Formatted output to stdout. */ 317 void driver_printf(const char* fmt, ...); 318 319 /* Monotonic host time in nanoseconds, or 0 if unavailable. */ 320 uint64_t driver_now_ns(void); 321 322 /* Fill `out` with `n` cryptographically-random bytes from the host CSPRNG. 323 * Returns 0 on success, non-zero on failure (in which case `out` must not be 324 * used). This is the single entropy source for key generation; the crypto 325 * primitives themselves never source randomness — it always flows in here. */ 326 int driver_random_bytes(uint8_t* out, size_t n); 327 328 /* Lookup a process environment variable; returns NULL if unset. The returned 329 * pointer aliases libc-owned storage and is valid until the next setenv/ 330 * putenv from any caller. */ 331 const char* driver_getenv(const char* name); 332 333 /* Borrow the process environment as NAME=VALUE strings. The array and strings 334 * are libc-owned and remain valid until the process environment is mutated. */ 335 const char* const* driver_environ(void); 336 337 /* Build a KitExec (<kit/exec.h>) backed by this DriverEnv's heap: the shared 338 * config-struct subprocess interface used by the build coordinator and `kit 339 * make`. The returned value borrows `env` (its `user`); do not outlive env. 340 * Implemented in driver/env/exec_{posix,windows}.c. */ 341 KitExec driver_exec(DriverEnv* env); 342 /* Set path's mtime to now, creating it empty if absent (make -t). 0 on success. */ 343 int driver_touch(const char* path); 344 345 /* Read all of stdin into a freshly-allocated buffer. On success returns 1 346 * and stores the buffer/size in out_data/out_size; the caller frees via 347 * driver_free(env, *out_data, *out_size). Returns 0 on read failure or 348 * allocation failure. */ 349 int driver_read_stdin(DriverEnv*, uint8_t** out_data, size_t* out_size); 350 351 /* Open a temporary file in $VISUAL, then $EDITOR, then vi. `suffix` should 352 * include the leading dot when a language-specific extension is useful. 353 * On success, returns the edited bytes in a freshly allocated buffer that the 354 * caller frees with driver_free(env, *out_data, *out_size). */ 355 int driver_edit_temp(DriverEnv*, const char* suffix, const uint8_t* initial, 356 size_t initial_size, uint8_t** out_data, size_t* out_size); 357 358 /* Path-shaped input loader. Wraps env.file_io.read_all so each tool can 359 * convert a list of paths to a list of KitSlice without re-implementing 360 * load/release/error bookkeeping. `loaded` is set to 1 on success; release is 361 * idempotent and does nothing when loaded is already 0. driver_load_bytes 362 * fills `in.name = path` plus the loaded data/len; driver_release_bytes hands 363 * the buffer back through file_io.release. On failure an error is emitted via 364 * driver_errf using the supplied tool tag. */ 365 typedef struct DriverLoad { 366 KitFileData fd; 367 int loaded; 368 } DriverLoad; 369 370 int driver_load_bytes(const KitFileIO*, const char* tool, const char* path, 371 DriverLoad* out, KitSlice* in); 372 void driver_release_bytes(const KitFileIO*, DriverLoad*); 373 374 /* Read one line from stdin into `buf` (cap >= 2). Strips the trailing 375 * newline and NUL-terminates. Returns the line length on success, 0 at 376 * EOF (with buf[0]='\0'), -1 on read error, or -2 when the read was 377 * interrupted by a signal (caller should print a fresh prompt and 378 * retry). Over-long lines are truncated to cap-1 bytes; the remainder 379 * up to the next newline is consumed silently. */ 380 int driver_read_line(char* buf, size_t cap); 381 382 typedef struct DriverLineHistory { 383 char** items; 384 size_t* sizes; 385 uint32_t count; 386 uint32_t cap; 387 } DriverLineHistory; 388 389 typedef struct DriverLineCompletion { 390 char* text; 391 size_t size; 392 } DriverLineCompletion; 393 394 typedef struct DriverLineCompletionList { 395 DriverEnv* env; 396 DriverLineCompletion* items; 397 uint32_t count; 398 uint32_t cap; 399 size_t replace_start; 400 size_t replace_end; 401 } DriverLineCompletionList; 402 403 typedef void (*DriverLineCompleteFn)(void* user, const char* line, 404 size_t cursor, 405 DriverLineCompletionList* out); 406 407 int driver_line_completion_add(DriverLineCompletionList*, const char* text, 408 size_t len); 409 /* Raw-mode line editor with history + tab completion. Ctrl-G drops the 410 * currently typed line into $EDITOR (seeded via driver_edit_temp using 411 * `edit_suffix` for the temp file's extension) and reloads the edited text 412 * back into the buffer, so the prompt is populated with what was typed. 413 * `edit_suffix` may be NULL to use an extension-less temp file; it is ignored 414 * on hosts whose line editor reads in cooked mode (no key interception). */ 415 int driver_read_line_edit(DriverEnv*, const char* prompt, char* buf, size_t cap, 416 DriverLineHistory*, DriverLineCompleteFn, 417 void* complete_user, const char* edit_suffix); 418 void driver_line_history_fini(DriverEnv*, DriverLineHistory*); 419 420 /* Flush the host stdout. The dbg REPL prompt has no trailing newline, so 421 * without an explicit flush the prompt stays buffered until the next 422 * line of output. */ 423 void driver_flush_stdout(void); 424 425 /* Install / restore a SIGINT handler. While installed, SIGINT runs `cb(user)` 426 * synchronously (so `cb` must be async-signal safe). Used by `dbg` to 427 * forward Ctrl-C into kit_dbg_session_interrupt while the worker is 428 * running, and to restore SIG_DFL while sitting at the REPL prompt so 429 * Ctrl-C terminates the program normally. Returns 0 on success. */ 430 int driver_install_sigint(void (*cb)(void*), void* user); 431 void driver_restore_sigint(void); 432 433 /* Crash-guarded execution for `kit run`. 434 * 435 * `entry` is the JITed program entry, invoked as `entry(argc, argv)`. On a 436 * clean return, *ret_out receives the program's status and the call returns 0. 437 * 438 * On a fatal fault raised by the program (SIGSEGV/SIGBUS/SIGILL/SIGFPE/SIGABRT/ 439 * SIGTRAP — the last covers __builtin_trap / failed asserts), the guard walks 440 * the frame-pointer chain *inside the signal handler* (where the faulting stack 441 * is still intact, since `kit run` shares its stack with the program), captures 442 * the return addresses innermost-first, and invokes `on_crash(user, signo, pcs, 443 * npcs)` from normal context — so symbolization (DWARF/malloc/printf) never 444 * runs async-signal. `arch` selects the FP register / pointer width for the 445 * walk. The call then returns 1; the program's own return value is undefined on 446 * this path, so the caller should treat the run as failed. 447 * 448 * Hosts without a fault guard (Windows) run `entry` directly, set *ret_out, and 449 * return 0 without ever calling on_crash. */ 450 typedef int (*DriverRunEntryFn)(int argc, char** argv); 451 typedef void (*DriverRunCrashFn)(void* user, int signo, const uint64_t* pcs, 452 int npcs); 453 int driver_run_with_crash_guard(DriverEnv* env, KitArchKind arch, 454 DriverRunEntryFn entry, int argc, char** argv, 455 int* ret_out, DriverRunCrashFn on_crash, 456 void* user); 457 458 /* Host-symbol resolver for JIT extern_resolver. Looks up `name` via 459 * dlsym(RTLD_DEFAULT, ...) on POSIX hosts, returning NULL on miss. Stateless; 460 * `user` is ignored and may be NULL. Wired into `kit run` so JITed code 461 * can call libc symbols (printf, malloc, ...) without an explicit linker 462 * step. */ 463 void* driver_dlsym_resolver(void* user, KitSlice name); 464 465 #endif