commit b264b52f4dfe675002249f74855d67fe720d7c29
parent 3bbb10f66899268262d8993ffd1f44a4b864e2df
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Fri, 29 May 2026 14:07:02 -0700
Improve dbg REPL listing and stop messages
Diffstat:
14 files changed, 343 insertions(+), 60 deletions(-)
diff --git a/doc/DBG_TODO.md b/doc/DBG_TODO.md
@@ -91,7 +91,7 @@ experience is solid.
- [ ] better handling for multi-line input and unmatched braces
- [ ] Improve Toy source/debug info:
- [ ] stable synthetic file names for REPL snippets
- - [ ] useful `list` output for synthetic snippets
+ - [x] useful `list` output for synthetic snippets
- [x] local/argument names and values at expected source stops
## Toy Transactional Frontend State
@@ -130,7 +130,7 @@ experience is solid.
- [x] Add completion for commands, symbols, locals, files, and breakpoint ids.
- [ ] Repeat the last stepping command on a blank line.
- [x] Print a compact source context after source-level stops.
-- [ ] Make stop messages distinguish user breakpoints, internal step
+- [x] Make stop messages distinguish user breakpoints, internal step
completions, signals, traps, and program exits cleanly.
- [x] Add `disasm` / `x/i` around the current PC.
- [ ] Add memory-format variants for `x` (bytes, words, strings, pointers).
diff --git a/driver/dbg.c b/driver/dbg.c
@@ -363,6 +363,14 @@ typedef struct Bp {
uint32_t session_id; /* libcfree handle; 0 when disarmed */
} Bp;
+typedef struct DbgSource {
+ char* name;
+ size_t name_size;
+ uint8_t* data;
+ size_t data_size;
+ size_t len;
+} DbgSource;
+
/* ============================================================
* Session-scoped state
* ============================================================ */
@@ -381,6 +389,9 @@ typedef struct DbgState {
CfreeLanguage default_jit_lang;
const char* default_jit_name;
CfreeCompileSession* compile_sessions[CFREE_LANG_COUNT];
+ DbgSource* sources;
+ uint32_t nsources;
+ uint32_t sources_cap;
int prog_argc;
char** prog_argv;
@@ -389,6 +400,7 @@ typedef struct DbgState {
uint32_t bps_cap;
int next_bp_id;
uint64_t expr_counter;
+ uint64_t source_counter;
int has_stop;
CfreeStopInfo last_stop;
@@ -499,6 +511,8 @@ static size_t dbg_parse_uint(const char* s, uint64_t* out) {
return i;
}
+static size_t dbg_u64_dec(char* dst, size_t cap, uint64_t v);
+
/* ============================================================
* Breakpoint table operations
* ============================================================ */
@@ -590,6 +604,22 @@ static void dbg_compile_sessions_release(DbgState* s) {
}
}
+static void dbg_sources_release_all(DbgState* s) {
+ uint32_t i;
+ for (i = 0; i < s->nsources; ++i) {
+ DbgSource* src = &s->sources[i];
+ if (src->name) driver_free(s->env, src->name, src->name_size);
+ if (src->data) driver_free(s->env, src->data, src->data_size);
+ }
+ if (s->sources) {
+ driver_free(s->env, s->sources,
+ (size_t)s->sources_cap * sizeof(*s->sources));
+ s->sources = NULL;
+ }
+ s->nsources = 0;
+ s->sources_cap = 0;
+}
+
/* ============================================================
* LOC parser
* ============================================================
@@ -783,6 +813,27 @@ static void dbg_print_source_listing(DbgState* s, CfreeSlice file,
uint32_t line, uint64_t pc,
int report_errors);
+static CfreeSlice dbg_step_stop_label(CfreeStopReason reason) {
+ switch (reason) {
+ case CFREE_STOP_REASON_STEP_INSN:
+ return CFREE_SLICE_LIT("Single-step complete at ");
+ case CFREE_STOP_REASON_STEP_LINE:
+ return CFREE_SLICE_LIT("Step complete at ");
+ case CFREE_STOP_REASON_NEXT_LINE:
+ return CFREE_SLICE_LIT("Next complete at ");
+ case CFREE_STOP_REASON_STEP_OUT:
+ return CFREE_SLICE_LIT("Finish complete at ");
+ case CFREE_STOP_REASON_UNKNOWN:
+ case CFREE_STOP_REASON_USER_BREAKPOINT:
+ case CFREE_STOP_REASON_SIGNAL:
+ case CFREE_STOP_REASON_TRAP:
+ case CFREE_STOP_REASON_INTERRUPT:
+ case CFREE_STOP_REASON_EXIT:
+ break;
+ }
+ return CFREE_SLICE_LIT("Internal breakpoint hit at ");
+}
+
static void dbg_render_stop(DbgState* s, const CfreeStopInfo* st) {
CfreeSlice file = {0};
uint32_t line = 0;
@@ -809,14 +860,19 @@ static void dbg_render_stop(DbgState* s, const CfreeStopInfo* st) {
if (b)
driver_printf("Breakpoint %d (%.*s) hit at ", b->id,
CFREE_SLICE_ARG(cfree_slice_cstr(b->spec)));
- else
- driver_printf("Breakpoint hit at ");
+ else {
+ CfreeSlice label = dbg_step_stop_label(st->reason);
+ driver_printf("%.*s", CFREE_SLICE_ARG(label));
+ }
dbg_print_pc(s, st->regs.pc);
driver_printf("\n");
break;
}
case CFREE_STOP_SIGNAL:
- driver_printf("Stopped on signal %d at ", st->signal);
+ if (st->reason == CFREE_STOP_REASON_TRAP)
+ driver_printf("Stopped on trap signal %d at ", st->signal);
+ else
+ driver_printf("Stopped on signal %d at ", st->signal);
dbg_print_pc(s, st->regs.pc);
driver_printf("\n");
break;
@@ -1607,6 +1663,103 @@ static int dbg_buf_append(DbgState* s, char** buf, size_t* len, size_t* cap,
return 0;
}
+static DbgSource* dbg_source_find(DbgState* s, CfreeSlice name) {
+ uint32_t i;
+ if (!s || !name.s || !name.len) return NULL;
+ for (i = 0; i < s->nsources; ++i) {
+ DbgSource* src = &s->sources[i];
+ if (src->name && src->name_size == name.len + 1u &&
+ memcmp(src->name, name.s, name.len) == 0) {
+ return src;
+ }
+ }
+ return NULL;
+}
+
+static DbgSource* dbg_source_grow(DbgState* s) {
+ uint32_t nc;
+ size_t old_size, new_size;
+ DbgSource* ns;
+ if (s->nsources < s->sources_cap) return &s->sources[s->nsources];
+
+ nc = s->sources_cap ? s->sources_cap * 2 : 8;
+ old_size = (size_t)s->sources_cap * sizeof(*s->sources);
+ new_size = (size_t)nc * sizeof(*s->sources);
+ ns = (DbgSource*)s->env->heap->realloc(s->env->heap, s->sources, old_size,
+ new_size, _Alignof(DbgSource));
+ if (!ns) return NULL;
+ {
+ char* z = (char*)ns + old_size;
+ size_t n = new_size - old_size;
+ size_t j;
+ for (j = 0; j < n; ++j) z[j] = 0;
+ }
+ s->sources = ns;
+ s->sources_cap = nc;
+ return &s->sources[s->nsources];
+}
+
+static int dbg_source_intern_name(DbgState* s, CfreeSlice name,
+ const char** out) {
+ DbgSource* src;
+ size_t name_size;
+ char* name_copy;
+ if (out) *out = NULL;
+ if (!s || !name.s || !name.len) return 1;
+
+ src = dbg_source_find(s, name);
+ if (src) {
+ if (out) *out = src->name;
+ return 0;
+ }
+
+ name_copy = dbg_dup(s->env, name.s, name.len, &name_size);
+ if (!name_copy) return 1;
+ src = dbg_source_grow(s);
+ if (!src) {
+ driver_free(s->env, name_copy, name_size);
+ return 1;
+ }
+ src->name = name_copy;
+ src->name_size = name_size;
+ s->nsources++;
+ if (out) *out = src->name;
+ return 0;
+}
+
+static int dbg_source_cache_put(DbgState* s, CfreeSlice name, const char* data,
+ size_t len) {
+ DbgSource* src;
+ uint8_t* data_copy;
+ size_t data_size = len ? len : 1u;
+ if (!s || !name.s || !name.len || !data) return 1;
+
+ data_copy = (uint8_t*)driver_alloc(s->env, data_size);
+ if (!data_copy) return 1;
+ if (len) driver_memcpy(data_copy, data, len);
+
+ src = dbg_source_find(s, name);
+ if (!src) {
+ if (dbg_source_intern_name(s, name, NULL) != 0) {
+ driver_free(s->env, data_copy, data_size);
+ return 1;
+ }
+ src = dbg_source_find(s, name);
+ if (!src) {
+ driver_free(s->env, data_copy, data_size);
+ return 1;
+ }
+ }
+ if (src->data) {
+ driver_free(s->env, src->data, src->data_size);
+ }
+
+ src->data = data_copy;
+ src->data_size = data_size;
+ src->len = len;
+ return 0;
+}
+
static int dbg_brace_delta(const char* p) {
int d = 0;
while (*p) {
@@ -1664,6 +1817,31 @@ static const char* dbg_jit_default_name(CfreeLanguage lang) {
return "<dbg-jit.c>";
}
+static int dbg_jit_uses_default_name(CfreeLanguage lang,
+ const char* input_name) {
+ return !input_name || driver_streq(input_name, dbg_jit_default_name(lang));
+}
+
+static int dbg_make_repl_source_name(CfreeLanguage lang, uint64_t id,
+ char* out, size_t cap) {
+ const char* prefix = "<dbg-jit-";
+ const char* suffix = dbg_jit_language_suffix(lang);
+ char num[32];
+ size_t prefix_len = driver_strlen(prefix);
+ size_t suffix_len = driver_strlen(suffix);
+ size_t num_len = dbg_u64_dec(num, sizeof(num), id);
+ size_t need;
+ if (!num_len) return 1;
+ need = prefix_len + num_len + suffix_len + 2u;
+ if (need > cap) return 1;
+ driver_memcpy(out, prefix, prefix_len);
+ driver_memcpy(out + prefix_len, num, num_len);
+ driver_memcpy(out + prefix_len + num_len, suffix, suffix_len);
+ out[prefix_len + num_len + suffix_len] = '>';
+ out[prefix_len + num_len + suffix_len + 1u] = '\0';
+ return 0;
+}
+
static CfreeLanguage dbg_jit_language_for_tag(DbgState* s, const char* tag,
const char** name_out) {
if (!tag || !*tag) {
@@ -1725,11 +1903,29 @@ static int dbg_jit_compile_append_ex(DbgState* s, CfreeLanguage lang,
CfreeCompileSession* session = NULL;
CfreeObjBuilder* ob = NULL;
CfreeStatus st;
+ char generated_name[96];
+ const char* effective_name =
+ input_name ? input_name : dbg_jit_default_name(lang);
+ uint64_t source_id = s->source_counter + 1u;
+ int generated_source_name = 0;
s->jit_counter++;
+ if (input_kind == CFREE_FRONTEND_INPUT_REPL_TOPLEVEL &&
+ dbg_jit_uses_default_name(lang, input_name)) {
+ if (dbg_make_repl_source_name(lang, source_id, generated_name,
+ sizeof(generated_name)) != 0) {
+ driver_errf(DBG_TOOL, "repl source name overflow");
+ return 1;
+ }
+ if (dbg_source_intern_name(s, cfree_slice_cstr(generated_name),
+ &effective_name) != 0) {
+ driver_errf(DBG_TOOL, "out of memory naming repl source");
+ return 1;
+ }
+ generated_source_name = 1;
+ }
memset(&sin, 0, sizeof(sin));
- sin.name =
- cfree_slice_cstr(input_name ? input_name : dbg_jit_default_name(lang));
+ sin.name = cfree_slice_cstr(effective_name);
sin.bytes.data = (const uint8_t*)src;
sin.bytes.len = len;
sin.lang = lang;
@@ -1759,6 +1955,12 @@ static int dbg_jit_compile_append_ex(DbgState* s, CfreeLanguage lang,
driver_errf(DBG_TOOL, "jit append failed");
return 1;
}
+ if (generated_source_name) s->source_counter = source_id;
+ if (lang == CFREE_LANG_TOY &&
+ input_kind == CFREE_FRONTEND_INPUT_REPL_TOPLEVEL &&
+ dbg_source_cache_put(s, sin.name, src, len) != 0) {
+ driver_errf(DBG_TOOL, "out of memory caching source for list");
+ }
dbg_refresh_dwarf(s);
return 0;
}
@@ -1792,6 +1994,12 @@ static int dbg_parse_jit_lang_arg(DbgState* s, const char* rest,
driver_memcpy(tag_buf, tag, tag_n);
tag_buf[tag_n] = '\0';
lang = dbg_jit_language_for_tag(s, tag_buf, &input_name);
+ if (input_name == tag_buf &&
+ dbg_source_intern_name(s, cfree_slice_cstr(input_name), &input_name) !=
+ 0) {
+ driver_errf(DBG_TOOL, "out of memory naming repl source");
+ return 1;
+ }
while (*p && dbg_isspace((unsigned char)*p)) ++p;
} else {
lang = dbg_jit_language_for_tag(s, NULL, &input_name);
@@ -2186,10 +2394,51 @@ static void dbg_cmd_disasm(DbgState* s, uint64_t addr, size_t count) {
* ============================================================
* Print a context window of source lines centered on `file:line`.
*
- * Reads `file` from disk via env.file_io. When the file isn't on disk
- * (e.g. the DWARF came from a `.o` / `.a` whose source isn't available
- * here), command-mode reports the DWARF line number alone and source stops
- * silently keep the already-rendered location line. */
+ * Reads REPL snippets from the debugger's in-memory source cache and normal
+ * files from disk via env.file_io. When neither is available (e.g. the DWARF
+ * came from a `.o` / `.a` whose source isn't available here), command-mode
+ * reports the DWARF line number alone and source stops silently keep the
+ * already-rendered location line. */
+
+static void dbg_print_source_bytes(const uint8_t* data, size_t size,
+ uint32_t line, int report_errors) {
+ static const uint8_t empty[1] = {0};
+ uint32_t target = line;
+ uint32_t lo = target > DBG_LIST_CTX ? target - DBG_LIST_CTX : 1;
+ uint32_t hi = target + DBG_LIST_CTX;
+ uint32_t cur = 1;
+ const uint8_t* p;
+ const uint8_t* end;
+ const uint8_t* line_start;
+
+ if (!data && size != 0) return;
+ if (!data) data = empty;
+ p = data;
+ end = data + size;
+ line_start = p;
+
+ while (p <= end) {
+ int eol = (p == end) || (*p == '\n');
+ if (eol) {
+ if (p == end && p == line_start && end > data && end[-1] == '\n') break;
+ if (cur >= lo && cur <= hi) {
+ size_t len = (size_t)(p - line_start);
+ driver_printf(
+ "%6u%.*s %.*s\n", cur,
+ CFREE_SLICE_ARG(cfree_slice_cstr(cur == target ? " >" : " ")),
+ (int)len, (const char*)line_start);
+ }
+ ++cur;
+ if (p == end) break;
+ line_start = p + 1;
+ }
+ ++p;
+ }
+ if (report_errors && cur <= target) {
+ driver_errf(DBG_TOOL, "file has only %u lines; %u requested", cur - 1u,
+ target);
+ }
+}
static void dbg_print_source_listing(DbgState* s, CfreeSlice file,
uint32_t line, uint64_t pc,
@@ -2197,8 +2446,22 @@ static void dbg_print_source_listing(DbgState* s, CfreeSlice file,
char path[1024];
CfreeFileData fd;
const CfreeFileIO* io;
+ DbgSource* cached;
- if (!file.s || file.len == 0 || file.len >= sizeof(path)) {
+ if (!file.s || file.len == 0) {
+ if (report_errors) {
+ driver_errf(DBG_TOOL, "bad file in '%.*s'", CFREE_SLICE_ARG(file));
+ }
+ return;
+ }
+
+ cached = dbg_source_find(s, file);
+ if (cached && cached->data) {
+ dbg_print_source_bytes(cached->data, cached->len, line, report_errors);
+ return;
+ }
+
+ if (file.len >= sizeof(path)) {
if (report_errors) {
driver_errf(DBG_TOOL, "bad file in '%.*s'", CFREE_SLICE_ARG(file));
}
@@ -2219,39 +2482,7 @@ static void dbg_print_source_listing(DbgState* s, CfreeSlice file,
return;
}
- /* Walk the buffer, counting newlines. Print lines in
- * [target-DBG_LIST_CTX, target+DBG_LIST_CTX]. */
- {
- uint32_t target = line;
- uint32_t lo = target > DBG_LIST_CTX ? target - DBG_LIST_CTX : 1;
- uint32_t hi = target + DBG_LIST_CTX;
- uint32_t cur = 1;
- const uint8_t* p = fd.data;
- const uint8_t* end = fd.data + fd.size;
- const uint8_t* line_start = p;
- while (p <= end) {
- int eol = (p == end) || (*p == '\n');
- if (eol) {
- if (p == end && p == line_start && end > fd.data && end[-1] == '\n')
- break;
- if (cur >= lo && cur <= hi) {
- size_t len = (size_t)(p - line_start);
- driver_printf(
- "%6u%.*s %.*s\n", cur,
- CFREE_SLICE_ARG(cfree_slice_cstr(cur == target ? " >" : " ")),
- (int)len, (const char*)line_start);
- }
- ++cur;
- if (p == end) break;
- line_start = p + 1;
- }
- ++p;
- }
- if (report_errors && cur <= target) {
- driver_errf(DBG_TOOL, "file has only %u lines; %u requested", cur - 1u,
- target);
- }
- }
+ dbg_print_source_bytes(fd.data, fd.size, line, report_errors);
if (io->release) io->release(io->user, &fd);
}
@@ -3230,6 +3461,7 @@ int driver_dbg(int argc, char** argv) {
driver_line_history_fini(&env, &st.line_history);
dbg_bps_release_all(&st);
dbg_compile_sessions_release(&st);
+ dbg_sources_release_all(&st);
if (st.dwarf) cfree_dwarf_free(st.dwarf);
if (st.session) cfree_jit_session_free(st.session);
cfree_jit_free(jit);
diff --git a/driver/env/posix_dbg.c b/driver/env/posix_dbg.c
@@ -294,6 +294,7 @@ CfreeDbgOs g_dbg_os_posix = {
.signals_install = dbg_signals_install,
.signals_uninstall = dbg_signals_uninstall,
.interrupt_signo = DBG_INTERRUPT_SIGNO,
+ .trap_signo = SIGTRAP,
.code_write_begin = os_dbg_code_write_begin,
.code_write_end = os_dbg_code_write_end,
.flush_icache = os_dbg_flush_icache,
diff --git a/driver/env/windows.c b/driver/env/windows.c
@@ -1530,6 +1530,7 @@ static CfreeDbgOs g_dbg_os_win = {
.signals_install = dbg_signals_install_win,
.signals_uninstall = dbg_signals_uninstall_win,
.interrupt_signo = DBG_WIN_INTERRUPT_SIGNO,
+ .trap_signo = 5,
.code_write_begin = dbg_code_write_begin_win,
.code_write_end = dbg_code_write_end_win,
.flush_icache = dbg_flush_icache_win,
diff --git a/include/cfree/dbg.h b/include/cfree/dbg.h
@@ -32,6 +32,7 @@ typedef struct CfreeDbgOs {
void* session);
void (*signals_uninstall)(void* user);
int interrupt_signo;
+ int trap_signo;
CfreeStatus (*code_write_begin)(void* user, void* runtime_addr, size_t n,
void** write_out);
@@ -57,8 +58,22 @@ typedef enum CfreeStopKind {
CFREE_STOP_INTERRUPT,
} CfreeStopKind;
+typedef enum CfreeStopReason {
+ CFREE_STOP_REASON_UNKNOWN = 0,
+ CFREE_STOP_REASON_USER_BREAKPOINT,
+ CFREE_STOP_REASON_STEP_INSN,
+ CFREE_STOP_REASON_STEP_LINE,
+ CFREE_STOP_REASON_NEXT_LINE,
+ CFREE_STOP_REASON_STEP_OUT,
+ CFREE_STOP_REASON_SIGNAL,
+ CFREE_STOP_REASON_TRAP,
+ CFREE_STOP_REASON_INTERRUPT,
+ CFREE_STOP_REASON_EXIT,
+} CfreeStopReason;
+
typedef struct CfreeStopInfo {
CfreeStopKind kind;
+ CfreeStopReason reason;
int signal;
int exit_code;
uint32_t bp_id;
diff --git a/src/dbg/session.c b/src/dbg/session.c
@@ -13,16 +13,21 @@
/* ---- fault classification ------------------------------------------- */
-static int signo_is_trap(int signo) {
- /* Trap = software breakpoint. The host typically maps
- * this to SIGTRAP; we don't include the platform header to assert the
- * value but debugger trap faults always carry the trap signo for the
- * host that installed the handler. The POSIX impl in driver/env.c
- * passes the host signo straight through. We treat any signo whose
- * fault PC is patched as a trap, so the actual signo here is mostly
- * advisory. */
- (void)signo;
- return 1;
+static CfreeStopReason stop_reason_for_step(CfreeResumeMode mode) {
+ switch (mode) {
+ case CFREE_RESUME_STEP_INSN:
+ return CFREE_STOP_REASON_STEP_INSN;
+ case CFREE_RESUME_STEP_LINE:
+ return CFREE_STOP_REASON_STEP_LINE;
+ case CFREE_RESUME_NEXT_LINE:
+ return CFREE_STOP_REASON_NEXT_LINE;
+ case CFREE_RESUME_STEP_OUT:
+ return CFREE_STOP_REASON_STEP_OUT;
+ case CFREE_RESUME_CONTINUE:
+ case CFREE_RESUME_ABORT:
+ break;
+ }
+ return CFREE_STOP_REASON_UNKNOWN;
}
static CfreeStatus on_fault(void* session_v, int signo,
@@ -39,10 +44,12 @@ static CfreeStatus on_fault(void* session_v, int signo,
s->stop.signal = signo;
s->stop.exit_code = 0;
s->stop.bp_id = 0;
+ s->stop.reason = CFREE_STOP_REASON_UNKNOWN;
/* Interrupt — host requested via thread_interrupt. */
if (s->os->interrupt_signo != 0 && signo == s->os->interrupt_signo) {
s->stop.kind = CFREE_STOP_INTERRUPT;
+ s->stop.reason = CFREE_STOP_REASON_INTERRUPT;
goto park;
}
@@ -72,6 +79,7 @@ static CfreeStatus on_fault(void* session_v, int signo,
}
s->stop.kind = CFREE_STOP_BREAKPOINT;
s->stop.bp_id = 0;
+ s->stop.reason = stop_reason_for_step(s->pending_mode);
goto park;
}
@@ -86,6 +94,7 @@ static CfreeStatus on_fault(void* session_v, int signo,
}
s->stop.kind = CFREE_STOP_BREAKPOINT;
s->stop.bp_id = 0;
+ s->stop.reason = stop_reason_for_step(s->pending_mode);
goto park;
}
@@ -103,6 +112,7 @@ static CfreeStatus on_fault(void* session_v, int signo,
s->pending_step_pending = 0;
s->stop.kind = CFREE_STOP_BREAKPOINT;
s->stop.bp_id = bp->user_id;
+ s->stop.reason = CFREE_STOP_REASON_USER_BREAKPOINT;
goto park;
}
/* Apply any PC override the prepare-step path set. */
@@ -119,6 +129,7 @@ static CfreeStatus on_fault(void* session_v, int signo,
s->pending_step_pending = 0;
s->stop.kind = CFREE_STOP_BREAKPOINT;
s->stop.bp_id = bp->user_id;
+ s->stop.reason = CFREE_STOP_REASON_USER_BREAKPOINT;
goto park;
}
if (s->pending_has_pc) {
@@ -129,6 +140,7 @@ static CfreeStatus on_fault(void* session_v, int signo,
}
s->stop.kind = CFREE_STOP_BREAKPOINT;
s->stop.bp_id = bp->user_id;
+ s->stop.reason = CFREE_STOP_REASON_USER_BREAKPOINT;
if (bp->max_hits != 0 && bp->hit_count >= bp->max_hits + bp->skip_count) {
/* Auto-clear after surfacing. Defer to post-park so the bp_id
* is still valid when the driver inspects. */
@@ -139,8 +151,10 @@ static CfreeStatus on_fault(void* session_v, int signo,
/* Not a patched address — pass through as SIGNAL (covers SEGV, BUS,
* ILL, FPE, and any SIGTRAP from a program-emitted trap). */
- (void)signo_is_trap;
s->stop.kind = CFREE_STOP_SIGNAL;
+ s->stop.reason = (s->os->trap_signo != 0 && signo == s->os->trap_signo)
+ ? CFREE_STOP_REASON_TRAP
+ : CFREE_STOP_REASON_SIGNAL;
park:
s->state = DBG_STATE_STOPPED;
@@ -241,6 +255,7 @@ static void worker_run_entry(void* arg) {
}
memset(&s->stop, 0, sizeof(s->stop));
s->stop.kind = CFREE_STOP_EXIT;
+ s->stop.reason = CFREE_STOP_REASON_EXIT;
s->stop.exit_code = ret;
}
@@ -260,6 +275,7 @@ static void worker_main(void* arg) {
if (aborted) {
memset(&s->stop, 0, sizeof(s->stop));
s->stop.kind = CFREE_STOP_EXIT;
+ s->stop.reason = CFREE_STOP_REASON_EXIT;
s->stop.exit_code = -1;
}
s->state = DBG_STATE_EXITED;
diff --git a/test/dbg/cases/toy-file-line-step/expected b/test/dbg/cases/toy-file-line-step/expected
@@ -6,13 +6,13 @@ Breakpoint 1 (@CASE@/main.toy:2) hit at 0xADDR <main+0x60> at @CASE@/main.toy:2:
3 let y: i64 = x + 32;
4 return y as i32;
5 }
-Breakpoint hit at 0xADDR <main+0x64> at @CASE@/main.toy:2:16
+Single-step complete at 0xADDR <main+0x64> at @CASE@/main.toy:2:16
1 fn main(): i32 {
2 > let x: i64 = 10;
3 let y: i64 = x + 32;
4 return y as i32;
5 }
-Breakpoint hit at 0xADDR <main+0x68> at @CASE@/main.toy:3:20
+Next complete at 0xADDR <main+0x68> at @CASE@/main.toy:3:20
1 fn main(): i32 {
2 let x: i64 = 10;
3 > let y: i64 = x + 32;
diff --git a/test/dbg/cases/toy-repl-source-list/args b/test/dbg/cases/toy-repl-source-list/args
@@ -0,0 +1,2 @@
+--language
+toy
diff --git a/test/dbg/cases/toy-repl-source-list/expected b/test/dbg/cases/toy-repl-source-list/expected
@@ -0,0 +1,3 @@
+cfree dbg — 'h' for help, 'q' to quit
+ 1 > fn first(): i64 { return 1; }
+ 1 > fn second(): i64 { return 2; }
diff --git a/test/dbg/cases/toy-repl-source-list/stdin b/test/dbg/cases/toy-repl-source-list/stdin
@@ -0,0 +1,5 @@
+jit { fn first(): i64 { return 1; } }
+jit { fn second(): i64 { return 2; } }
+list <dbg-jit-1.toy>:1
+list <dbg-jit-2.toy>:1
+q
diff --git a/test/dbg/cases/toy-step-finish/expected b/test/dbg/cases/toy-step-finish/expected
@@ -9,7 +9,7 @@ Breakpoint 1 (@CASE@/main.toy:8) hit at 0xADDR <main+0x68> at @CASE@/main.toy:8:
8 > let out: i64 = helper(base);
9 return out as i32;
10 }
-Breakpoint hit at 0xADDR <helper+0x64> at @CASE@/main.toy:2:20
+Step complete at 0xADDR <helper+0x64> at @CASE@/main.toy:2:20
1 fn helper(v: i64): i64 {
2 > let y: i64 = v + 1;
3 return y;
@@ -17,7 +17,7 @@ Breakpoint hit at 0xADDR <helper+0x64> at @CASE@/main.toy:2:20
5
6 fn main(): i32 {
7 let base: i64 = 41;
-Breakpoint hit at 0xADDR <main+0x78> at @CASE@/main.toy:8:25
+Finish complete at 0xADDR <main+0x78> at @CASE@/main.toy:8:25
3 return y;
4 }
5
diff --git a/test/dbg/cases/toy-trap-stop/args b/test/dbg/cases/toy-trap-stop/args
@@ -0,0 +1,2 @@
+--language
+toy
diff --git a/test/dbg/cases/toy-trap-stop/expected b/test/dbg/cases/toy-trap-stop/expected
@@ -0,0 +1,3 @@
+cfree dbg — 'h' for help, 'q' to quit
+Stopped on trap signal 5 at 0xADDR <main+0x60> at <dbg-jit-1.toy>:1:19
+ 1 > fn main(): i32 { @trap(); return 0 as i32; }
diff --git a/test/dbg/cases/toy-trap-stop/stdin b/test/dbg/cases/toy-trap-stop/stdin
@@ -0,0 +1,3 @@
+jit { fn main(): i32 { @trap(); return 0 as i32; } }
+run
+q