kit

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

commit e2f339d3eade735eba75b825ca40478aa7d2c579
parent dfc469bfd5b8989da32e1941ac3f7bfe6af84310
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 21 May 2026 10:32:39 -0700

Implement JIT session resilience via setjmp/longjmp

Diffstat:
Mdriver/dbg.c | 15++++++++++++++-
Mdriver/env.c | 18++++++++++++++++++
Minclude/cfree/dbg.h | 5+++++
Msrc/dbg/session.c | 36+++++++++++++++++++++++++++++-------
Msrc/dbg/step.c | 2++
5 files changed, 68 insertions(+), 8 deletions(-)

diff --git a/driver/dbg.c b/driver/dbg.c @@ -769,7 +769,10 @@ static int dbg_drive(DbgState *s, DbgRunMode mode) { if (mode == RUN_FRESH && s->has_stop) { /* The previous session is dead (entry returned or signal landed). - * Start a new one. */ + * Start a new one. Try to abort it first in case it's parked in a fault. */ + if (s->session) { + cfree_jit_session_resume(s->session, CFREE_RESUME_ABORT, NULL); + } s->has_stop = 0; } else if (mode != RUN_FRESH && !s->has_stop) { driver_errf(DBG_TOOL, "no program is running; use 'r' to start"); @@ -2692,6 +2695,16 @@ static int dbg_dispatch(DbgState *s, char *line) { dbg_drive(s, RUN_FRESH); return 0; } + if (driver_streq(cmd, "abort")) { + if (s->has_stop && s->session) { + cfree_jit_session_resume(s->session, CFREE_RESUME_ABORT, NULL); + s->has_stop = 0; + driver_errf(DBG_TOOL, "execution aborted"); + } else { + driver_errf(DBG_TOOL, "nothing to abort"); + } + return 0; + } if (driver_streq(cmd, "c") || driver_streq(cmd, "cont") || driver_streq(cmd, "continue")) { dbg_drive(s, RUN_CONTINUE); diff --git a/driver/env.c b/driver/env.c @@ -841,6 +841,22 @@ static CfreeStatus dbg_guarded_copy(void *user, void *dst, const void *src, return CFREE_OK; } +static __thread sigjmp_buf g_dbg_abort_buf; + +static int dbg_call_with_catch(void *user, void (*fn)(void *), void *arg) { + (void)user; + if (sigsetjmp(g_dbg_abort_buf, 1) == 0) { + fn(arg); + return 0; + } + return 1; +} + +static void dbg_thread_abort(void *user) { + (void)user; + siglongjmp(g_dbg_abort_buf, 1); +} + static CfreeDbgOs g_dbg_os_posix; /* ---------------- jit_tls (pthread-key backed) ---------------- */ @@ -1191,6 +1207,8 @@ void driver_env_init(DriverEnv *e) { g_dbg_os_posix.code_write_end = dbg_code_write_end; g_dbg_os_posix.flush_icache = dbg_flush_icache; g_dbg_os_posix.guarded_copy = dbg_guarded_copy; + g_dbg_os_posix.call_with_catch = dbg_call_with_catch; + g_dbg_os_posix.thread_abort = dbg_thread_abort; g_dbg_os_posix.user = NULL; e->dbg_os = &g_dbg_os_posix; diff --git a/include/cfree/dbg.h b/include/cfree/dbg.h @@ -40,6 +40,10 @@ typedef struct CfreeDbgOs { CfreeStatus (*guarded_copy)(void *user, void *dst, const void *src, size_t n); + + int (*call_with_catch)(void *user, void (*fn)(void *), void *arg); + void (*thread_abort)(void *user); + void *user; } CfreeDbgOs; @@ -68,6 +72,7 @@ typedef enum CfreeResumeMode { CFREE_RESUME_STEP_LINE, CFREE_RESUME_NEXT_LINE, CFREE_RESUME_STEP_OUT, + CFREE_RESUME_ABORT, } CfreeResumeMode; typedef enum CfreeEntryKind { diff --git a/src/dbg/session.c b/src/dbg/session.c @@ -140,6 +140,13 @@ park: s->os->event_signal(s->os->user, s->ev_stop); s->os->event_wait(s->os->user, s->ev_resume); s->os->event_reset(s->os->user, s->ev_resume); + + if (s->pending_mode == CFREE_RESUME_ABORT) { + if (s->os->thread_abort) { + s->os->thread_abort(s->os->user); + } + } + /* Apply pending PC override (set by step_resume) before returning. */ if (s->pending_has_pc) { regs->pc = s->pending_pc_override; @@ -154,14 +161,9 @@ park: /* ---- worker thread -------------------------------------------------- */ -static void worker_main(void* arg) { +static void worker_run_entry(void* arg) { CfreeJitSession* s = (CfreeJitSession*)arg; - for (;;) { - s->os->event_wait(s->os->user, s->ev_resume); - s->os->event_reset(s->os->user, s->ev_resume); - if (s->worker_should_exit) return; - if (s->state == DBG_STATE_RUNNING && s->entry) { - typedef int (*EntryIntArgv)(int, char**); + typedef int (*EntryIntArgv)(int, char**); typedef uint64_t (*EntryU64_0)(void); typedef uint64_t (*EntryU64_1)(uint64_t); typedef uint64_t (*EntryU64_2)(uint64_t, uint64_t); @@ -239,6 +241,26 @@ static void worker_main(void* arg) { memset(&s->stop, 0, sizeof(s->stop)); s->stop.kind = CFREE_STOP_EXIT; s->stop.exit_code = ret; +} + +static void worker_main(void* arg) { + CfreeJitSession* s = (CfreeJitSession*)arg; + for (;;) { + s->os->event_wait(s->os->user, s->ev_resume); + s->os->event_reset(s->os->user, s->ev_resume); + if (s->worker_should_exit) return; + if (s->state == DBG_STATE_RUNNING && s->entry) { + int aborted = 0; + if (s->os->call_with_catch) { + aborted = s->os->call_with_catch(s->os->user, worker_run_entry, s); + } else { + worker_run_entry(s); + } + if (aborted) { + memset(&s->stop, 0, sizeof(s->stop)); + s->stop.kind = CFREE_STOP_EXIT; + s->stop.exit_code = -1; + } s->state = DBG_STATE_EXITED; s->entry = NULL; s->os->event_signal(s->os->user, s->ev_stop); diff --git a/src/dbg/step.c b/src/dbg/step.c @@ -191,6 +191,8 @@ static CfreeStatus run_next_line(CfreeJitSession* s) { CfreeStatus dbg_step_resume(CfreeJitSession* s, CfreeResumeMode mode) { switch (mode) { + case CFREE_RESUME_ABORT: + return CFREE_OK; case CFREE_RESUME_CONTINUE: if (dbg_bp_lookup_index(s, s->stop.regs.pc) != 0) { return prepare_step_insn(s);