kit

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

freebsd.c (5155B)


      1 /* FreeBSD-specific env bits. Uses:
      2  *   - memfd_create(3) (FreeBSD 13+) for the dual-map fd
      3  *   - st_mtim (POSIX.1-2008) for mtime
      4  *   - dlsym(RTLD_DEFAULT) for the resolver
      5  *
      6  * If this file ever needs to support pre-13 FreeBSD, switch the fd source
      7  * to shm_open(SHM_ANON, O_RDWR, 0) + shm_unlink(); the rest of the dance
      8  * (ftruncate + two mmaps of the fd at distinct VAs) is identical. */
      9 
     10 #include <dlfcn.h>
     11 #include <stdint.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include <sys/mman.h>
     15 #include <sys/stat.h>
     16 #include <sys/sysctl.h>
     17 #include <sys/types.h>
     18 #include <unistd.h>
     19 
     20 #include "env_posix.h"
     21 
     22 /* ---------------- dual-mapped exec memory ---------------- */
     23 
     24 KitStatus os_execmem_reserve_exec(size_t size, KitExecMemRegion* out) {
     25   int fd = memfd_create("kit-jit", 0);
     26   void* w;
     27   void* r;
     28   ExecMemToken* tok;
     29   if (fd < 0) return KIT_ERR;
     30   if (ftruncate(fd, (off_t)size) != 0) {
     31     close(fd);
     32     return KIT_ERR;
     33   }
     34 
     35   w = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     36   if (w == MAP_FAILED) {
     37     close(fd);
     38     return KIT_NOMEM;
     39   }
     40   r = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
     41   if (r == MAP_FAILED) {
     42     munmap(w, size);
     43     close(fd);
     44     return KIT_NOMEM;
     45   }
     46   close(fd);
     47 
     48   tok = (ExecMemToken*)malloc(sizeof(*tok));
     49   if (!tok) {
     50     munmap(r, size);
     51     munmap(w, size);
     52     return KIT_NOMEM;
     53   }
     54   tok->write_addr = w;
     55   tok->runtime_addr = r;
     56   tok->size = size;
     57 
     58   exec_dual_register(w, r, size);
     59 
     60   out->write = w;
     61   out->runtime = r;
     62   out->size = size;
     63   out->token = tok;
     64   return KIT_OK;
     65 }
     66 
     67 /* ---------------- dbg W^X dance ---------------- */
     68 /* Same shape as Linux: prefer alias lookup, fall back to transient mprotect
     69  * of the runtime alias for single-mapping reservations. */
     70 
     71 static size_t page_floor(size_t v, size_t pg) { return v & ~(pg - 1); }
     72 static size_t page_ceil(size_t v, size_t pg) {
     73   return (v + pg - 1) & ~(pg - 1);
     74 }
     75 
     76 KitStatus os_dbg_code_write_begin(void* user, void* runtime_addr, size_t n,
     77                                   void** write_out) {
     78   size_t pg;
     79   uintptr_t a;
     80   uintptr_t base;
     81   size_t span;
     82   (void)user;
     83   if (!runtime_addr || !n || !write_out) return KIT_INVALID;
     84   if (exec_dual_lookup(runtime_addr, n, write_out) == 0) return KIT_OK;
     85   pg = driver_host_page_size();
     86   a = (uintptr_t)runtime_addr;
     87   base = page_floor(a, pg);
     88   span = page_ceil((a - base) + n, pg);
     89   if (mprotect((void*)base, span, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
     90     return KIT_ERR;
     91   *write_out = runtime_addr;
     92   return KIT_OK;
     93 }
     94 
     95 void os_dbg_code_write_end(void* user, void* runtime_addr, size_t n) {
     96   void* w;
     97   size_t pg;
     98   uintptr_t a;
     99   uintptr_t base;
    100   size_t span;
    101   (void)user;
    102   if (exec_dual_lookup(runtime_addr, n, &w) == 0) return;
    103   pg = driver_host_page_size();
    104   a = (uintptr_t)runtime_addr;
    105   base = page_floor(a, pg);
    106   span = page_ceil((a - base) + n, pg);
    107   mprotect((void*)base, span, PROT_READ | PROT_EXEC);
    108 }
    109 
    110 void os_dbg_flush_icache(void* user, void* runtime_addr, size_t n) {
    111   (void)user;
    112   env_flush_icache(runtime_addr, n);
    113 }
    114 
    115 /* ---------------- st_mtim ---------------- */
    116 
    117 int os_stat_mtime_ns(const struct stat* sb, int64_t* out) {
    118   *out =
    119       (int64_t)sb->st_mtim.tv_sec * 1000000000LL + (int64_t)sb->st_mtim.tv_nsec;
    120   return 0;
    121 }
    122 
    123 /* ---------------- dlsym ---------------- */
    124 
    125 void* os_dlsym(const char* name) {
    126   void* p = dlsym(RTLD_DEFAULT, name);
    127   if (!p && name[0] == '_' && name[1] != '\0')
    128     p = dlsym(RTLD_DEFAULT, name + 1);
    129   return p;
    130 }
    131 
    132 /* ---------------- host_target os/obj ---------------- */
    133 
    134 void os_host_target_fill(KitTargetSpec* t) {
    135   t->os = KIT_OS_FREEBSD;
    136   t->obj = KIT_OBJ_ELF;
    137 }
    138 
    139 /* ---------------- self executable path ---------------- */
    140 /* The KERN_PROC_PATHNAME sysctl returns the absolute path of a process's text
    141  * image; pid -1 selects the calling process. A first call with a NULL buffer
    142  * reports the required length (including the NUL). */
    143 int driver_self_exe_path(DriverEnv* env, char** out, size_t* out_size) {
    144   int mib[4];
    145   size_t len = 0;
    146   size_t cap;
    147   char* buf;
    148 
    149   if (!env || !out || !out_size) return 1;
    150   mib[0] = CTL_KERN;
    151   mib[1] = KERN_PROC;
    152   mib[2] = KERN_PROC_PATHNAME;
    153   mib[3] = -1;
    154   if (sysctl(mib, 4, NULL, &len, NULL, 0) != 0 || len == 0) return 1;
    155   cap = len;
    156   buf = (char*)driver_alloc(env, cap);
    157   if (!buf) return 1;
    158   if (sysctl(mib, 4, buf, &len, NULL, 0) != 0) {
    159     driver_free(env, buf, cap);
    160     return 1;
    161   }
    162   buf[cap - 1u] = '\0'; /* defensive: ensure termination */
    163   *out = buf;
    164   *out_size = cap;
    165   return 0;
    166 }
    167 
    168 /* ---------------- default hosted dirs probe ---------------- */
    169 /* FreeBSD base system is flat: headers in /usr/include, crt + libc in /usr/lib
    170  * and /lib (libc.so.7 lives in /lib). Host target only. */
    171 int driver_default_hosted_dirs(DriverEnv* env, KitTargetSpec target,
    172                                DriverHostedDirs* out) {
    173   (void)env;
    174   if (target.os != KIT_OS_FREEBSD) return 1;
    175   if (driver_hosted_dirs_add_inc(out, "/usr/include") != 0) return 1;
    176   if (driver_hosted_dirs_add_lib(out, "/usr/lib") != 0) return 1;
    177   if (driver_hosted_dirs_add_lib(out, "/lib") != 0) return 1;
    178   return out->nlibdirs ? 0 : 1;
    179 }