dbg.c (120329B)
1 #include <kit/arch.h> 2 #include <kit/compile.h> 3 #include <kit/core.h> 4 #include <kit/dbg.h> 5 #include <kit/disasm.h> 6 #include <kit/dwarf.h> 7 #include <kit/jit.h> 8 #include <kit/link.h> 9 #include <kit/object.h> 10 #include <stddef.h> 11 #include <stdint.h> 12 #include <string.h> 13 14 #include "backtrace.h" 15 #include "cflags.h" 16 #include "driver.h" 17 #include "inputs.h" 18 19 /* `kit dbg` — interactive JIT debugger. 20 * 21 * Mirrors `kit run` for compile flags and argv shape, but instead of 22 * calling the entry directly drops into a REPL that drives a 23 * KitJitSession. The session (in libkit) owns the worker thread, 24 * signal handlers, breakpoint patcher, and per-arch single-step / 25 * displaced-step trampoline. This driver TU only: 26 * 27 * - parses argv and turns the source list into a JIT image, 28 * - opens DWARF and a JIT-image view, 29 * - manages a driver-local breakpoint table (id, spec text, enabled 30 * flag) keyed off session-side handles, 31 * - parses LOC strings (file:line, sym[+off], 0xADDR) into addresses 32 * via kit_dwarf_line_to_addr / kit_jit_lookup, 33 * - reads commands from stdin and dispatches, 34 * - renders KitStopInfo into source-level stop messages and the 35 * backtrace via kit_dwarf_unwind_step, 36 * - decodes `p name` via kit_dwarf_var_at + kit_dwarf_loc_read. 37 * 38 * Forwarding Ctrl-C: while a session call is in flight the driver 39 * installs a SIGINT handler that calls kit_jit_session_interrupt; on 40 * return it restores SIG_DFL so Ctrl-C at the REPL prompt terminates 41 * the program. */ 42 43 #define DBG_TOOL "dbg" 44 #define LINE_CAP 1024 45 #define WORD_CAP 256 46 #define HEX_CAP 8 /* upper bound on per-arch trap-byte save */ 47 48 /* ============================================================ 49 * argv parsing (mirrors run.c) 50 * ============================================================ */ 51 52 typedef enum { DBG_ENTRY_FILE, DBG_ENTRY_CMD } DbgEntryKind; 53 typedef struct { 54 DbgEntryKind kind; 55 const char* value; /* argv pointer — no per-entry allocation */ 56 } DbgScriptEntry; 57 58 typedef struct DbgOpts { 59 DriverEnv* env; 60 size_t argv_bound; 61 62 int opt_level; 63 int debug_info; 64 const char* entry; 65 KitLanguage default_lang; 66 int has_default_lang; 67 68 DriverCflags cf; 69 DriverInputs inputs; 70 71 char** prog_argv; 72 uint32_t prog_argc; 73 74 DbgScriptEntry* script_entries; 75 uint32_t nscript_entries; 76 uint32_t script_entries_cap; 77 int batch_mode; 78 } DbgOpts; 79 80 void driver_help_dbg(void) { 81 driver_printf( 82 "%.*s", 83 KIT_SLICE_ARG(KIT_SLICE_LIT( 84 "kit dbg — interactive JIT debugger\n" 85 "\n" 86 "USAGE\n" 87 " kit dbg [options] [input.{c,toy,s} ...] [-- prog-arg ...]\n" 88 "\n" 89 "DESCRIPTION\n" 90 " Mirrors `kit run` for compile flags and argv shape, but " 91 "instead\n" 92 " of calling the entry directly drops into a REPL that drives the\n" 93 " JIT session: breakpoints, source-line stepping (into / over),\n" 94 " instruction stepping,\n" 95 " finish, backtrace, registers, locals/args, variable read/write,\n" 96 " and raw memory examine. -g is forced on so source lines and\n" 97 " variable locations are available at runtime.\n" 98 "\n" 99 " Anything after `--` is passed to the JITed program as argv.\n" 100 " With no input files, dbg starts an empty JIT session; append " 101 "code\n" 102 " with `jit` or evaluate expressions directly from the REPL.\n" 103 "\n" 104 "COMPILE OPTIONS\n" 105 " -O0 -O1 -O2 Optimization level (default -O0)\n" 106 " -g Emit DWARF (forced on)\n" 107 " -e SYMBOL Entry symbol (default `main`)\n" 108 " -x LANG Default REPL language: c, toy, asm, wasm/wat\n" 109 " --language LANG Same as -x\n" 110 " -I DIR Add quoted-include search path\n" 111 " -isystem DIR Add system-include search path\n" 112 " -D NAME[=BODY] Define a macro\n" 113 " -U NAME Undefine a builtin/predefined macro\n" 114 "\n" 115 "REPL COMMANDS (also shown by `h` at the prompt)\n" 116 " h, help show REPL help\n" 117 " q, quit exit (Ctrl-D also works)\n" 118 " r, run start fresh execution at entry\n" 119 " c, cont continue after a stop\n" 120 " s, step step to next source line (into " 121 "calls)\n" 122 " si, stepi single-step one instruction\n" 123 " n, next step to next source line (over " 124 "calls)\n" 125 " finish run until current frame returns\n" 126 " jit [LANG|NAME] { ... } compile and append a language " 127 "snippet\n" 128 " { ... } same as jit { ... }\n" 129 " edit [LANG|NAME] edit and append a language snippet\n" 130 " expr EXPR | expr { ... } compile and call an expression " 131 "thunk\n" 132 " EXPR same as expr EXPR\n" 133 " LANG defaults to the selected " 134 "language\n" 135 " jump ADDR set PC to ADDR (no resume)\n" 136 " bt, backtrace print stack trace with arguments\n" 137 " b LOC set breakpoint at LOC:\n" 138 " 0xADDR | sym[+off] | file.c:line\n" 139 " ignore N COUNT skip the next COUNT hits of bp N\n" 140 " d N, delete N delete breakpoint N\n" 141 " enable N | disable N toggle breakpoint N\n" 142 " p NAME print variable / global\n" 143 " set NAME VALUE write VALUE into NAME\n" 144 " x ADDR [count] examine memory (default 16 bytes)\n" 145 " disasm [ADDR] [count], x/i disassemble at PC or ADDR\n" 146 " list FILE:LINE | l FILE:LINE source listing around FILE:LINE\n" 147 " info b list breakpoints\n" 148 " info reg, info registers dump registers\n" 149 " info locals | info args list locals / args at current PC\n" 150 " info functions [PATTERN] list JIT functions matching PATTERN\n" 151 " info variables [PATTERN] list JIT globals matching PATTERN\n" 152 "\n" 153 "BATCH / SCRIPTING\n" 154 " --script FILE execute debugger commands from FILE (repeatable)\n" 155 " --command CMD execute CMD as if typed at the REPL (repeatable)\n" 156 " -c CMD same as --command\n" 157 " --batch non-interactive: suppress banner, exit after\n" 158 " --script / --command sources drain; exit 1 on\n" 159 " any command error\n" 160 " Note: multi-line jit{} / expr{} blocks in --script files must fit\n" 161 " on a single line (continuation reads go to stdin, not the file).\n" 162 "\n" 163 "SIGNALS\n" 164 " Ctrl-C is forwarded into the running session as an interrupt; at\n" 165 " the REPL prompt it terminates the program normally.\n" 166 "\n" 167 "GETTING HELP\n" 168 " -h, --help Show this help and exit (this is " 169 "the\n" 170 " command-line help; once the REPL is\n" 171 " running, type `h` for REPL " 172 "commands)\n" 173 "\n" 174 "EXIT CODES\n" 175 " 0 clean exit 1 compile/link/command error 2 " 176 "bad " 177 "usage\n"))); 178 } 179 180 static int dbg_alloc_arrays(DbgOpts* o, int argc) { 181 size_t bound = (size_t)argc; 182 o->argv_bound = bound; 183 o->prog_argv = driver_alloc_zeroed(o->env, bound * sizeof(*o->prog_argv)); 184 if (!o->prog_argv) { 185 driver_errf(DBG_TOOL, "out of memory"); 186 return 1; 187 } 188 if (driver_inputs_init(&o->inputs, o->env, DBG_TOOL, argc) != 0) return 1; 189 if (driver_cflags_init(&o->cf, o->env, argc) != 0) { 190 driver_errf(DBG_TOOL, "out of memory"); 191 return 1; 192 } 193 return 0; 194 } 195 196 static int dbg_parse_language_name(const char* name, KitLanguage* out) { 197 /* Resolve off the compile-time default frontend set (no compiler exists at 198 * arg-parse time). Value-equivalent to the former explicit map: 199 * c->C, toy->TOY, asm/s->ASM, wasm/wat->WASM. */ 200 KitLanguage lang; 201 if (!name || !*name || !out) return 0; 202 lang = kit_language_for_name(NULL, name); 203 if (lang == KIT_LANG_UNKNOWN) return 0; 204 *out = lang; 205 return 1; 206 } 207 208 static int dbg_set_default_language(DbgOpts* o, const char* name) { 209 KitLanguage lang = KIT_LANG_COUNT; 210 if (!dbg_parse_language_name(name, &lang)) { 211 driver_errf(DBG_TOOL, "unsupported language: %.*s", 212 KIT_SLICE_ARG(kit_slice_cstr(name))); 213 return 1; 214 } 215 o->default_lang = lang; 216 o->has_default_lang = 1; 217 return 0; 218 } 219 220 static int dbg_script_entry_push(DbgOpts* o, DbgEntryKind kind, 221 const char* value) { 222 if (o->nscript_entries >= o->script_entries_cap) { 223 uint32_t nc = o->script_entries_cap ? o->script_entries_cap * 2 : 4; 224 size_t old_sz = (size_t)o->script_entries_cap * sizeof(DbgScriptEntry); 225 size_t new_sz = (size_t)nc * sizeof(DbgScriptEntry); 226 DbgScriptEntry* nb = o->env->heap->realloc(o->env->heap, 227 o->script_entries, 228 old_sz, new_sz, 229 _Alignof(DbgScriptEntry)); 230 if (!nb) { driver_errf(DBG_TOOL, "out of memory"); return 1; } 231 o->script_entries = nb; 232 o->script_entries_cap = nc; 233 } 234 o->script_entries[o->nscript_entries].kind = kind; 235 o->script_entries[o->nscript_entries].value = value; 236 o->nscript_entries++; 237 return 0; 238 } 239 240 static int dbg_parse(int argc, char** argv, DbgOpts* o) { 241 int i; 242 int after_dash_dash = 0; 243 if (dbg_alloc_arrays(o, argc) != 0) return 1; 244 245 for (i = 1; i < argc; ++i) { 246 const char* a = argv[i]; 247 248 if (after_dash_dash) { 249 o->prog_argv[o->prog_argc++] = argv[i]; 250 continue; 251 } 252 if (driver_streq(a, "--")) { 253 after_dash_dash = 1; 254 continue; 255 } 256 257 { 258 int r = 259 driver_cflags_try_consume(&o->cf, o->env, DBG_TOOL, argc, argv, &i); 260 if (r < 0) return 1; 261 if (r > 0) continue; 262 } 263 264 if (driver_streq(a, "-g")) { 265 o->debug_info = 1; 266 continue; 267 } 268 if (driver_streq(a, "-O0")) { 269 o->opt_level = 0; 270 continue; 271 } 272 if (driver_streq(a, "-O1")) { 273 o->opt_level = 1; 274 continue; 275 } 276 if (driver_streq(a, "-O2")) { 277 o->opt_level = 2; 278 continue; 279 } 280 281 if (driver_streq(a, "-e")) { 282 if (++i >= argc) { 283 driver_errf(DBG_TOOL, "-e requires an argument"); 284 return 1; 285 } 286 o->entry = argv[i]; 287 continue; 288 } 289 290 if (driver_streq(a, "-x") || driver_streq(a, "--language") || 291 driver_streq(a, "--lang")) { 292 if (++i >= argc) { 293 driver_errf(DBG_TOOL, "%.*s requires an argument", 294 KIT_SLICE_ARG(kit_slice_cstr(a))); 295 return 1; 296 } 297 if (dbg_set_default_language(o, argv[i]) != 0) return 1; 298 continue; 299 } 300 if (driver_strneq(a, "--language=", 11)) { 301 if (dbg_set_default_language(o, a + 11) != 0) return 1; 302 continue; 303 } 304 if (driver_strneq(a, "--lang=", 7)) { 305 if (dbg_set_default_language(o, a + 7) != 0) return 1; 306 continue; 307 } 308 309 if (driver_streq(a, "--script")) { 310 if (++i >= argc) { 311 driver_errf(DBG_TOOL, "--script requires a FILE argument"); 312 return 1; 313 } 314 if (dbg_script_entry_push(o, DBG_ENTRY_FILE, argv[i]) != 0) return 1; 315 continue; 316 } 317 if (driver_streq(a, "--command") || driver_streq(a, "-c")) { 318 if (++i >= argc) { 319 driver_errf(DBG_TOOL, "%.*s requires a CMD argument", 320 KIT_SLICE_ARG(kit_slice_cstr(a))); 321 return 1; 322 } 323 if (dbg_script_entry_push(o, DBG_ENTRY_CMD, argv[i]) != 0) return 1; 324 continue; 325 } 326 if (driver_streq(a, "--batch")) { 327 o->batch_mode = 1; 328 continue; 329 } 330 331 if (a[0] == '-' && a[1] != '\0') { 332 driver_errf(DBG_TOOL, "unknown flag: %.*s", 333 KIT_SLICE_ARG(kit_slice_cstr(a))); 334 return 1; 335 } 336 337 { 338 int r = driver_inputs_classify(&o->inputs, a); 339 if (r < 0) return 1; 340 if (r == 0) { 341 driver_errf(DBG_TOOL, "input does not have a recognized suffix: %.*s", 342 KIT_SLICE_ARG(kit_slice_cstr(a))); 343 return 1; 344 } 345 } 346 } 347 348 if (!o->entry) o->entry = "main"; 349 if (!o->debug_info) { 350 /* Without -g there are no source lines or variable locations to 351 * read at runtime; force it on so `b file:line` and `p name` 352 * have something to look at. The user can always re-run without 353 * if they want to inspect optimized code at the asm level. */ 354 o->debug_info = 1; 355 } 356 return 0; 357 } 358 359 static void dbg_options_release(DbgOpts* o) { 360 size_t bound = o->argv_bound; 361 driver_inputs_release(&o->inputs); 362 driver_cflags_fini(&o->cf, o->env); 363 driver_free(o->env, o->prog_argv, bound * sizeof(*o->prog_argv)); 364 if (o->script_entries) 365 driver_free(o->env, o->script_entries, 366 (size_t)o->script_entries_cap * sizeof(DbgScriptEntry)); 367 } 368 369 /* Compile every C source through a compiler owned by the caller and JIT-link 370 * the result. Compiler ownership stays with the caller so DWARF lookups 371 * during the REPL session can run against the live compiler. */ 372 static int dbg_compile_and_jit(DbgOpts* o, KitCompiler* compiler, 373 const KitJitHost* host, KitJit** out_jit) { 374 KitCCompileOptions copts; 375 const char* link_entry = driver_inputs_count(&o->inputs) ? o->entry : NULL; 376 { 377 KitCCompileOptions z = {0}; 378 copts = z; 379 } 380 KitPreprocessOptions pp; 381 copts.code.opt_level = o->opt_level; 382 copts.code.debug_info = o->debug_info; 383 driver_cflags_fill_pp(&o->cf, &pp); 384 return driver_inputs_compile_and_jit(&o->inputs, compiler, host, &copts, &pp, 385 link_entry, driver_dlsym_resolver, NULL, 386 out_jit); 387 } 388 389 static void dbg_fill_compile_options(DbgOpts* o, KitCCompileOptions* copts, 390 KitPreprocessOptions* pp) { 391 { 392 KitCCompileOptions z = {0}; 393 *copts = z; 394 } 395 copts->code.opt_level = o->opt_level; 396 copts->code.debug_info = o->debug_info; 397 driver_cflags_fill_pp(&o->cf, pp); 398 } 399 400 /* ============================================================ 401 * Breakpoint table (driver-side) 402 * ============================================================ 403 * Each entry pairs a session-side handle (assigned by libkit) with 404 * driver-side bookkeeping: a stable integer id we expose to the user, the 405 * spec text the user gave us, and a flag that lets us cheaply re-arm 406 * temp-disabled breakpoints. */ 407 408 typedef enum BpKind { 409 BP_ADDR, 410 BP_SYM, 411 BP_LINE, 412 } BpKind; 413 414 typedef struct Bp { 415 int id; /* user-facing handle, 1.. */ 416 int enabled; 417 BpKind kind; 418 char* spec; /* heap-owned NUL-terminated copy */ 419 size_t spec_size; 420 uint64_t addr; 421 uint64_t skip_count; /* silent skips before the first stop */ 422 uint64_t max_hits; /* 0 = unlimited */ 423 uint32_t session_id; /* libkit handle; 0 when disarmed */ 424 } Bp; 425 426 typedef struct DbgSource { 427 char* name; 428 size_t name_size; 429 uint8_t* data; 430 size_t data_size; 431 size_t len; 432 } DbgSource; 433 434 /* ============================================================ 435 * Session-scoped state 436 * ============================================================ */ 437 438 typedef struct DbgState { 439 DriverEnv* env; 440 KitCompiler* compiler; 441 KitContext ctx; 442 KitCCompileOptions copts; 443 KitPreprocessOptions pp; /* preprocessor settings for REPL compiles */ 444 KitJit* jit; 445 KitJitSession* session; 446 const KitObjFile* view; 447 KitDebugInfo* dwarf; 448 void* entry_addr; 449 const char* entry_name; 450 KitLanguage default_jit_lang; 451 const char* default_jit_name; 452 /* Backing storage for default_jit_name (built from the canonical frontend 453 * extension), kept stable for the session's lifetime. */ 454 char default_jit_name_buf[32]; 455 KitCompileSession* compile_sessions[KIT_LANG_COUNT]; 456 DbgSource* sources; 457 uint32_t nsources; 458 uint32_t sources_cap; 459 int prog_argc; 460 char** prog_argv; 461 462 Bp* bps; 463 uint32_t nbps; 464 uint32_t bps_cap; 465 int next_bp_id; 466 uint64_t 467 expr_counter; /* user-visible $N; advances only on a successful expr */ 468 uint64_t expr_attempt; /* unique thunk-symbol id; advances every attempt */ 469 uint64_t source_counter; 470 471 int has_stop; 472 KitStopInfo last_stop; 473 uint64_t jit_counter; 474 DriverLineHistory line_history; 475 476 DbgScriptEntry* script_entries; /* transferred from DbgOpts */ 477 uint32_t nscript_entries; 478 int batch_mode; 479 int error_count; 480 } DbgState; 481 482 /* Like driver_errf but increments s->error_count so --batch can propagate 483 * command failures to the exit code. */ 484 #define dbg_errf(s, ...) \ 485 (driver_errf(DBG_TOOL, __VA_ARGS__), (void)((s)->error_count++)) 486 487 #define DBG_LIST_CTX 5 /* lines printed before/after the target */ 488 489 /* SIGINT trampoline. The handler in env.c calls our cb with this state; 490 * we forward into the session. kit_jit_session_interrupt is documented 491 * async-signal-safe. */ 492 static void dbg_on_sigint(void* user) { 493 DbgState* s = (DbgState*)user; 494 if (s && s->session) kit_jit_session_interrupt(s->session); 495 } 496 497 /* PC-space translation between the JIT runtime address space (where 498 * SIGTRAP fires and where the debugger installs breakpoints) and the 499 * image-relative vaddr space DWARF was authored in. Every DWARF call 500 * that takes a PC consumes an image vaddr, and every DWARF result 501 * that names a code address is image-relative — translate at the 502 * boundary. Fallback is pass-through so out-of-image PCs (e.g. 503 * stops inside libc on a future multi-input setup) don't return 0 504 * and silently degrade lookups. */ 505 static uint64_t dbg_pc_rt_to_img(DbgState* s, uint64_t rt) { 506 uint64_t v = kit_jit_runtime_to_image(s->jit, rt); 507 return v ? v : rt; 508 } 509 static uint64_t dbg_pc_img_to_rt(DbgState* s, uint64_t img) { 510 uint64_t v = kit_jit_image_to_runtime(s->jit, img); 511 return v ? v : img; 512 } 513 514 /* Build a frame view in image-PC space for DWARF queries that key off 515 * frame->pc (subprogram_at, param_iter_new, vars_at_new, unwind_step). 516 * The register snapshot and CFA stay in their original (runtime) form 517 * because dw_eval_expr / loc_read interpret them as live host values. */ 518 static KitUnwindFrame dbg_frame_for_dwarf(DbgState* s, 519 const KitUnwindFrame* rt) { 520 KitUnwindFrame out = *rt; 521 out.pc = dbg_pc_rt_to_img(s, rt->pc); 522 return out; 523 } 524 525 /* Translate any image-vaddr fields stored on a KitDwarfVarLoc back 526 * to runtime addresses before the loc is handed to a memory accessor 527 * (session_read_mem / session_write_mem operate in runtime space). 528 * Only DLOC_GLOBAL carries an absolute address straight from 529 * .debug_info; DLOC_REG / DLOC_FRAME_OFS / DLOC_EXPR derive their 530 * effective address from live register state or are evaluated against 531 * the frame, both of which are already in runtime space. */ 532 static void dbg_translate_loc(DbgState* s, KitDwarfVarLoc* loc) { 533 if (!loc) return; 534 if (loc->kind == KIT_DLOC_GLOBAL) 535 loc->v.global = dbg_pc_img_to_rt(s, loc->v.global); 536 } 537 538 /* ============================================================ 539 * Tiny driver-local string utilities 540 * ============================================================ 541 * The driver TU may use plain libc <string.h>/<ctype.h> per the project 542 * rules (no syscalls). We avoid pulling in libc here only because the 543 * existing driver shims cover everything we need. */ 544 545 static int dbg_isspace(int c) { 546 return c == ' ' || c == '\t' || c == '\r' || c == '\n'; 547 } 548 static int dbg_isdigit(int c) { return c >= '0' && c <= '9'; } 549 static int dbg_isxdigit(int c) { 550 return dbg_isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); 551 } 552 553 static int dbg_xval(int c) { 554 if (dbg_isdigit(c)) return c - '0'; 555 if (c >= 'a' && c <= 'f') return c - 'a' + 10; 556 return c - 'A' + 10; 557 } 558 559 static char* dbg_dup(DriverEnv* env, const char* s, size_t n, 560 size_t* size_out) { 561 char* p = driver_alloc(env, n + 1); 562 if (!p) return NULL; 563 driver_memcpy(p, s, n); 564 p[n] = '\0'; 565 if (size_out) *size_out = n + 1; 566 return p; 567 } 568 569 /* Parse a 0x-prefixed hex literal or a decimal literal into *out. Returns 570 * the number of characters consumed, or 0 on failure. */ 571 static size_t dbg_parse_uint(const char* s, uint64_t* out) { 572 size_t i = 0; 573 uint64_t v = 0; 574 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { 575 i = 2; 576 if (!dbg_isxdigit((unsigned char)s[i])) return 0; 577 for (; dbg_isxdigit((unsigned char)s[i]); ++i) { 578 v = (v << 4) | (uint64_t)dbg_xval((unsigned char)s[i]); 579 } 580 } else { 581 if (!dbg_isdigit((unsigned char)s[0])) return 0; 582 for (; dbg_isdigit((unsigned char)s[i]); ++i) { 583 v = v * 10 + (uint64_t)(s[i] - '0'); 584 } 585 } 586 *out = v; 587 return i; 588 } 589 590 static size_t dbg_u64_dec(char* dst, size_t cap, uint64_t v); 591 592 /* ============================================================ 593 * Breakpoint table operations 594 * ============================================================ */ 595 596 static Bp* dbg_bp_grow(DbgState* s) { 597 uint32_t nc; 598 size_t old_size, new_size; 599 Bp* nb; 600 if (s->nbps < s->bps_cap) return &s->bps[s->nbps]; 601 602 nc = s->bps_cap ? s->bps_cap * 2 : 8; 603 old_size = (size_t)s->bps_cap * sizeof(Bp); 604 new_size = (size_t)nc * sizeof(Bp); 605 nb = s->env->heap->realloc(s->env->heap, s->bps, old_size, new_size, 606 _Alignof(Bp)); 607 if (!nb) { 608 dbg_errf(s, "out of memory growing breakpoint table"); 609 return NULL; 610 } 611 /* Zero the freshly grown tail so future driver_free walks it cleanly. */ 612 { 613 char* z = (char*)nb + old_size; 614 size_t n = new_size - old_size; 615 size_t j; 616 for (j = 0; j < n; ++j) z[j] = 0; 617 } 618 s->bps = nb; 619 s->bps_cap = nc; 620 return &s->bps[s->nbps]; 621 } 622 623 static Bp* dbg_bp_find(DbgState* s, int id) { 624 uint32_t i; 625 for (i = 0; i < s->nbps; ++i) { 626 if (s->bps[i].id == id) return &s->bps[i]; 627 } 628 return NULL; 629 } 630 631 static void dbg_bp_release(DbgState* s, Bp* b) { 632 if (b->session_id) { 633 kit_jit_session_breakpoint_clear(s->session, b->session_id); 634 b->session_id = 0; 635 } 636 if (b->spec) { 637 driver_free(s->env, b->spec, b->spec_size); 638 b->spec = NULL; 639 b->spec_size = 0; 640 } 641 } 642 643 static int dbg_bp_remove(DbgState* s, int id) { 644 uint32_t i; 645 for (i = 0; i < s->nbps; ++i) { 646 if (s->bps[i].id == id) { 647 dbg_bp_release(s, &s->bps[i]); 648 /* Shift tail down to keep the array dense; ids stay stable. */ 649 { 650 uint32_t j; 651 for (j = i + 1; j < s->nbps; ++j) s->bps[j - 1] = s->bps[j]; 652 } 653 s->nbps--; 654 { 655 Bp z = {0}; 656 s->bps[s->nbps] = z; 657 } 658 return 0; 659 } 660 } 661 return 1; 662 } 663 664 static void dbg_bps_release_all(DbgState* s) { 665 uint32_t i; 666 for (i = 0; i < s->nbps; ++i) dbg_bp_release(s, &s->bps[i]); 667 if (s->bps) { 668 driver_free(s->env, s->bps, (size_t)s->bps_cap * sizeof(Bp)); 669 s->bps = NULL; 670 s->bps_cap = 0; 671 s->nbps = 0; 672 } 673 } 674 675 static void dbg_compile_sessions_release(DbgState* s) { 676 uint32_t i; 677 for (i = 0; i < (uint32_t)KIT_LANG_COUNT; ++i) { 678 kit_compile_session_free(s->compile_sessions[i]); 679 s->compile_sessions[i] = NULL; 680 } 681 } 682 683 static void dbg_sources_release_all(DbgState* s) { 684 uint32_t i; 685 for (i = 0; i < s->nsources; ++i) { 686 DbgSource* src = &s->sources[i]; 687 if (src->name) driver_free(s->env, src->name, src->name_size); 688 if (src->data) driver_free(s->env, src->data, src->data_size); 689 } 690 if (s->sources) { 691 driver_free(s->env, s->sources, 692 (size_t)s->sources_cap * sizeof(*s->sources)); 693 s->sources = NULL; 694 } 695 s->nsources = 0; 696 s->sources_cap = 0; 697 } 698 699 /* ============================================================ 700 * LOC parser 701 * ============================================================ 702 * Resolves a user-supplied location specification into a single address 703 * within the JIT image: 704 * 705 * 0xADDR raw address 706 * sym[+0xN | +N] symbol via kit_jit_lookup, optional offset 707 * file.c:LINE DWARF lookup 708 * 709 * Returns 0 on success, 1 on parse / resolution failure (already 710 * reported via driver_errf). */ 711 712 static int dbg_resolve_loc(DbgState* s, const char* spec, BpKind* kind_out, 713 uint64_t* addr_out) { 714 /* file:line — uniquely identifiable by a colon NOT preceded by + and 715 * followed by digits. We require the suffix after ':' to be all 716 * digits so we don't confuse, say, hypothetical `func:42` (which 717 * isn't a thing in C). */ 718 const char* colon = driver_strchr(spec, ':'); 719 if (colon && dbg_isdigit((unsigned char)colon[1])) { 720 size_t file_n = (size_t)(colon - spec); 721 char* file; 722 uint64_t line64; 723 size_t used; 724 size_t file_size; 725 uint64_t pc; 726 727 if (file_n == 0) { 728 dbg_errf(s, "empty file in '%.*s'", 729 KIT_SLICE_ARG(kit_slice_cstr(spec))); 730 return 1; 731 } 732 file = dbg_dup(s->env, spec, file_n, &file_size); 733 if (!file) { 734 dbg_errf(s, "out of memory"); 735 return 1; 736 } 737 used = dbg_parse_uint(colon + 1, &line64); 738 if (!used || colon[1 + used] != '\0') { 739 dbg_errf(s, "expected file.c:LINE, got '%.*s'", 740 KIT_SLICE_ARG(kit_slice_cstr(spec))); 741 driver_free(s->env, file, file_size); 742 return 1; 743 } 744 if (!s->dwarf) { 745 dbg_errf(s, "no DWARF: cannot resolve %.*s", 746 KIT_SLICE_ARG(kit_slice_cstr(spec))); 747 driver_free(s->env, file, file_size); 748 return 1; 749 } 750 { 751 KitStatus rc = kit_dwarf_line_to_addr(s->dwarf, kit_slice_cstr(file), 752 (uint32_t)line64, &pc); 753 if (rc == KIT_NOT_FOUND) { 754 dbg_errf(s, "no line %u in %.*s", (uint32_t)line64, 755 KIT_SLICE_ARG(kit_slice_cstr(file))); 756 driver_free(s->env, file, file_size); 757 return 1; 758 } 759 if (rc == KIT_AMBIGUOUS) { 760 KitDwarfLineMatch cands[8]; 761 uint32_t n = 0; 762 uint32_t k; 763 kit_dwarf_line_to_addr_all(s->dwarf, kit_slice_cstr(file), 764 (uint32_t)line64, cands, 8u, &n); 765 dbg_errf(s, "ambiguous: %.*s:%u matches %u files", 766 KIT_SLICE_ARG(kit_slice_cstr(file)), (uint32_t)line64, 767 (unsigned)n); 768 for (k = 0; k < n && k < 8u; ++k) { 769 dbg_errf(s, " %.*s (0x%llx)", KIT_SLICE_ARG(cands[k].file), 770 (unsigned long long)cands[k].pc); 771 } 772 if (n > 8u) dbg_errf(s, " ... and %u more", n - 8u); 773 dbg_errf(s, "use a longer path suffix (e.g. b dir/%.*s:%u)", 774 KIT_SLICE_ARG(kit_slice_cstr(file)), (uint32_t)line64); 775 driver_free(s->env, file, file_size); 776 return 1; 777 } 778 if (rc != KIT_OK) { 779 dbg_errf(s, "no line entry for %.*s", 780 KIT_SLICE_ARG(kit_slice_cstr(spec))); 781 driver_free(s->env, file, file_size); 782 return 1; 783 } 784 } 785 driver_free(s->env, file, file_size); 786 *kind_out = BP_LINE; 787 *addr_out = dbg_pc_img_to_rt(s, pc); 788 return 0; 789 } 790 791 /* 0xADDR or decimal address. */ 792 if ((spec[0] == '0' && (spec[1] == 'x' || spec[1] == 'X')) || 793 dbg_isdigit((unsigned char)spec[0])) { 794 uint64_t v; 795 size_t used = dbg_parse_uint(spec, &v); 796 if (!used || spec[used] != '\0') { 797 dbg_errf(s, "trailing junk in address '%.*s'", 798 KIT_SLICE_ARG(kit_slice_cstr(spec))); 799 return 1; 800 } 801 *kind_out = BP_ADDR; 802 *addr_out = v; 803 return 0; 804 } 805 806 /* sym[+off] */ 807 { 808 const char* plus = driver_strchr(spec, '+'); 809 size_t name_n = plus ? (size_t)(plus - spec) : driver_strlen(spec); 810 char* name; 811 size_t name_size; 812 void* resolved; 813 uint64_t off = 0; 814 815 if (name_n == 0) { 816 dbg_errf(s, "empty symbol in '%.*s'", 817 KIT_SLICE_ARG(kit_slice_cstr(spec))); 818 return 1; 819 } 820 name = dbg_dup(s->env, spec, name_n, &name_size); 821 if (!name) { 822 dbg_errf(s, "out of memory"); 823 return 1; 824 } 825 resolved = kit_jit_lookup(s->jit, kit_slice_cstr(name)); 826 if (!resolved) { 827 dbg_errf(s, "symbol not found: %.*s", 828 KIT_SLICE_ARG(kit_slice_cstr(name))); 829 driver_free(s->env, name, name_size); 830 return 1; 831 } 832 driver_free(s->env, name, name_size); 833 834 if (plus) { 835 size_t used = dbg_parse_uint(plus + 1, &off); 836 if (!used || plus[1 + used] != '\0') { 837 dbg_errf(s, "bad offset in '%.*s'", 838 KIT_SLICE_ARG(kit_slice_cstr(spec))); 839 return 1; 840 } 841 } 842 843 *kind_out = BP_SYM; 844 /* Object-pointer to integer cast: implementation-defined in 845 * standard C, defined as the address on every host where a JIT 846 * runs. */ 847 { 848 union { 849 void* p; 850 uint64_t u; 851 } cv; 852 cv.p = resolved; 853 *addr_out = cv.u + off; 854 } 855 return 0; 856 } 857 } 858 859 /* ============================================================ 860 * Stop rendering 861 * ============================================================ */ 862 863 static void dbg_print_pc(DbgState* s, uint64_t pc) { 864 KitSlice sym = KIT_SLICE_NULL; 865 uint64_t off = 0; 866 KitSlice file = KIT_SLICE_NULL; 867 uint32_t line = 0; 868 uint32_t col = 0; 869 870 driver_printf("0x%llx", (unsigned long long)pc); 871 if (kit_jit_addr_to_sym(s->jit, pc, &sym, &off) == KIT_OK && sym.s) { 872 if (off) 873 driver_printf(" <%.*s+0x%llx>", KIT_SLICE_ARG(sym), 874 (unsigned long long)off); 875 else 876 driver_printf(" <%.*s>", KIT_SLICE_ARG(sym)); 877 } 878 if (s->dwarf && 879 kit_dwarf_addr_to_line(s->dwarf, dbg_pc_rt_to_img(s, pc), &file, &line, 880 &col) == KIT_OK && 881 file.s) { 882 driver_printf(" at %.*s:%u", KIT_SLICE_ARG(file), line); 883 if (col) driver_printf(":%u", col); 884 } 885 } 886 887 static void dbg_print_source_listing(DbgState* s, KitSlice file, uint32_t line, 888 uint64_t pc, int report_errors); 889 890 static KitSlice dbg_step_stop_label(KitStopReason reason) { 891 switch (reason) { 892 case KIT_STOP_REASON_STEP_INSN: 893 return KIT_SLICE_LIT("Single-step complete at "); 894 case KIT_STOP_REASON_STEP_LINE: 895 return KIT_SLICE_LIT("Step complete at "); 896 case KIT_STOP_REASON_NEXT_LINE: 897 return KIT_SLICE_LIT("Next complete at "); 898 case KIT_STOP_REASON_STEP_OUT: 899 return KIT_SLICE_LIT("Finish complete at "); 900 case KIT_STOP_REASON_UNKNOWN: 901 case KIT_STOP_REASON_USER_BREAKPOINT: 902 case KIT_STOP_REASON_SIGNAL: 903 case KIT_STOP_REASON_TRAP: 904 case KIT_STOP_REASON_INTERRUPT: 905 case KIT_STOP_REASON_EXIT: 906 break; 907 } 908 return KIT_SLICE_LIT("Internal breakpoint hit at "); 909 } 910 911 static void dbg_cmd_bt(DbgState* s); 912 static KitStatus dbg_dwarf_read_mem(void* user, uint64_t addr, void* dst, 913 size_t n); 914 915 static void dbg_render_stop(DbgState* s, const KitStopInfo* st) { 916 KitSlice file = {0}; 917 uint32_t line = 0; 918 uint32_t col = 0; 919 int has_source = 0; 920 921 if (st->kind != KIT_STOP_EXIT && s->dwarf && 922 kit_dwarf_addr_to_line(s->dwarf, dbg_pc_rt_to_img(s, st->regs.pc), &file, 923 &line, &col) == KIT_OK && 924 file.s) { 925 has_source = 1; 926 } 927 928 switch (st->kind) { 929 case KIT_STOP_BREAKPOINT: { 930 Bp* b = NULL; 931 uint32_t i; 932 for (i = 0; i < s->nbps; ++i) { 933 if (s->bps[i].session_id == st->bp_id) { 934 b = &s->bps[i]; 935 break; 936 } 937 } 938 if (b) 939 driver_printf("Breakpoint %d (%.*s) hit at ", b->id, 940 KIT_SLICE_ARG(kit_slice_cstr(b->spec))); 941 else { 942 KitSlice label = dbg_step_stop_label(st->reason); 943 driver_printf("%.*s", KIT_SLICE_ARG(label)); 944 } 945 dbg_print_pc(s, st->regs.pc); 946 driver_printf("\n"); 947 break; 948 } 949 case KIT_STOP_SIGNAL: 950 if (st->reason == KIT_STOP_REASON_TRAP) 951 driver_printf("Stopped on trap signal %d at ", st->signal); 952 else 953 driver_printf("Stopped on signal %d at ", st->signal); 954 dbg_print_pc(s, st->regs.pc); 955 driver_printf("\n"); 956 /* A fault/trap is a crash, not a planned stop: print the backtrace 957 * automatically (the user would type `bt` next anyway). Breakpoints and 958 * step completions are separate stop kinds, so this only fires on a real 959 * signal or __builtin_trap/assert. */ 960 if (s->dwarf) dbg_cmd_bt(s); 961 break; 962 case KIT_STOP_INTERRUPT: 963 driver_printf("Interrupted at "); 964 dbg_print_pc(s, st->regs.pc); 965 driver_printf("\n"); 966 break; 967 case KIT_STOP_EXIT: 968 driver_printf("Program exited with code %d\n", st->exit_code); 969 break; 970 } 971 if (has_source) 972 dbg_print_source_listing(s, file, line, dbg_pc_rt_to_img(s, st->regs.pc), 973 0); 974 } 975 976 /* ============================================================ 977 * Run / continue / step 978 * ============================================================ 979 * Both `r` and `c` flow through the same wrapper: install SIGINT, drive 980 * the session (call or resume), restore SIGINT, render the stop. The 981 * dbg owns no signal-handling complexity itself — that's the session's 982 * job. */ 983 984 typedef enum DbgRunMode { 985 RUN_FRESH, /* r — _call from entry */ 986 RUN_CONTINUE, /* c — _resume(continue) */ 987 RUN_STEP_INSN, /* si — _resume(step_insn) */ 988 RUN_STEP_LINE, /* s — _resume(step_line) */ 989 RUN_NEXT_LINE, /* n — _resume(next_line) */ 990 RUN_STEP_OUT, /* finish — _resume(step_out) */ 991 } DbgRunMode; 992 993 static int dbg_drive(DbgState* s, DbgRunMode mode) { 994 KitStatus rc; 995 996 if (mode == RUN_FRESH && s->has_stop) { 997 /* The previous session is dead (entry returned or signal landed). 998 * Start a new one. Try to abort it first in case it's parked in a fault. */ 999 if (s->session) { 1000 kit_jit_session_resume(s->session, KIT_RESUME_ABORT, NULL); 1001 } 1002 s->has_stop = 0; 1003 } else if (mode != RUN_FRESH && !s->has_stop) { 1004 dbg_errf(s, "no program is running; use 'r' to start"); 1005 return 1; 1006 } 1007 1008 if (mode == RUN_FRESH && !s->entry_addr) { 1009 if (!s->entry_name || !*s->entry_name) { 1010 dbg_errf(s, "no entry symbol configured"); 1011 return 1; 1012 } 1013 s->entry_addr = kit_jit_lookup(s->jit, kit_slice_cstr(s->entry_name)); 1014 if (!s->entry_addr) { 1015 dbg_errf(s, "entry symbol not found: %.*s", 1016 KIT_SLICE_ARG(kit_slice_cstr(s->entry_name))); 1017 return 1; 1018 } 1019 } 1020 1021 if (driver_install_sigint(dbg_on_sigint, s) != 0) { 1022 dbg_errf(s, "failed to install SIGINT handler"); 1023 return 1; 1024 } 1025 1026 if (mode == RUN_FRESH) { 1027 rc = kit_jit_session_call(s->session, s->entry_addr, KIT_ENTRY_INT_ARGV, 1028 s->prog_argc, s->prog_argv, &s->last_stop); 1029 } else { 1030 KitResumeMode rm = KIT_RESUME_CONTINUE; 1031 switch (mode) { 1032 case RUN_STEP_INSN: 1033 rm = KIT_RESUME_STEP_INSN; 1034 break; 1035 case RUN_STEP_LINE: 1036 rm = KIT_RESUME_STEP_LINE; 1037 break; 1038 case RUN_NEXT_LINE: 1039 rm = KIT_RESUME_NEXT_LINE; 1040 break; 1041 case RUN_STEP_OUT: 1042 rm = KIT_RESUME_STEP_OUT; 1043 break; 1044 case RUN_CONTINUE: 1045 rm = KIT_RESUME_CONTINUE; 1046 break; 1047 case RUN_FRESH: 1048 break; /* unreachable */ 1049 } 1050 rc = kit_jit_session_resume(s->session, rm, &s->last_stop); 1051 } 1052 1053 driver_restore_sigint(); 1054 1055 if (rc != KIT_OK) { 1056 driver_errf( 1057 DBG_TOOL, 1058 "session %.*s failed (st=%d) — " 1059 "JIT session implementation pending", 1060 KIT_SLICE_ARG(kit_slice_cstr(mode == RUN_FRESH ? "call" : "resume")), 1061 (int)rc); 1062 return 1; 1063 } 1064 1065 s->has_stop = 1; 1066 dbg_render_stop(s, &s->last_stop); 1067 if (s->last_stop.kind == KIT_STOP_EXIT) s->has_stop = 0; 1068 return 0; 1069 } 1070 1071 /* Forward declarations: backtrace renders parameter values via the 1072 * type-aware printer defined below. */ 1073 static void dbg_print_value(DbgState*, const KitDwarfType*, const uint8_t*, 1074 size_t got, int depth); 1075 static int dbg_read_value(DbgState*, const KitDwarfVarLoc*, 1076 const KitUnwindFrame*, uint8_t* stack_buf, 1077 size_t stack_cap, uint8_t** buf_out, 1078 size_t* alloc_out, size_t* got_out); 1079 static void dbg_release_value_buf(DbgState*, uint8_t* buf, size_t alloc); 1080 static char* dbg_take_word(char* line, char** word_out); 1081 1082 /* ============================================================ 1083 * Backtrace 1084 * ============================================================ 1085 * Renders one line per frame: 1086 * #N 0xPC <sym+off> in func (arg1=val1, arg2=val2) at file:line 1087 * Parameter rendering uses kit_dwarf_param_iter_* against the frame's 1088 * PC and the unwound register snapshot. Inlined frames are flagged. */ 1089 1090 static void dbg_cmd_bt(DbgState* s) { 1091 KitUnwindFrame frame; 1092 int level = 0; 1093 1094 if (!s->has_stop) { 1095 dbg_errf(s, "no program is stopped"); 1096 return; 1097 } 1098 if (!s->dwarf) { 1099 dbg_errf(s, "no DWARF: backtrace unavailable"); 1100 return; 1101 } 1102 1103 frame = s->last_stop.regs; 1104 for (;;) { 1105 KitDwarfSubprogram sp; 1106 KitUnwindFrame img_frame; 1107 int have_sp; 1108 1109 driver_printf("#%-2d ", level); 1110 driver_printf("0x%llx", (unsigned long long)frame.pc); 1111 1112 { 1113 KitSlice sym = KIT_SLICE_NULL; 1114 uint64_t off = 0; 1115 if (kit_jit_addr_to_sym(s->jit, frame.pc, &sym, &off) == KIT_OK && 1116 sym.s) { 1117 if (off) 1118 driver_printf(" <%.*s+0x%llx>", KIT_SLICE_ARG(sym), 1119 (unsigned long long)off); 1120 else 1121 driver_printf(" <%.*s>", KIT_SLICE_ARG(sym)); 1122 } 1123 } 1124 1125 img_frame = dbg_frame_for_dwarf(s, &frame); 1126 have_sp = (kit_dwarf_subprogram_at(s->dwarf, img_frame.pc, &sp) == KIT_OK); 1127 if (have_sp && sp.name.s) { 1128 KitDwarfParamIter* it = NULL; 1129 KitDwarfVar p; 1130 int first = 1; 1131 driver_printf(" in %.*s%.*s (", KIT_SLICE_ARG(sp.name), 1132 KIT_SLICE_ARG(sp.inlined ? KIT_SLICE_LIT(" [inlined]") 1133 : KIT_SLICE_NULL)); 1134 if (kit_dwarf_param_iter_new(s->dwarf, img_frame.pc, &it) == KIT_OK) { 1135 for (;;) { 1136 KitIterResult r; 1137 uint8_t stack_buf[64]; 1138 uint8_t* buf; 1139 size_t alloc; 1140 size_t got; 1141 r = kit_dwarf_param_iter_next(it, &p); 1142 if (r != KIT_ITER_ITEM) break; 1143 if (!first) driver_printf(", "); 1144 driver_printf("%.*s=", 1145 KIT_SLICE_ARG(p.name.s ? p.name : KIT_SLICE_LIT("?"))); 1146 dbg_translate_loc(s, &p.loc); 1147 if (dbg_read_value(s, &p.loc, &frame, stack_buf, sizeof(stack_buf), 1148 &buf, &alloc, &got) == 0) { 1149 dbg_print_value(s, p.loc.type, buf, got, 0); 1150 dbg_release_value_buf(s, buf, alloc); 1151 } else { 1152 driver_printf("?"); 1153 } 1154 first = 0; 1155 } 1156 kit_dwarf_param_iter_free(it); 1157 } 1158 driver_printf(")"); 1159 } 1160 1161 { 1162 KitSlice file = KIT_SLICE_NULL; 1163 uint32_t line = 0; 1164 uint32_t col = 0; 1165 KitStatus rc = 1166 kit_dwarf_addr_to_line(s->dwarf, img_frame.pc, &file, &line, &col); 1167 if (rc == KIT_OK && file.s) { 1168 driver_printf(" at %.*s:%u", KIT_SLICE_ARG(file), line); 1169 if (col) driver_printf(":%u", col); 1170 } else if (rc == KIT_NOT_FOUND) { 1171 driver_printf(" [no debug info for this frame]"); 1172 } 1173 } 1174 driver_printf("\n"); 1175 1176 /* Advance to the caller by following the frame-pointer chain. kit keeps a 1177 * frame pointer on every backend with a uniform record (fp[0] = caller fp, 1178 * fp[1] = saved return address), so a memory-reading FP walk is reliable 1179 * where kit_dwarf_unwind_step is not — the CFI stepper takes no memory 1180 * provider and so cannot recover a return address spilled to the stack 1181 * (the common case), terminating after the leaf frame. Reads go through the 1182 * session; pc/fp/cfa stay runtime addresses, translated per DWARF query. */ 1183 { 1184 KitArchKind arch = driver_host_target().arch; 1185 int fpreg = driver_bt_fp_dwarf_reg(arch); 1186 int ptr = driver_bt_ptr_size(arch); 1187 uint64_t ra = 0, next_fp = 0; 1188 if (fpreg < 0) break; 1189 if (!driver_bt_fp_step(arch, dbg_dwarf_read_mem, s->session, 1190 frame.regs[fpreg], &ra, &next_fp)) 1191 break; /* bottom of stack */ 1192 /* Stop at the kit-image boundary: past `main` the chain runs into the 1193 * session/JIT trampoline and host libc, which carry no symbols and whose 1194 * depth is host-dependent. */ 1195 if (kit_jit_runtime_to_image(s->jit, ra) == 0) break; 1196 frame.pc = ra; 1197 frame.regs[fpreg] = next_fp; 1198 /* Caller CFA in kit's layout: the address just above the saved pair. */ 1199 frame.cfa = next_fp + 2u * (uint64_t)ptr; 1200 } 1201 if (++level > 256) { 1202 dbg_errf(s, "backtrace truncated at 256 frames"); 1203 break; 1204 } 1205 } 1206 } 1207 1208 /* ============================================================ 1209 * Type-aware value printer 1210 * ============================================================ 1211 * Walks a KitDwarfType and pretty-prints its byte representation. Used 1212 * by `p`, `info locals`, `info args`, and the backtrace-arg renderer. 1213 * Self-recursive for aggregates (struct, union, array). When `type` is 1214 * NULL (no DWARF type info recovered) the printer falls back to LE-as-u64 1215 * for small reads and a hex dump for the rest. The function emits the 1216 * value only — callers print any leading "name = " and the trailing 1217 * newline. */ 1218 1219 static uint64_t dbg_load_le_u(const uint8_t* buf, size_t n) { 1220 uint64_t v = 0; 1221 size_t i; 1222 for (i = 0; i < n && i < 8; ++i) v |= ((uint64_t)buf[i]) << (8 * i); 1223 return v; 1224 } 1225 1226 static int64_t dbg_load_le_s(const uint8_t* buf, size_t n) { 1227 uint64_t v = dbg_load_le_u(buf, n); 1228 if (n > 0 && n < 8) { 1229 uint64_t sign = (uint64_t)1 << (8 * n - 1); 1230 if (v & sign) v |= ~((sign << 1) - 1); 1231 } 1232 return (int64_t)v; 1233 } 1234 1235 static void dbg_indent(int n) { 1236 int i; 1237 for (i = 0; i < n; ++i) driver_printf(" "); 1238 } 1239 1240 static void dbg_print_value(DbgState* s, const KitDwarfType* type, 1241 const uint8_t* buf, size_t got, int depth) { 1242 KitDwarfTypeInfo ti; 1243 1244 if (!type) { 1245 if (got == 0) { 1246 driver_printf("<empty>"); 1247 return; 1248 } 1249 if (got <= 8) { 1250 uint64_t v = dbg_load_le_u(buf, got); 1251 driver_printf("0x%llx (%llu)", (unsigned long long)v, 1252 (unsigned long long)v); 1253 return; 1254 } 1255 { 1256 size_t i; 1257 driver_printf("{"); 1258 for (i = 0; i < got; ++i) driver_printf(" %02x", buf[i]); 1259 driver_printf(" }"); 1260 return; 1261 } 1262 } 1263 1264 ti = kit_dwarf_type_info(type); 1265 switch (ti.kind) { 1266 case KIT_DT_VOID: 1267 driver_printf("void"); 1268 return; 1269 case KIT_DT_SINT: 1270 case KIT_DT_CHAR: 1271 driver_printf("%lld", (long long)dbg_load_le_s(buf, got)); 1272 return; 1273 case KIT_DT_UINT: 1274 case KIT_DT_BOOL: 1275 driver_printf("%llu", (unsigned long long)dbg_load_le_u(buf, got)); 1276 return; 1277 case KIT_DT_PTR: 1278 driver_printf("0x%llx", (unsigned long long)dbg_load_le_u(buf, got)); 1279 return; 1280 case KIT_DT_FLOAT: 1281 if (got == 4) { 1282 union { 1283 uint32_t u; 1284 float f; 1285 } cv; 1286 cv.u = (uint32_t)dbg_load_le_u(buf, 4); 1287 driver_printf("%g", (double)cv.f); 1288 } else if (got == 8) { 1289 union { 1290 uint64_t u; 1291 double d; 1292 } cv; 1293 cv.u = dbg_load_le_u(buf, 8); 1294 driver_printf("%g", cv.d); 1295 } else { 1296 size_t i; 1297 driver_printf("<float-%zu", got); 1298 for (i = 0; i < got; ++i) driver_printf(" %02x", buf[i]); 1299 driver_printf(">"); 1300 } 1301 return; 1302 case KIT_DT_ENUM: { 1303 int64_t v = dbg_load_le_s(buf, got); 1304 KitDwarfEnumIter* it = NULL; 1305 KitDwarfEnumVal ev; 1306 KitSlice match = KIT_SLICE_NULL; 1307 if (kit_dwarf_enum_iter_new(s->dwarf, type, &it) == KIT_OK) { 1308 for (;;) { 1309 KitIterResult r = kit_dwarf_enum_iter_next(it, &ev); 1310 if (r != KIT_ITER_ITEM) break; 1311 if (ev.value == v) { 1312 match = ev.name; 1313 break; 1314 } 1315 } 1316 kit_dwarf_enum_iter_free(it); 1317 } 1318 if (match.s) 1319 driver_printf("%.*s (%lld)", KIT_SLICE_ARG(match), (long long)v); 1320 else 1321 driver_printf("%lld", (long long)v); 1322 return; 1323 } 1324 case KIT_DT_TYPEDEF: 1325 dbg_print_value(s, ti.inner, buf, got, depth); 1326 return; 1327 case KIT_DT_ARRAY: { 1328 uint32_t n = ti.element_count; 1329 size_t esz = 0; 1330 uint32_t i; 1331 if (ti.inner) { 1332 KitDwarfTypeInfo ein = kit_dwarf_type_info(ti.inner); 1333 esz = ein.byte_size; 1334 } 1335 if (esz == 0 || n == 0 || (size_t)n * esz > got) { 1336 size_t k; 1337 driver_printf("{"); 1338 for (k = 0; k < got; ++k) driver_printf(" %02x", buf[k]); 1339 driver_printf(" }"); 1340 return; 1341 } 1342 driver_printf("{\n"); 1343 for (i = 0; i < n; ++i) { 1344 dbg_indent(depth + 1); 1345 driver_printf("[%u] = ", i); 1346 dbg_print_value(s, ti.inner, buf + (size_t)i * esz, esz, depth + 1); 1347 driver_printf(",\n"); 1348 } 1349 dbg_indent(depth); 1350 driver_printf("}"); 1351 return; 1352 } 1353 case KIT_DT_STRUCT: 1354 case KIT_DT_UNION: { 1355 KitDwarfFieldIter* it = NULL; 1356 KitDwarfField f; 1357 driver_printf("{\n"); 1358 if (kit_dwarf_field_iter_new(s->dwarf, type, &it) == KIT_OK) { 1359 for (;;) { 1360 KitIterResult r = kit_dwarf_field_iter_next(it, &f); 1361 if (r != KIT_ITER_ITEM) break; 1362 size_t fsz = 0; 1363 dbg_indent(depth + 1); 1364 driver_printf( 1365 ".%.*s = ", 1366 KIT_SLICE_ARG(f.name.len ? f.name : KIT_SLICE_LIT("<anon>"))); 1367 if (f.bit_size) { 1368 /* Bitfield: read up to 8 bytes spanning the storage 1369 * unit at byte_offset, shift, mask. */ 1370 size_t off = f.byte_offset; 1371 size_t take = (off + 8 <= got) ? 8 : (off < got ? got - off : 0); 1372 uint64_t raw = take ? dbg_load_le_u(buf + off, take) : 0; 1373 uint64_t mask = (f.bit_size >= 64) 1374 ? (uint64_t)-1 1375 : (((uint64_t)1 << f.bit_size) - 1); 1376 uint64_t v = (raw >> f.bit_offset) & mask; 1377 driver_printf("%llu", (unsigned long long)v); 1378 } else { 1379 if (f.type) { 1380 KitDwarfTypeInfo fti = kit_dwarf_type_info(f.type); 1381 fsz = fti.byte_size; 1382 } 1383 if (f.type && fsz > 0 && (size_t)f.byte_offset + fsz <= got) { 1384 dbg_print_value(s, f.type, buf + f.byte_offset, fsz, depth + 1); 1385 } else { 1386 driver_printf("<truncated>"); 1387 } 1388 } 1389 driver_printf(",\n"); 1390 } 1391 kit_dwarf_field_iter_free(it); 1392 } 1393 dbg_indent(depth); 1394 driver_printf("}"); 1395 return; 1396 } 1397 case KIT_DT_FUNC: 1398 driver_printf("<function@0x%llx>", 1399 (unsigned long long)dbg_load_le_u(buf, got)); 1400 return; 1401 } 1402 driver_printf("<?>"); 1403 } 1404 1405 /* KitDwarfReadMemFn adapter: forwards a DWARF-driven memory read into 1406 * the JIT session's address space. The user pointer carries the 1407 * KitJitSession. */ 1408 static KitStatus dbg_dwarf_read_mem(void* user, uint64_t addr, void* dst, 1409 size_t n) { 1410 KitJitSession* sess = (KitJitSession*)user; 1411 if (!sess) return KIT_INVALID; 1412 return kit_jit_session_read_mem(sess, addr, dst, n); 1413 } 1414 1415 /* Read a variable's bytes into a heap or stack buffer sized for its DIE 1416 * type. On success returns 0 and sets *buf_out (which may point at 1417 * stack_buf or at a heap allocation) plus *got_out. The caller frees 1418 * *buf_out via dbg_release_value_buf when done. */ 1419 static int dbg_read_value(DbgState* s, const KitDwarfVarLoc* loc, 1420 const KitUnwindFrame* frame, uint8_t* stack_buf, 1421 size_t stack_cap, uint8_t** buf_out, 1422 size_t* alloc_out, size_t* got_out) { 1423 uint8_t* buf = stack_buf; 1424 size_t alloc = 0; 1425 size_t cap = stack_cap; 1426 size_t got = 0; 1427 1428 if (loc->byte_size > cap) { 1429 alloc = loc->byte_size; 1430 buf = driver_alloc(s->env, alloc); 1431 if (!buf) return 1; 1432 cap = alloc; 1433 } 1434 if (kit_dwarf_loc_read(s->dwarf, loc, frame, dbg_dwarf_read_mem, s->session, 1435 buf, cap, &got) != KIT_OK) { 1436 if (alloc) driver_free(s->env, buf, alloc); 1437 return 1; 1438 } 1439 *buf_out = buf; 1440 *alloc_out = alloc; 1441 *got_out = got; 1442 return 0; 1443 } 1444 1445 static void dbg_release_value_buf(DbgState* s, uint8_t* buf, size_t alloc) { 1446 if (alloc) driver_free(s->env, buf, alloc); 1447 } 1448 1449 /* ============================================================ 1450 * `p name` 1451 * ============================================================ */ 1452 1453 static void dbg_cmd_print(DbgState* s, const char* name) { 1454 KitDwarfVarLoc loc; 1455 uint8_t stack_buf[64]; 1456 uint8_t* buf; 1457 size_t alloc; 1458 size_t got; 1459 1460 if (!s->has_stop) { 1461 dbg_errf(s, "no program is stopped"); 1462 return; 1463 } 1464 1465 { 1466 KitStatus rc = 1467 s->dwarf ? kit_dwarf_var_at(s->dwarf, 1468 dbg_pc_rt_to_img(s, s->last_stop.regs.pc), 1469 kit_slice_cstr(name), &loc) 1470 : KIT_NOT_FOUND; 1471 if (rc == KIT_OK) { 1472 dbg_translate_loc(s, &loc); 1473 if (dbg_read_value(s, &loc, &s->last_stop.regs, stack_buf, 1474 sizeof(stack_buf), &buf, &alloc, &got) != 0) { 1475 dbg_errf(s, "could not read %.*s", 1476 KIT_SLICE_ARG(kit_slice_cstr(name))); 1477 return; 1478 } 1479 driver_printf("%.*s = ", KIT_SLICE_ARG(kit_slice_cstr(name))); 1480 dbg_print_value(s, loc.type, buf, got, 0); 1481 driver_printf("\n"); 1482 dbg_release_value_buf(s, buf, alloc); 1483 return; 1484 } 1485 1486 /* DWARF didn't know about it — try a global symbol. */ 1487 { 1488 void* p = kit_jit_lookup(s->jit, kit_slice_cstr(name)); 1489 if (p) { 1490 union { 1491 void* p; 1492 uint64_t u; 1493 } cv; 1494 cv.p = p; 1495 driver_printf("%.*s = 0x%llx (no DWARF type info)\n", 1496 KIT_SLICE_ARG(kit_slice_cstr(name)), 1497 (unsigned long long)cv.u); 1498 return; 1499 } 1500 } 1501 dbg_errf(s, "no variable or symbol named '%.*s'", 1502 KIT_SLICE_ARG(kit_slice_cstr(name))); 1503 } 1504 } 1505 1506 /* ============================================================ 1507 * `set NAME VALUE` 1508 * ============================================================ 1509 * Writes a 64-bit value into a variable. Routes to write_mem for 1510 * frame-relative and global locations, set_regs for register-resident 1511 * variables. v1 supports integer/pointer scalars only — float and 1512 * aggregate writes are out of scope. */ 1513 1514 static void dbg_cmd_set(DbgState* s, const char* name, uint64_t value) { 1515 KitDwarfVarLoc loc; 1516 uint8_t buf[8]; 1517 size_t sz; 1518 size_t i; 1519 1520 if (!s->has_stop) { 1521 dbg_errf(s, "no program is stopped"); 1522 return; 1523 } 1524 { 1525 KitStatus rc = 1526 s->dwarf ? kit_dwarf_var_at(s->dwarf, 1527 dbg_pc_rt_to_img(s, s->last_stop.regs.pc), 1528 kit_slice_cstr(name), &loc) 1529 : KIT_NOT_FOUND; 1530 if (rc != KIT_OK) { 1531 dbg_errf(s, "no variable named '%.*s'", 1532 KIT_SLICE_ARG(kit_slice_cstr(name))); 1533 return; 1534 } 1535 } 1536 dbg_translate_loc(s, &loc); 1537 1538 sz = (loc.byte_size == 0 || loc.byte_size > 8) ? 8 : loc.byte_size; 1539 for (i = 0; i < sz; ++i) buf[i] = (uint8_t)(value >> (8 * i)); 1540 1541 switch (loc.kind) { 1542 case KIT_DLOC_FRAME_OFS: { 1543 uint64_t addr = 1544 s->last_stop.regs.cfa + (uint64_t)(int64_t)loc.v.frame_ofs; 1545 if (kit_jit_session_write_mem(s->session, addr, buf, sz) != KIT_OK) { 1546 dbg_errf(s, "memory write failed"); 1547 } 1548 return; 1549 } 1550 case KIT_DLOC_GLOBAL: 1551 if (kit_jit_session_write_mem(s->session, loc.v.global, buf, sz) != 1552 KIT_OK) { 1553 dbg_errf(s, "memory write failed"); 1554 } 1555 return; 1556 case KIT_DLOC_REG: { 1557 KitUnwindFrame fr = s->last_stop.regs; 1558 if (loc.v.reg >= 32) { 1559 dbg_errf(s, "register %u outside the snapshot range", 1560 loc.v.reg); 1561 return; 1562 } 1563 fr.regs[loc.v.reg] = value; 1564 if (kit_jit_session_set_regs(s->session, &fr) != KIT_OK) { 1565 dbg_errf(s, "register write failed"); 1566 return; 1567 } 1568 s->last_stop.regs = fr; 1569 return; 1570 } 1571 case KIT_DLOC_EXPR: 1572 dbg_errf(s, "cannot set '%.*s': location is a DWARF expression", 1573 KIT_SLICE_ARG(kit_slice_cstr(name))); 1574 return; 1575 } 1576 } 1577 1578 /* ============================================================ 1579 * `jump ADDR` 1580 * ============================================================ 1581 * Move PC without resuming. The session validates that the new PC lies 1582 * within the JIT image. */ 1583 1584 static void dbg_cmd_jump(DbgState* s, uint64_t pc) { 1585 KitUnwindFrame fr; 1586 if (!s->has_stop) { 1587 dbg_errf(s, "no program is stopped"); 1588 return; 1589 } 1590 fr = s->last_stop.regs; 1591 fr.pc = pc; 1592 if (kit_jit_session_set_regs(s->session, &fr) != 0) { 1593 dbg_errf(s, "jump failed (pc 0x%llx outside image?)", 1594 (unsigned long long)pc); 1595 return; 1596 } 1597 s->last_stop.regs = fr; 1598 driver_printf("PC set to 0x%llx\n", (unsigned long long)pc); 1599 } 1600 1601 /* ============================================================ 1602 * `info locals` / `info args` / `info reg` 1603 * ============================================================ */ 1604 1605 static void dbg_cmd_info_vars(DbgState* s, uint32_t mask, const char* label) { 1606 KitDwarfVarIter* it = NULL; 1607 KitDwarfVar v; 1608 int printed = 0; 1609 1610 if (!s->has_stop) { 1611 dbg_errf(s, "no program is stopped"); 1612 return; 1613 } 1614 if (!s->dwarf) { 1615 dbg_errf(s, "no DWARF: %.*s unavailable", 1616 KIT_SLICE_ARG(kit_slice_cstr(label))); 1617 return; 1618 } 1619 1620 if (kit_dwarf_vars_at_new(s->dwarf, dbg_pc_rt_to_img(s, s->last_stop.regs.pc), 1621 mask, &it) != KIT_OK) { 1622 driver_printf("No %.*s.\n", KIT_SLICE_ARG(kit_slice_cstr(label))); 1623 return; 1624 } 1625 for (;;) { 1626 KitIterResult r = kit_dwarf_vars_at_next(it, &v); 1627 if (r != KIT_ITER_ITEM) break; 1628 uint8_t stack_buf[64]; 1629 uint8_t* buf; 1630 size_t alloc; 1631 size_t got; 1632 printed = 1; 1633 dbg_translate_loc(s, &v.loc); 1634 if (dbg_read_value(s, &v.loc, &s->last_stop.regs, stack_buf, 1635 sizeof(stack_buf), &buf, &alloc, &got) != 0) { 1636 driver_printf(" %.*s = <unreadable>\n", KIT_SLICE_ARG(v.name)); 1637 continue; 1638 } 1639 driver_printf(" %.*s = ", KIT_SLICE_ARG(v.name)); 1640 dbg_print_value(s, v.loc.type, buf, got, 1); 1641 driver_printf("\n"); 1642 dbg_release_value_buf(s, buf, alloc); 1643 } 1644 kit_dwarf_vars_at_free(it); 1645 if (!printed) 1646 driver_printf("No %.*s.\n", KIT_SLICE_ARG(kit_slice_cstr(label))); 1647 } 1648 1649 static void dbg_cmd_info_reg(DbgState* s) { 1650 KitArchKind arch = driver_host_target().arch; 1651 uint32_t n = kit_arch_register_count(arch); 1652 uint32_t i; 1653 1654 if (!s->has_stop) { 1655 dbg_errf(s, "no program is stopped"); 1656 return; 1657 } 1658 if (n == 0) { 1659 dbg_errf(s, "no register table for this arch"); 1660 return; 1661 } 1662 driver_printf("pc 0x%016llx\n", (unsigned long long)s->last_stop.regs.pc); 1663 driver_printf("cfa 0x%016llx\n", 1664 (unsigned long long)s->last_stop.regs.cfa); 1665 for (i = 0; i < n; ++i) { 1666 KitArchReg r; 1667 if (kit_arch_register_at(arch, i, &r) != KIT_OK) continue; 1668 if (r.dwarf_idx >= 32) continue; /* outside KitUnwindFrame.regs */ 1669 driver_printf("%-6.*s 0x%016llx\n", KIT_SLICE_ARG(r.name), 1670 (unsigned long long)s->last_stop.regs.regs[r.dwarf_idx]); 1671 } 1672 } 1673 1674 /* ============================================================ 1675 * `info functions [PATTERN]` / `info variables [PATTERN]` 1676 * ============================================================ */ 1677 1678 /* Tiny glob matcher: '*' matches any run, '?' matches any single byte. 1679 * NULL pattern matches every name. */ 1680 static int dbg_glob(const char* pat, const char* s) { 1681 if (!pat) return 1; 1682 while (*pat && *s) { 1683 if (*pat == '*') { 1684 if (pat[1] == '\0') return 1; 1685 while (*s) { 1686 if (dbg_glob(pat + 1, s)) return 1; 1687 ++s; 1688 } 1689 return dbg_glob(pat + 1, s); 1690 } 1691 if (*pat != '?' && *pat != *s) return 0; 1692 ++pat; 1693 ++s; 1694 } 1695 while (*pat == '*') ++pat; 1696 return *pat == '\0' && *s == '\0'; 1697 } 1698 1699 static void dbg_cmd_info_syms(DbgState* s, KitSymKind want, 1700 const char* pattern) { 1701 KitJitSymIter* it = NULL; 1702 KitJitSym sym; 1703 int printed = 0; 1704 1705 if (kit_jit_sym_iter_new(s->jit, &it) != KIT_OK) { 1706 dbg_errf(s, "symbol enumeration unavailable"); 1707 return; 1708 } 1709 for (;;) { 1710 KitIterResult r = kit_jit_sym_iter_next(it, &sym); 1711 if (r != KIT_ITER_ITEM) break; 1712 if (sym.kind != want) continue; 1713 if (pattern && !dbg_glob(pattern, sym.name.s)) continue; 1714 driver_printf("0x%016llx %.*s\n", (unsigned long long)sym.addr, 1715 KIT_SLICE_ARG(sym.name)); 1716 printed = 1; 1717 } 1718 kit_jit_sym_iter_free(it); 1719 if (!printed) driver_printf("(none)\n"); 1720 } 1721 1722 static int dbg_refresh_dwarf(DbgState* s) { 1723 if (s->dwarf) { 1724 kit_dwarf_free(s->dwarf); 1725 s->dwarf = NULL; 1726 } 1727 s->view = kit_jit_view(s->jit); 1728 if (s->view) { 1729 if (kit_dwarf_open(&s->ctx, s->view, &s->dwarf) != KIT_OK) s->dwarf = NULL; 1730 if (s->dwarf && s->session) { 1731 kit_jit_session_attach_dwarf(s->session, s->dwarf); 1732 } 1733 } else if (s->session) { 1734 kit_jit_session_attach_dwarf(s->session, NULL); 1735 } 1736 return 0; 1737 } 1738 1739 static int dbg_buf_append(DbgState* s, char** buf, size_t* len, size_t* cap, 1740 const char* src, size_t n) { 1741 if (*len + n + 1u > *cap) { 1742 size_t nc = *cap ? *cap * 2u : 1024u; 1743 char* nb; 1744 while (nc < *len + n + 1u) nc *= 2u; 1745 nb = (char*)s->env->heap->realloc(s->env->heap, *buf, *cap, nc, 1746 _Alignof(char)); 1747 if (!nb) return 1; 1748 *buf = nb; 1749 *cap = nc; 1750 } 1751 driver_memcpy(*buf + *len, src, n); 1752 *len += n; 1753 (*buf)[*len] = '\0'; 1754 return 0; 1755 } 1756 1757 static DbgSource* dbg_source_find(DbgState* s, KitSlice name) { 1758 uint32_t i; 1759 if (!s || !name.s || !name.len) return NULL; 1760 for (i = 0; i < s->nsources; ++i) { 1761 DbgSource* src = &s->sources[i]; 1762 if (src->name && src->name_size == name.len + 1u && 1763 memcmp(src->name, name.s, name.len) == 0) { 1764 return src; 1765 } 1766 } 1767 return NULL; 1768 } 1769 1770 static DbgSource* dbg_source_grow(DbgState* s) { 1771 uint32_t nc; 1772 size_t old_size, new_size; 1773 DbgSource* ns; 1774 if (s->nsources < s->sources_cap) return &s->sources[s->nsources]; 1775 1776 nc = s->sources_cap ? s->sources_cap * 2 : 8; 1777 old_size = (size_t)s->sources_cap * sizeof(*s->sources); 1778 new_size = (size_t)nc * sizeof(*s->sources); 1779 ns = (DbgSource*)s->env->heap->realloc(s->env->heap, s->sources, old_size, 1780 new_size, _Alignof(DbgSource)); 1781 if (!ns) return NULL; 1782 { 1783 char* z = (char*)ns + old_size; 1784 size_t n = new_size - old_size; 1785 size_t j; 1786 for (j = 0; j < n; ++j) z[j] = 0; 1787 } 1788 s->sources = ns; 1789 s->sources_cap = nc; 1790 return &s->sources[s->nsources]; 1791 } 1792 1793 static int dbg_source_intern_name(DbgState* s, KitSlice name, 1794 const char** out) { 1795 DbgSource* src; 1796 size_t name_size; 1797 char* name_copy; 1798 if (out) *out = NULL; 1799 if (!s || !name.s || !name.len) return 1; 1800 1801 src = dbg_source_find(s, name); 1802 if (src) { 1803 if (out) *out = src->name; 1804 return 0; 1805 } 1806 1807 name_copy = dbg_dup(s->env, name.s, name.len, &name_size); 1808 if (!name_copy) return 1; 1809 src = dbg_source_grow(s); 1810 if (!src) { 1811 driver_free(s->env, name_copy, name_size); 1812 return 1; 1813 } 1814 src->name = name_copy; 1815 src->name_size = name_size; 1816 s->nsources++; 1817 if (out) *out = src->name; 1818 return 0; 1819 } 1820 1821 static int dbg_source_cache_put(DbgState* s, KitSlice name, const char* data, 1822 size_t len) { 1823 DbgSource* src; 1824 uint8_t* data_copy; 1825 size_t data_size = len ? len : 1u; 1826 if (!s || !name.s || !name.len || !data) return 1; 1827 1828 data_copy = (uint8_t*)driver_alloc(s->env, data_size); 1829 if (!data_copy) return 1; 1830 if (len) driver_memcpy(data_copy, data, len); 1831 1832 src = dbg_source_find(s, name); 1833 if (!src) { 1834 if (dbg_source_intern_name(s, name, NULL) != 0) { 1835 driver_free(s->env, data_copy, data_size); 1836 return 1; 1837 } 1838 src = dbg_source_find(s, name); 1839 if (!src) { 1840 driver_free(s->env, data_copy, data_size); 1841 return 1; 1842 } 1843 } 1844 if (src->data) { 1845 driver_free(s->env, src->data, src->data_size); 1846 } 1847 1848 src->data = data_copy; 1849 src->data_size = data_size; 1850 src->len = len; 1851 return 0; 1852 } 1853 1854 static int dbg_brace_delta(const char* p) { 1855 int d = 0; 1856 while (*p) { 1857 if (*p == '{') 1858 ++d; 1859 else if (*p == '}') 1860 --d; 1861 ++p; 1862 } 1863 return d; 1864 } 1865 1866 /* Caller buffer sizes for the REPL filename builders below. ".<ext>" and 1867 * "<dbg-jit.<ext>>" with the canonical frontend extension comfortably fit. */ 1868 #define DBG_JIT_SUFFIX_CAP 16 1869 #define DBG_JIT_NAME_CAP 32 1870 /* DbgState.default_jit_name_buf must match DBG_JIT_NAME_CAP (it is sized with a 1871 * literal because it precedes this macro in the file). */ 1872 _Static_assert(sizeof(((DbgState*)0)->default_jit_name_buf) == DBG_JIT_NAME_CAP, 1873 "default_jit_name_buf must equal DBG_JIT_NAME_CAP"); 1874 1875 /* Canonical language name for the JIT REPL (kit_language_name with a "c" 1876 * fallback so C and any unnamed/out-of-range language render as "c", matching 1877 * the former hardcoded default). The result is borrowed static storage. */ 1878 static const char* dbg_jit_language_name(KitCompiler* c, KitLanguage lang) { 1879 const char* name = kit_language_name(c, lang); 1880 return name ? name : "c"; 1881 } 1882 1883 /* Append NUL-terminated `s` into `buf[cap]` starting at `*pos`, advancing 1884 * `*pos`. Truncates rather than overflowing; the result is always 1885 * NUL-terminated when cap > 0. (dbg.c builds strings with driver_* helpers 1886 * rather than stdio.) */ 1887 static void dbg_str_append(char* buf, size_t cap, size_t* pos, const char* s) { 1888 size_t n = driver_strlen(s); 1889 size_t room; 1890 if (*pos >= cap) return; 1891 room = cap - 1u - *pos; /* leave space for NUL */ 1892 if (n > room) n = room; 1893 driver_memcpy(buf + *pos, s, n); 1894 *pos += n; 1895 buf[*pos] = '\0'; 1896 } 1897 1898 /* Build the dotted file suffix (e.g. ".toy") for `lang` into `buf`, defaulting 1899 * to ".c" for C and any unnamed/out-of-range language. The canonical bare 1900 * extension is the single source of truth (kit_language_default_extension); 1901 * the leading "." is tool presentation. Returns `buf`. */ 1902 static const char* dbg_jit_language_suffix(KitCompiler* c, KitLanguage lang, 1903 char* buf, size_t cap) { 1904 const char* ext = kit_language_default_extension(c, lang); 1905 size_t pos = 0; 1906 if (lang == KIT_LANG_C || !ext) ext = "c"; 1907 if (cap > 0) buf[0] = '\0'; 1908 dbg_str_append(buf, cap, &pos, "."); 1909 dbg_str_append(buf, cap, &pos, ext); 1910 return buf; 1911 } 1912 1913 /* Build the default synthesized REPL source name (e.g. "<dbg-jit.toy>") for 1914 * `lang` into `buf`, derived from the canonical suffix. Returns `buf`. */ 1915 static const char* dbg_jit_default_name(KitCompiler* c, KitLanguage lang, 1916 char* buf, size_t cap) { 1917 char suffix[DBG_JIT_SUFFIX_CAP]; 1918 size_t pos = 0; 1919 dbg_jit_language_suffix(c, lang, suffix, sizeof suffix); 1920 if (cap > 0) buf[0] = '\0'; 1921 dbg_str_append(buf, cap, &pos, "<dbg-jit"); 1922 dbg_str_append(buf, cap, &pos, suffix); 1923 dbg_str_append(buf, cap, &pos, ">"); 1924 return buf; 1925 } 1926 1927 static int dbg_jit_uses_default_name(KitCompiler* c, KitLanguage lang, 1928 const char* input_name) { 1929 char def[DBG_JIT_NAME_CAP]; 1930 return !input_name || 1931 driver_streq(input_name, 1932 dbg_jit_default_name(c, lang, def, sizeof def)); 1933 } 1934 1935 static int dbg_make_repl_source_name(KitCompiler* c, KitLanguage lang, 1936 uint64_t id, char* out, size_t cap) { 1937 const char* prefix = "<dbg-jit-"; 1938 char suffix_buf[DBG_JIT_SUFFIX_CAP]; 1939 const char* suffix = 1940 dbg_jit_language_suffix(c, lang, suffix_buf, sizeof suffix_buf); 1941 char num[32]; 1942 size_t prefix_len = driver_strlen(prefix); 1943 size_t suffix_len = driver_strlen(suffix); 1944 size_t num_len = dbg_u64_dec(num, sizeof(num), id); 1945 size_t need; 1946 if (!num_len) return 1; 1947 need = prefix_len + num_len + suffix_len + 2u; 1948 if (need > cap) return 1; 1949 driver_memcpy(out, prefix, prefix_len); 1950 driver_memcpy(out + prefix_len, num, num_len); 1951 driver_memcpy(out + prefix_len + num_len, suffix, suffix_len); 1952 out[prefix_len + num_len + suffix_len] = '>'; 1953 out[prefix_len + num_len + suffix_len + 1u] = '\0'; 1954 return 0; 1955 } 1956 1957 static KitLanguage dbg_jit_language_for_tag(DbgState* s, const char* tag, 1958 const char** name_out) { 1959 if (!tag || !*tag) { 1960 if (name_out) *name_out = s->default_jit_name; 1961 return s->default_jit_lang; 1962 } 1963 if (driver_streq(tag, "c")) { 1964 if (name_out) *name_out = "<dbg-jit.c>"; 1965 return KIT_LANG_C; 1966 } 1967 if (driver_streq(tag, "toy")) { 1968 if (name_out) *name_out = "<dbg-jit.toy>"; 1969 return KIT_LANG_TOY; 1970 } 1971 if (driver_streq(tag, "asm") || driver_streq(tag, "s")) { 1972 if (name_out) *name_out = "<dbg-jit.s>"; 1973 return KIT_LANG_ASM; 1974 } 1975 if (driver_streq(tag, "wasm") || driver_streq(tag, "wat")) { 1976 if (name_out) *name_out = "<dbg-jit.wat>"; 1977 return KIT_LANG_WASM; 1978 } 1979 if (name_out) *name_out = tag; 1980 return kit_language_for_path(s->compiler, tag); 1981 } 1982 1983 static KitStatus dbg_compile_session_for(DbgState* s, KitLanguage lang, 1984 KitCompileSession** out) { 1985 KitCompileSessionOptions sopts; 1986 KitStatus st; 1987 1988 if (!s || !out || (unsigned)lang >= KIT_LANG_COUNT) return KIT_INVALID; 1989 *out = NULL; 1990 if (s->compile_sessions[lang]) { 1991 *out = s->compile_sessions[lang]; 1992 return KIT_OK; 1993 } 1994 { 1995 KitCompileSessionOptions z = {0}; 1996 sopts = z; 1997 } 1998 sopts.lang = lang; 1999 sopts.compile.code = s->copts.code; 2000 sopts.compile.diagnostics = s->copts.diagnostics; 2001 sopts.compile.preprocess = s->pp; 2002 st = kit_compile_session_new(s->compiler, &sopts, &s->compile_sessions[lang]); 2003 if (st != KIT_OK) return st; 2004 *out = s->compile_sessions[lang]; 2005 return KIT_OK; 2006 } 2007 2008 static int dbg_jit_compile_append_ex(DbgState* s, KitLanguage lang, 2009 const char* input_name, const char* src, 2010 size_t len, 2011 KitFrontendInputKind input_kind, 2012 const char* repl_entry_name) { 2013 KitSourceInput sin; 2014 KitCompileSession* session = NULL; 2015 KitObjBuilder* ob = NULL; 2016 KitStatus st; 2017 char generated_name[96]; 2018 char default_name[DBG_JIT_NAME_CAP]; 2019 const char* effective_name = 2020 input_name ? input_name 2021 : dbg_jit_default_name(s->compiler, lang, default_name, 2022 sizeof default_name); 2023 uint64_t source_id = s->source_counter + 1u; 2024 int generated_source_name = 0; 2025 2026 s->jit_counter++; 2027 if (input_kind == KIT_FRONTEND_INPUT_REPL_TOPLEVEL && 2028 dbg_jit_uses_default_name(s->compiler, lang, input_name)) { 2029 if (dbg_make_repl_source_name(s->compiler, lang, source_id, generated_name, 2030 sizeof(generated_name)) != 0) { 2031 dbg_errf(s, "repl source name overflow"); 2032 return 1; 2033 } 2034 if (dbg_source_intern_name(s, kit_slice_cstr(generated_name), 2035 &effective_name) != 0) { 2036 dbg_errf(s, "out of memory naming repl source"); 2037 return 1; 2038 } 2039 generated_source_name = 1; 2040 } 2041 memset(&sin, 0, sizeof(sin)); 2042 sin.name = kit_slice_cstr(effective_name); 2043 sin.bytes.data = (const uint8_t*)src; 2044 sin.bytes.len = len; 2045 sin.lang = lang; 2046 sin.input_kind = input_kind; 2047 sin.repl_entry_name = kit_slice_cstr(repl_entry_name); 2048 st = dbg_compile_session_for(s, lang, &session); 2049 /* Stage the compile: on success the frontend's durable declarations are left 2050 * pending so we only commit them once the object has actually been published 2051 * into the JIT image. A failed compile is already rolled back internally. */ 2052 if (st == KIT_OK) st = kit_compile_session_stage(session, &sin, &ob); 2053 if (st != KIT_OK || !ob) { 2054 if (ob) kit_obj_builder_free(ob); 2055 dbg_errf(s, "jit compile failed"); 2056 return 1; 2057 } 2058 { 2059 KitLinkSessionOptions lopts = {0}; 2060 KitLinkSession* link = NULL; 2061 KitJitPublishOptions popts = {0}; 2062 KitJitPublishResult pres; 2063 lopts.output_kind = KIT_LINK_OUTPUT_RELOCATABLE; 2064 st = kit_link_session_new(s->compiler, &lopts, &link); 2065 if (st == KIT_OK) st = kit_link_session_add_obj(link, ob); 2066 popts.kind = KIT_JIT_PUBLISH_APPEND_OBJECTS; 2067 popts.link = link; 2068 if (st == KIT_OK) st = kit_jit_publish(s->jit, &popts, &pres); 2069 kit_link_session_free(link); 2070 } 2071 if (st != KIT_OK) { 2072 /* Publish rejected the object (e.g. a duplicate global). Roll back the 2073 * staged declarations so the frontend never advertises a symbol the JIT 2074 * image does not have. */ 2075 kit_compile_session_abort(session); 2076 dbg_errf(s, "jit append failed"); 2077 return 1; 2078 } 2079 /* Published: make the staged declarations durable. */ 2080 kit_compile_session_commit(session); 2081 if (generated_source_name) s->source_counter = source_id; 2082 { 2083 /* Cache the verbatim toplevel text only for frontends that re-read 2084 * earlier toplevel source on later compiles (toy today), per the 2085 * frontend's static capability rather than a hard-coded language. */ 2086 KitFrontendCaps caps = {0}; 2087 int cache_source = 2088 kit_frontend_caps(s->compiler, lang, &caps) == KIT_OK && 2089 caps.cache_repl_toplevel_source; 2090 if (cache_source && input_kind == KIT_FRONTEND_INPUT_REPL_TOPLEVEL && 2091 dbg_source_cache_put(s, sin.name, src, len) != 0) { 2092 dbg_errf(s, "out of memory caching source for list"); 2093 } 2094 } 2095 dbg_refresh_dwarf(s); 2096 return 0; 2097 } 2098 2099 static int dbg_jit_compile_append(DbgState* s, KitLanguage lang, 2100 const char* input_name, const char* src, 2101 size_t len) { 2102 return dbg_jit_compile_append_ex(s, lang, input_name, src, len, 2103 KIT_FRONTEND_INPUT_REPL_TOPLEVEL, NULL); 2104 } 2105 2106 static int dbg_parse_jit_lang_arg(DbgState* s, const char* rest, 2107 KitLanguage* lang_out, 2108 const char** input_name_out, 2109 const char** after_out) { 2110 const char* p = rest; 2111 const char* input_name = NULL; 2112 KitLanguage lang; 2113 2114 while (*p && dbg_isspace((unsigned char)*p)) ++p; 2115 if (*p && *p != '{') { 2116 const char* tag = p; 2117 size_t tag_n; 2118 char tag_buf[64]; 2119 while (*p && !dbg_isspace((unsigned char)*p) && *p != '{') ++p; 2120 tag_n = (size_t)(p - tag); 2121 if (tag_n == 0 || tag_n >= sizeof(tag_buf)) { 2122 dbg_errf(s, "language/name is too long"); 2123 return 1; 2124 } 2125 driver_memcpy(tag_buf, tag, tag_n); 2126 tag_buf[tag_n] = '\0'; 2127 lang = dbg_jit_language_for_tag(s, tag_buf, &input_name); 2128 if (input_name == tag_buf && 2129 dbg_source_intern_name(s, kit_slice_cstr(input_name), &input_name) != 2130 0) { 2131 dbg_errf(s, "out of memory naming repl source"); 2132 return 1; 2133 } 2134 while (*p && dbg_isspace((unsigned char)*p)) ++p; 2135 } else { 2136 lang = dbg_jit_language_for_tag(s, NULL, &input_name); 2137 } 2138 2139 *lang_out = lang; 2140 *input_name_out = input_name; 2141 *after_out = p; 2142 return 0; 2143 } 2144 2145 static void dbg_cmd_jit(DbgState* s, const char* rest) { 2146 char* src = NULL; 2147 size_t len = 0, cap = 0; 2148 const char* p; 2149 const char* input_name; 2150 KitLanguage lang; 2151 int depth; 2152 2153 if (dbg_parse_jit_lang_arg(s, rest, &lang, &input_name, &p) != 0) return; 2154 if (*p != '{') { 2155 dbg_errf(s, "usage: jit [c|toy|asm|name.ext] { ... }"); 2156 return; 2157 } 2158 ++p; 2159 depth = 1 + dbg_brace_delta(p); 2160 { 2161 const char* end = p + driver_strlen(p); 2162 if (depth <= 0) { 2163 while (end > p && end[-1] != '}') --end; 2164 if (end > p) --end; 2165 } 2166 if (dbg_buf_append(s, &src, &len, &cap, p, (size_t)(end - p)) != 0) 2167 goto oom; 2168 if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) goto oom; 2169 } 2170 while (depth > 0) { 2171 char line[LINE_CAP]; 2172 int n; 2173 driver_printf(" > "); 2174 driver_flush_stdout(); 2175 n = driver_read_line(line, sizeof(line)); 2176 if (n <= 0) { 2177 dbg_errf(s, "unterminated jit block"); 2178 goto out; 2179 } 2180 depth += dbg_brace_delta(line); 2181 if (depth <= 0) { 2182 char* close = line; 2183 while (*close && *close != '}') ++close; 2184 if (dbg_buf_append(s, &src, &len, &cap, line, (size_t)(close - line)) != 2185 0) 2186 goto oom; 2187 if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) goto oom; 2188 break; 2189 } 2190 if (dbg_buf_append(s, &src, &len, &cap, line, driver_strlen(line)) != 0) 2191 goto oom; 2192 if (dbg_buf_append(s, &src, &len, &cap, "\n", 1) != 0) goto oom; 2193 } 2194 2195 (void)dbg_jit_compile_append(s, lang, input_name, src, len); 2196 goto out; 2197 2198 oom: 2199 dbg_errf(s, "out of memory"); 2200 out: 2201 if (src) driver_free(s->env, src, cap); 2202 } 2203 2204 static void dbg_cmd_edit(DbgState* s, const char* rest) { 2205 KitLanguage lang; 2206 const char* input_name; 2207 const char* p; 2208 uint8_t* src = NULL; 2209 size_t len = 0; 2210 char suffix[DBG_JIT_SUFFIX_CAP]; 2211 2212 if (dbg_parse_jit_lang_arg(s, rest, &lang, &input_name, &p) != 0) return; 2213 if (*p) { 2214 dbg_errf(s, "usage: edit [c|toy|asm|name.ext]"); 2215 return; 2216 } 2217 if (!driver_edit_temp(s->env, 2218 dbg_jit_language_suffix(s->compiler, lang, suffix, 2219 sizeof suffix), 2220 NULL, 0, &src, &len)) { 2221 dbg_errf(s, "editor failed"); 2222 return; 2223 } 2224 if (len == 0) { 2225 dbg_errf(s, "empty editor buffer; nothing appended"); 2226 goto out; 2227 } 2228 (void)dbg_jit_compile_append(s, lang, input_name, (const char*)src, len); 2229 2230 out: 2231 driver_free(s->env, src, len); 2232 } 2233 2234 static void dbg_cmd_language(DbgState* s, const char* rest) { 2235 char tmp[WORD_CAP]; 2236 const char* p = rest; 2237 size_t n = 0; 2238 KitLanguage lang; 2239 const char* name; 2240 2241 while (*p && dbg_isspace((unsigned char)*p)) ++p; 2242 while (p[n] && !dbg_isspace((unsigned char)p[n])) ++n; 2243 if (n == 0) { 2244 const KitPreprocessOptions* pp = &s->pp; 2245 driver_printf("Language: %.*s\n", 2246 KIT_SLICE_ARG(kit_slice_cstr(dbg_jit_language_name( 2247 s->compiler, s->default_jit_lang)))); 2248 driver_printf( 2249 "Language options: input=%.*s opt=-O%d debug=%.*s includes=%u " 2250 "system-includes=%u defines=%u undefines=%u session=%.*s\n", 2251 KIT_SLICE_ARG(kit_slice_cstr(s->default_jit_name)), 2252 s->copts.code.opt_level, 2253 KIT_SLICE_ARG(kit_slice_cstr(s->copts.code.debug_info ? "on" : "off")), 2254 (unsigned)pp->ninclude_dirs, (unsigned)pp->nsystem_include_dirs, 2255 (unsigned)pp->ndefines, (unsigned)pp->nundefines, 2256 KIT_SLICE_ARG(kit_slice_cstr(s->compile_sessions[s->default_jit_lang] 2257 ? "cached" 2258 : "not-created"))); 2259 return; 2260 } 2261 if (n >= sizeof(tmp)) { 2262 dbg_errf(s, "usage: :language c|toy|asm|wat|wasm"); 2263 return; 2264 } 2265 driver_memcpy(tmp, p, n); 2266 tmp[n] = '\0'; 2267 lang = dbg_jit_language_for_tag(s, tmp, &name); 2268 (void)name; 2269 if (lang == KIT_LANG_COUNT) { 2270 dbg_errf(s, "unsupported language: %.*s", 2271 KIT_SLICE_ARG(kit_slice_cstr(tmp))); 2272 return; 2273 } 2274 s->default_jit_lang = lang; 2275 s->default_jit_name = dbg_jit_default_name( 2276 s->compiler, lang, s->default_jit_name_buf, sizeof s->default_jit_name_buf); 2277 driver_printf( 2278 "Language: %.*s\n", 2279 KIT_SLICE_ARG(kit_slice_cstr(dbg_jit_language_name(s->compiler, lang)))); 2280 } 2281 2282 static size_t dbg_u64_dec(char* dst, size_t cap, uint64_t v) { 2283 char tmp[32]; 2284 size_t n = 0; 2285 size_t i; 2286 if (!dst || cap == 0) return 0; 2287 if (v == 0) { 2288 if (cap < 2u) return 0; 2289 dst[0] = '0'; 2290 dst[1] = '\0'; 2291 return 1; 2292 } 2293 while (v && n < sizeof(tmp)) { 2294 tmp[n++] = (char)('0' + (v % 10u)); 2295 v /= 10u; 2296 } 2297 if (n + 1u > cap) return 0; 2298 for (i = 0; i < n; ++i) dst[i] = tmp[n - 1u - i]; 2299 dst[n] = '\0'; 2300 return n; 2301 } 2302 2303 static int dbg_call_u64_entry(DbgState* s, void* entry, const uint64_t* args, 2304 uint32_t nargs, uint64_t* ret_out) { 2305 uint64_t ret = 0; 2306 KitStopInfo stop; 2307 2308 if (driver_install_sigint(dbg_on_sigint, s) != 0) { 2309 dbg_errf(s, "failed to install SIGINT handler"); 2310 return 1; 2311 } 2312 if (kit_jit_session_call_u64(s->session, entry, args, nargs, &ret, &stop) != 2313 KIT_OK) { 2314 driver_restore_sigint(); 2315 dbg_errf(s, "call failed (debuggee must be idle or exited)"); 2316 return 1; 2317 } 2318 driver_restore_sigint(); 2319 s->last_stop = stop; 2320 s->has_stop = (stop.kind != KIT_STOP_EXIT); 2321 if (ret_out) *ret_out = ret; 2322 if (stop.kind != KIT_STOP_EXIT) { 2323 s->has_stop = 1; 2324 dbg_render_stop(s, &stop); 2325 return 2; 2326 } 2327 return 0; 2328 } 2329 2330 static void dbg_cmd_expr(DbgState* s, const char* expr) { 2331 char* body = NULL; 2332 size_t body_len = 0, body_cap = 0; 2333 char num[32]; 2334 char name[64]; 2335 size_t num_len; 2336 size_t prefix_len; 2337 void* entry; 2338 uint64_t ret = 0; 2339 uint64_t attempt; 2340 uint64_t id; 2341 int is_block = 0; 2342 2343 while (*expr && dbg_isspace((unsigned char)*expr)) ++expr; 2344 if (!*expr) { 2345 dbg_errf(s, "usage: expr EXPR | expr { STATEMENTS }"); 2346 return; 2347 } 2348 2349 if (*expr == '{') { 2350 const char* p = expr + 1; 2351 int depth = 1 + dbg_brace_delta(p); 2352 const char* end = p + driver_strlen(p); 2353 is_block = 1; 2354 if (depth <= 0) { 2355 while (end > p && end[-1] != '}') --end; 2356 if (end > p) --end; 2357 } 2358 if (dbg_buf_append(s, &body, &body_len, &body_cap, p, (size_t)(end - p)) != 2359 0) 2360 goto oom; 2361 if (dbg_buf_append(s, &body, &body_len, &body_cap, "\n", 1) != 0) goto oom; 2362 while (depth > 0) { 2363 char line[LINE_CAP]; 2364 int n; 2365 driver_printf("expr > "); 2366 driver_flush_stdout(); 2367 n = driver_read_line(line, sizeof(line)); 2368 if (n <= 0) { 2369 dbg_errf(s, "unterminated expr block"); 2370 goto out; 2371 } 2372 depth += dbg_brace_delta(line); 2373 if (depth <= 0) { 2374 char* close = line; 2375 while (*close && *close != '}') ++close; 2376 if (dbg_buf_append(s, &body, &body_len, &body_cap, line, 2377 (size_t)(close - line)) != 0) 2378 goto oom; 2379 if (dbg_buf_append(s, &body, &body_len, &body_cap, "\n", 1) != 0) 2380 goto oom; 2381 break; 2382 } 2383 if (dbg_buf_append(s, &body, &body_len, &body_cap, line, 2384 driver_strlen(line)) != 0) 2385 goto oom; 2386 if (dbg_buf_append(s, &body, &body_len, &body_cap, "\n", 1) != 0) 2387 goto oom; 2388 } 2389 } 2390 2391 /* The thunk symbol name uses a monotonic per-attempt counter so each 2392 * compiled thunk gets a unique linkage name even across failed attempts. 2393 * The user-visible result number ($N) is a separate counter advanced only 2394 * after a full success (compile + publish + call), so a failed snippet does 2395 * not consume a result number. */ 2396 attempt = ++s->expr_attempt; 2397 num_len = dbg_u64_dec(num, sizeof(num), attempt); 2398 if (!num_len) { 2399 dbg_errf(s, "expression counter overflow"); 2400 goto out; 2401 } 2402 prefix_len = driver_strlen("__kit_dbg_expr_"); 2403 if (prefix_len + num_len + 1u > sizeof(name)) { 2404 dbg_errf(s, "expression symbol too long"); 2405 goto out; 2406 } 2407 driver_memcpy(name, "__kit_dbg_expr_", prefix_len); 2408 driver_memcpy(name + prefix_len, num, num_len + 1u); 2409 2410 { 2411 const char* src = is_block ? body : expr; 2412 size_t len = is_block ? body_len : driver_strlen(expr); 2413 KitFrontendInputKind kind = 2414 is_block ? KIT_FRONTEND_INPUT_REPL_BLOCK : KIT_FRONTEND_INPUT_REPL_EXPR; 2415 /* s->default_jit_name mirrors dbg_jit_default_name(s->default_jit_lang), 2416 * kept in sync wherever default_jit_lang is set. */ 2417 if (dbg_jit_compile_append_ex(s, s->default_jit_lang, s->default_jit_name, 2418 src, len, kind, name) != 0) { 2419 goto out; 2420 } 2421 } 2422 2423 entry = kit_jit_lookup(s->jit, kit_slice_cstr(name)); 2424 if (!entry) { 2425 dbg_errf(s, "expression thunk not found: %.*s", 2426 KIT_SLICE_ARG(kit_slice_cstr(name))); 2427 goto out; 2428 } 2429 if (dbg_call_u64_entry(s, entry, NULL, 0, &ret) == 0) { 2430 id = ++s->expr_counter; 2431 driver_printf("$%llu = %llu (0x%llx)\n", (unsigned long long)id, 2432 (unsigned long long)ret, (unsigned long long)ret); 2433 } 2434 goto out; 2435 2436 oom: 2437 dbg_errf(s, "out of memory"); 2438 out: 2439 if (body) driver_free(s->env, body, body_cap); 2440 } 2441 2442 /* ============================================================ 2443 * `x ADDR [count]` 2444 * ============================================================ 2445 * Examine memory: reads `count` bytes (default 16) at `addr` from the 2446 * worker's address space and prints them as 16-byte rows. */ 2447 2448 static void dbg_cmd_examine(DbgState* s, uint64_t addr, size_t count) { 2449 uint8_t buf[256]; 2450 size_t remaining = count; 2451 2452 if (!s->has_stop) { 2453 dbg_errf(s, "no program is stopped"); 2454 return; 2455 } 2456 2457 while (remaining) { 2458 size_t chunk = remaining > sizeof(buf) ? sizeof(buf) : remaining; 2459 size_t i; 2460 if (kit_jit_session_read_mem(s->session, addr, buf, chunk) != KIT_OK) { 2461 dbg_errf(s, "read failed at 0x%llx", (unsigned long long)addr); 2462 return; 2463 } 2464 for (i = 0; i < chunk; i += 16) { 2465 size_t j; 2466 size_t row = chunk - i < 16 ? chunk - i : 16; 2467 driver_printf("0x%llx:", (unsigned long long)(addr + i)); 2468 for (j = 0; j < row; ++j) driver_printf(" %02x", buf[i + j]); 2469 driver_printf("\n"); 2470 } 2471 addr += chunk; 2472 remaining -= chunk; 2473 } 2474 } 2475 2476 /* ============================================================ 2477 * `disasm [ADDR] [count]`, `x/i [ADDR] [count]` 2478 * ============================================================ 2479 * Decode a small instruction window from the stopped program. Without an 2480 * address, starts at the stopped PC; count is in instructions. */ 2481 2482 static void dbg_cmd_disasm(DbgState* s, uint64_t addr, size_t count) { 2483 uint8_t buf[512]; 2484 KitDisasmContext dctx; 2485 KitDisasmIter* it = NULL; 2486 size_t byte_count; 2487 size_t shown = 0; 2488 2489 if (!s->has_stop) { 2490 dbg_errf(s, "no program is stopped"); 2491 return; 2492 } 2493 if (count == 0) count = 8; 2494 if (count > 32) { 2495 dbg_errf(s, "disasm count too large"); 2496 return; 2497 } 2498 byte_count = count * 16u; 2499 if (byte_count > sizeof(buf)) byte_count = sizeof(buf); 2500 if (kit_jit_session_read_mem(s->session, addr, buf, byte_count) != KIT_OK) { 2501 dbg_errf(s, "read failed at 0x%llx", (unsigned long long)addr); 2502 return; 2503 } 2504 2505 memset(&dctx, 0, sizeof(dctx)); 2506 dctx.target = kit_compiler_target(s->compiler); 2507 dctx.context = s->ctx; 2508 if (kit_disasm_iter_new(&dctx, buf, byte_count, addr, s->view, &it) != 2509 KIT_OK) { 2510 dbg_errf(s, "disassembler unavailable"); 2511 return; 2512 } 2513 while (shown < count) { 2514 KitInsn insn; 2515 KitIterResult r = kit_disasm_iter_next(it, &insn); 2516 if (r == KIT_ITER_END) break; 2517 if (r != KIT_ITER_ITEM) { 2518 dbg_errf(s, "disassembly failed"); 2519 break; 2520 } 2521 driver_printf("0x%llx: %-8.*s", (unsigned long long)insn.vaddr, 2522 KIT_SLICE_ARG(insn.mnemonic)); 2523 if (insn.operands.len) driver_printf(" %.*s", KIT_SLICE_ARG(insn.operands)); 2524 if (insn.annotation.len) 2525 driver_printf(" %.*s", KIT_SLICE_ARG(insn.annotation)); 2526 driver_printf("\n"); 2527 shown++; 2528 } 2529 kit_disasm_iter_free(it); 2530 } 2531 2532 /* ============================================================ 2533 * Source listing 2534 * ============================================================ 2535 * Print a context window of source lines centered on `file:line`. 2536 * 2537 * Reads REPL snippets from the debugger's in-memory source cache and normal 2538 * files from disk via env.file_io. When neither is available (e.g. the DWARF 2539 * came from a `.o` / `.a` whose source isn't available here), command-mode 2540 * reports the DWARF line number alone and source stops silently keep the 2541 * already-rendered location line. */ 2542 2543 static void dbg_print_source_bytes(const uint8_t* data, size_t size, 2544 uint32_t line, int report_errors) { 2545 static const uint8_t empty[1] = {0}; 2546 uint32_t target = line; 2547 uint32_t lo = target > DBG_LIST_CTX ? target - DBG_LIST_CTX : 1; 2548 uint32_t hi = target + DBG_LIST_CTX; 2549 uint32_t cur = 1; 2550 const uint8_t* p; 2551 const uint8_t* end; 2552 const uint8_t* line_start; 2553 2554 if (!data && size != 0) return; 2555 if (!data) data = empty; 2556 p = data; 2557 end = data + size; 2558 line_start = p; 2559 2560 while (p <= end) { 2561 int eol = (p == end) || (*p == '\n'); 2562 if (eol) { 2563 if (p == end && p == line_start && end > data && end[-1] == '\n') break; 2564 if (cur >= lo && cur <= hi) { 2565 size_t len = (size_t)(p - line_start); 2566 driver_printf( 2567 "%6u%.*s %.*s\n", cur, 2568 KIT_SLICE_ARG(kit_slice_cstr(cur == target ? " >" : " ")), 2569 (int)len, (const char*)line_start); 2570 } 2571 ++cur; 2572 if (p == end) break; 2573 line_start = p + 1; 2574 } 2575 ++p; 2576 } 2577 if (report_errors && cur <= target) 2578 driver_errf(DBG_TOOL, "file has only %u lines; %u requested", cur - 1u, 2579 target); 2580 } 2581 2582 static void dbg_print_source_listing(DbgState* s, KitSlice file, uint32_t line, 2583 uint64_t pc, int report_errors) { 2584 char path[1024]; 2585 KitFileData fd; 2586 const KitFileIO* io; 2587 DbgSource* cached; 2588 2589 if (!file.s || file.len == 0) { 2590 if (report_errors) { 2591 dbg_errf(s, "bad file in '%.*s'", KIT_SLICE_ARG(file)); 2592 } 2593 return; 2594 } 2595 2596 cached = dbg_source_find(s, file); 2597 if (cached && cached->data) { 2598 dbg_print_source_bytes(cached->data, cached->len, line, report_errors); 2599 return; 2600 } 2601 2602 if (file.len >= sizeof(path)) { 2603 if (report_errors) { 2604 dbg_errf(s, "bad file in '%.*s'", KIT_SLICE_ARG(file)); 2605 } 2606 return; 2607 } 2608 driver_memcpy(path, file.s, file.len); 2609 path[file.len] = '\0'; 2610 2611 /* Try to read the file via file_io. On miss, fall back to the 2612 * DWARF-only summary line per doc/DBG.md §10. */ 2613 io = s->env && s->env->file_io.read_all ? &s->env->file_io : NULL; 2614 if (!io || io->read_all(io->user, path, &fd) != KIT_OK) { 2615 if (report_errors) { 2616 driver_printf("%.*s:%u [source not available; pc=0x%llx]\n", 2617 KIT_SLICE_ARG(kit_slice_cstr(path)), line, 2618 (unsigned long long)pc); 2619 } 2620 return; 2621 } 2622 2623 dbg_print_source_bytes(fd.data, fd.size, line, report_errors); 2624 2625 if (io->release) io->release(io->user, &fd); 2626 } 2627 2628 static void dbg_cmd_list(DbgState* s, const char* spec) { 2629 const char* colon; 2630 size_t flen; 2631 char path[1024]; 2632 uint64_t line_u; 2633 size_t used; 2634 uint64_t pc; 2635 KitSlice file; 2636 2637 if (!s->dwarf) { 2638 dbg_errf(s, "no DWARF: cannot resolve %.*s", 2639 KIT_SLICE_ARG(kit_slice_cstr(spec))); 2640 return; 2641 } 2642 2643 colon = driver_strchr(spec, ':'); 2644 if (!colon || !dbg_isdigit((unsigned char)colon[1])) { 2645 dbg_errf(s, "usage: list file:line"); 2646 return; 2647 } 2648 flen = (size_t)(colon - spec); 2649 if (flen == 0 || flen >= sizeof(path)) { 2650 dbg_errf(s, "bad file in '%.*s'", 2651 KIT_SLICE_ARG(kit_slice_cstr(spec))); 2652 return; 2653 } 2654 driver_memcpy(path, spec, flen); 2655 path[flen] = '\0'; 2656 used = dbg_parse_uint(colon + 1, &line_u); 2657 if (!used || colon[1 + used] != '\0') { 2658 dbg_errf(s, "usage: list file:line"); 2659 return; 2660 } 2661 2662 /* Validate via DWARF first. */ 2663 { 2664 KitStatus st = kit_dwarf_line_to_addr(s->dwarf, kit_slice_cstr(path), 2665 (uint32_t)line_u, &pc); 2666 if (st == KIT_NOT_FOUND) { 2667 dbg_errf(s, "no line %u in %.*s", (uint32_t)line_u, 2668 KIT_SLICE_ARG(kit_slice_cstr(path))); 2669 return; 2670 } 2671 if (st == KIT_AMBIGUOUS) { 2672 dbg_errf(s, 2673 "ambiguous: %.*s:%u matches multiple files; " 2674 "use a longer path suffix", 2675 KIT_SLICE_ARG(kit_slice_cstr(path)), (uint32_t)line_u); 2676 return; 2677 } 2678 if (st != KIT_OK) { 2679 dbg_errf(s, "no line entry for %.*s", 2680 KIT_SLICE_ARG(kit_slice_cstr(spec))); 2681 return; 2682 } 2683 } 2684 2685 file = kit_slice_cstr(path); 2686 dbg_print_source_listing(s, file, (uint32_t)line_u, pc, 1); 2687 } 2688 2689 /* ============================================================ 2690 * `info b`, `b LOC`, `d N`, `enable N` / `disable N`, `ignore N COUNT` 2691 * ============================================================ */ 2692 2693 /* Arm a Bp through the appropriate session entry. The plain breakpoint_set 2694 * is used when no skip/cap is in effect; otherwise the spec form. The 2695 * driver does not yet wire conditions, but the spec callback slot is left 2696 * NULL so this remains forward-compatible. */ 2697 static int dbg_bp_arm(DbgState* s, Bp* b) { 2698 KitStatus st; 2699 if (b->skip_count == 0 && b->max_hits == 0) { 2700 st = kit_jit_session_breakpoint_set(s->session, b->addr, &b->session_id); 2701 } else { 2702 KitBreakpointSpec spec; 2703 KitBreakpointSpec z = {0}; 2704 spec = z; 2705 spec.addr = b->addr; 2706 spec.skip_count = b->skip_count; 2707 spec.max_hits = b->max_hits; 2708 st = kit_jit_session_breakpoint_set_spec(s->session, &spec, &b->session_id); 2709 } 2710 return st == KIT_OK ? 0 : 1; 2711 } 2712 2713 static void dbg_cmd_break(DbgState* s, const char* spec) { 2714 BpKind kind; 2715 uint64_t addr; 2716 Bp* b; 2717 2718 if (!*spec) { 2719 dbg_errf(s, "usage: b <0xADDR | sym[+off] | file.c:line>"); 2720 return; 2721 } 2722 if (dbg_resolve_loc(s, spec, &kind, &addr) != 0) return; 2723 2724 b = dbg_bp_grow(s); 2725 if (!b) return; 2726 2727 { 2728 Bp z = {0}; 2729 *b = z; 2730 } 2731 b->id = ++s->next_bp_id; 2732 b->enabled = 1; 2733 b->kind = kind; 2734 b->addr = addr; 2735 b->spec = dbg_dup(s->env, spec, driver_strlen(spec), &b->spec_size); 2736 if (!b->spec) { 2737 dbg_errf(s, "out of memory"); 2738 return; 2739 } 2740 2741 if (dbg_bp_arm(s, b) != 0) { 2742 dbg_errf(s, "failed to arm breakpoint at 0x%llx", 2743 (unsigned long long)addr); 2744 b->session_id = 0; 2745 b->enabled = 0; 2746 } 2747 2748 s->nbps++; 2749 driver_printf( 2750 "Breakpoint %d at 0x%llx (%.*s)%.*s\n", b->id, (unsigned long long)addr, 2751 KIT_SLICE_ARG(kit_slice_cstr(spec)), 2752 KIT_SLICE_ARG(kit_slice_cstr(b->session_id ? "" : " [disarmed]"))); 2753 } 2754 2755 static void dbg_cmd_info_b(DbgState* s) { 2756 uint32_t i; 2757 if (s->nbps == 0) { 2758 driver_printf("No breakpoints.\n"); 2759 return; 2760 } 2761 driver_printf("Num Enb Address Skip Max Spec\n"); 2762 for (i = 0; i < s->nbps; ++i) { 2763 Bp* b = &s->bps[i]; 2764 driver_printf( 2765 "%-4d %-4s 0x%-18llx %-6llu %-6llu %.*s%.*s\n", b->id, 2766 b->enabled ? "y" : "n", (unsigned long long)b->addr, 2767 (unsigned long long)b->skip_count, (unsigned long long)b->max_hits, 2768 KIT_SLICE_ARG(kit_slice_cstr(b->spec)), 2769 KIT_SLICE_ARG(kit_slice_cstr(b->session_id ? "" : " [disarmed]"))); 2770 } 2771 } 2772 2773 static void dbg_cmd_ignore(DbgState* s, int id, uint64_t count) { 2774 Bp* b = dbg_bp_find(s, id); 2775 if (!b) { 2776 dbg_errf(s, "no breakpoint %d", id); 2777 return; 2778 } 2779 if (b->session_id) { 2780 kit_jit_session_breakpoint_clear(s->session, b->session_id); 2781 b->session_id = 0; 2782 } 2783 b->skip_count = count; 2784 if (b->enabled) { 2785 if (dbg_bp_arm(s, b) != 0) { 2786 dbg_errf(s, "failed to re-arm breakpoint %d", id); 2787 return; 2788 } 2789 } 2790 driver_printf("Breakpoint %d will skip the next %llu hits\n", id, 2791 (unsigned long long)count); 2792 } 2793 2794 static void dbg_cmd_delete(DbgState* s, int id) { 2795 if (dbg_bp_remove(s, id) != 0) { 2796 dbg_errf(s, "no breakpoint %d", id); 2797 } 2798 } 2799 2800 static void dbg_cmd_set_enabled(DbgState* s, int id, int enable) { 2801 Bp* b = dbg_bp_find(s, id); 2802 if (!b) { 2803 dbg_errf(s, "no breakpoint %d", id); 2804 return; 2805 } 2806 if (enable && !b->enabled) { 2807 if (dbg_bp_arm(s, b) != 0) { 2808 dbg_errf(s, "failed to re-arm breakpoint %d", id); 2809 return; 2810 } 2811 b->enabled = 1; 2812 } else if (!enable && b->enabled) { 2813 if (b->session_id) { 2814 kit_jit_session_breakpoint_clear(s->session, b->session_id); 2815 b->session_id = 0; 2816 } 2817 b->enabled = 0; 2818 } 2819 } 2820 2821 /* ============================================================ 2822 * Help 2823 * ============================================================ */ 2824 2825 static void dbg_cmd_help(void) { 2826 driver_printf( 2827 "%.*s", 2828 KIT_SLICE_ARG(KIT_SLICE_LIT( 2829 "Commands (abbrev. shown):\n" 2830 " h, help show this help\n" 2831 " q, quit exit (Ctrl-D also works)\n" 2832 " :language c|toy|asm|wasm/wat\n" 2833 " select language for jit/expr input\n" 2834 " r, run start fresh execution at entry\n" 2835 " c, cont continue after a stop\n" 2836 " s, step step to next source line (into " 2837 "calls)\n" 2838 " si, stepi single-step one instruction\n" 2839 " n, next step to next source line (over " 2840 "calls)\n" 2841 " finish run until current frame returns\n" 2842 " jit [LANG|NAME] { ... } compile and append a language " 2843 "snippet\n" 2844 " { ... } same as jit { ... }\n" 2845 " edit [LANG|NAME], e [...] edit and append a language snippet\n" 2846 " expr EXPR | expr { ... } compile and call an expression thunk\n" 2847 " EXPR same as expr EXPR\n" 2848 " LANG defaults to the selected " 2849 "language\n" 2850 " jump ADDR set PC to ADDR (no resume)\n" 2851 " bt, backtrace print stack trace with arguments\n" 2852 " b LOC set breakpoint at LOC:\n" 2853 " 0xADDR | sym[+off] | file.c:line\n" 2854 " ignore N COUNT skip the next COUNT hits of bp N\n" 2855 " d N, delete N delete breakpoint N\n" 2856 " enable N | disable N toggle breakpoint N\n" 2857 " p NAME print variable / global\n" 2858 " set NAME VALUE write VALUE into NAME\n" 2859 " x ADDR [count] examine memory (count bytes, default " 2860 "16)\n" 2861 " disasm [ADDR] [count], x/i disassemble at PC or ADDR\n" 2862 " list FILE:LINE, l FILE:LINE source listing around FILE:LINE\n" 2863 " info b list breakpoints\n" 2864 " info reg, info registers dump registers\n" 2865 " info locals list locals at current PC\n" 2866 " info args list args at current PC\n" 2867 " info functions [PATTERN] list JIT functions matching PATTERN\n" 2868 " info variables [PATTERN] list JIT globals matching " 2869 "PATTERN\n"))); 2870 } 2871 2872 static KitLanguage dbg_default_language_from_inputs(KitCompiler* c, 2873 const DbgOpts* o) { 2874 if (o->has_default_lang) return o->default_lang; 2875 if (o->inputs.nsources) return kit_language_for_path(c, o->inputs.sources[0]); 2876 if (o->inputs.nsource_memory) return o->inputs.source_memory[0].lang; 2877 return KIT_LANG_C; 2878 } 2879 2880 /* ============================================================ 2881 * Tokenizer / dispatch 2882 * ============================================================ */ 2883 2884 /* Trim leading whitespace and split off one whitespace-delimited word. 2885 * Returns the start of the next region (i.e. the rest of the line, with 2886 * its own leading whitespace skipped). The input buffer is mutated: 2887 * the byte after the first word is replaced with a NUL. */ 2888 static char* dbg_take_word(char* line, char** word_out) { 2889 char* p = line; 2890 char* w; 2891 while (*p && dbg_isspace((unsigned char)*p)) ++p; 2892 if (!*p) { 2893 *word_out = p; 2894 return p; 2895 } 2896 w = p; 2897 while (*p && !dbg_isspace((unsigned char)*p)) ++p; 2898 if (*p) { 2899 *p = '\0'; 2900 ++p; 2901 } 2902 while (*p && dbg_isspace((unsigned char)*p)) ++p; 2903 *word_out = w; 2904 return p; 2905 } 2906 2907 static int dbg_dispatch(DbgState* s, char* line) { 2908 char raw[LINE_CAP]; 2909 size_t raw_len = driver_strlen(line); 2910 char* cmd; 2911 char* rest; 2912 2913 if (raw_len >= sizeof(raw)) raw_len = sizeof(raw) - 1u; 2914 driver_memcpy(raw, line, raw_len); 2915 raw[raw_len] = '\0'; 2916 2917 rest = dbg_take_word(line, &cmd); 2918 2919 if (!*cmd) return 0; /* blank line */ 2920 2921 if (driver_streq(cmd, "h") || driver_streq(cmd, "help")) { 2922 dbg_cmd_help(); 2923 return 0; 2924 } 2925 if (driver_streq(cmd, ":language") || driver_streq(cmd, ":lang") || 2926 driver_streq(cmd, "language")) { 2927 dbg_cmd_language(s, rest); 2928 return 0; 2929 } 2930 if (driver_streq(cmd, "q") || driver_streq(cmd, "quit") || 2931 driver_streq(cmd, "exit")) { 2932 return 1; /* signal "exit REPL" */ 2933 } 2934 if (driver_streq(cmd, "r") || driver_streq(cmd, "run")) { 2935 dbg_drive(s, RUN_FRESH); 2936 return 0; 2937 } 2938 if (driver_streq(cmd, "abort")) { 2939 if (s->has_stop && s->session) { 2940 kit_jit_session_resume(s->session, KIT_RESUME_ABORT, NULL); 2941 s->has_stop = 0; 2942 dbg_errf(s, "execution aborted"); 2943 } else { 2944 dbg_errf(s, "nothing to abort"); 2945 } 2946 return 0; 2947 } 2948 if (driver_streq(cmd, "c") || driver_streq(cmd, "cont") || 2949 driver_streq(cmd, "continue")) { 2950 dbg_drive(s, RUN_CONTINUE); 2951 return 0; 2952 } 2953 if (driver_streq(cmd, "s") || driver_streq(cmd, "step")) { 2954 dbg_drive(s, RUN_STEP_LINE); 2955 return 0; 2956 } 2957 if (driver_streq(cmd, "si") || driver_streq(cmd, "stepi")) { 2958 dbg_drive(s, RUN_STEP_INSN); 2959 return 0; 2960 } 2961 if (driver_streq(cmd, "n") || driver_streq(cmd, "next")) { 2962 dbg_drive(s, RUN_NEXT_LINE); 2963 return 0; 2964 } 2965 if (driver_streq(cmd, "finish")) { 2966 dbg_drive(s, RUN_STEP_OUT); 2967 return 0; 2968 } 2969 if (driver_streq(cmd, "jit")) { 2970 dbg_cmd_jit(s, rest); 2971 return 0; 2972 } 2973 if (driver_streq(cmd, "edit") || driver_streq(cmd, "e")) { 2974 dbg_cmd_edit(s, rest); 2975 return 0; 2976 } 2977 if (driver_streq(cmd, "expr")) { 2978 if (!s->session) { 2979 dbg_errf(s, "no JIT session"); 2980 return 0; 2981 } 2982 dbg_cmd_expr(s, rest); 2983 return 0; 2984 } 2985 if (driver_streq(cmd, "bt") || driver_streq(cmd, "backtrace") || 2986 driver_streq(cmd, "where")) { 2987 dbg_cmd_bt(s); 2988 return 0; 2989 } 2990 if (driver_streq(cmd, "b") || driver_streq(cmd, "break")) { 2991 char* loc; 2992 dbg_take_word(rest, &loc); 2993 dbg_cmd_break(s, loc); 2994 return 0; 2995 } 2996 if (driver_streq(cmd, "info")) { 2997 char* what; 2998 rest = dbg_take_word(rest, &what); 2999 if (driver_streq(what, "b") || driver_streq(what, "break") || 3000 driver_streq(what, "breakpoints")) { 3001 dbg_cmd_info_b(s); 3002 } else if (driver_streq(what, "reg") || driver_streq(what, "registers")) { 3003 dbg_cmd_info_reg(s); 3004 } else if (driver_streq(what, "locals")) { 3005 dbg_cmd_info_vars(s, 1u << KIT_DVR_LOCAL, "locals"); 3006 } else if (driver_streq(what, "args")) { 3007 dbg_cmd_info_vars(s, 1u << KIT_DVR_ARG, "args"); 3008 } else if (driver_streq(what, "functions") || driver_streq(what, "func")) { 3009 char* pat; 3010 dbg_take_word(rest, &pat); 3011 dbg_cmd_info_syms(s, KIT_SK_FUNC, *pat ? pat : NULL); 3012 } else if (driver_streq(what, "variables") || driver_streq(what, "var")) { 3013 char* pat; 3014 dbg_take_word(rest, &pat); 3015 dbg_cmd_info_syms(s, KIT_SK_OBJ, *pat ? pat : NULL); 3016 } else { 3017 dbg_errf(s, "unknown 'info' subcommand: %.*s", 3018 KIT_SLICE_ARG(kit_slice_cstr(what))); 3019 } 3020 return 0; 3021 } 3022 if (driver_streq(cmd, "set")) { 3023 char* name; 3024 char* val_s; 3025 uint64_t v; 3026 size_t used; 3027 rest = dbg_take_word(rest, &name); 3028 if (!*name) { 3029 dbg_errf(s, "usage: set NAME VALUE"); 3030 return 0; 3031 } 3032 /* Accept an optional `=` between name and value: `set x = 5`. */ 3033 if (driver_streq(name, "=")) { 3034 dbg_errf(s, "usage: set NAME VALUE"); 3035 return 0; 3036 } 3037 rest = dbg_take_word(rest, &val_s); 3038 if (driver_streq(val_s, "=")) { 3039 rest = dbg_take_word(rest, &val_s); 3040 } 3041 if (!*val_s) { 3042 dbg_errf(s, "usage: set NAME VALUE"); 3043 return 0; 3044 } 3045 used = dbg_parse_uint(val_s, &v); 3046 if (!used || val_s[used] != '\0') { 3047 dbg_errf(s, "expected integer value, got '%.*s'", 3048 KIT_SLICE_ARG(kit_slice_cstr(val_s))); 3049 return 0; 3050 } 3051 dbg_cmd_set(s, name, v); 3052 return 0; 3053 } 3054 if (driver_streq(cmd, "jump") || driver_streq(cmd, "j")) { 3055 char* addr_s; 3056 uint64_t addr; 3057 size_t used; 3058 dbg_take_word(rest, &addr_s); 3059 if (!*addr_s) { 3060 dbg_errf(s, "usage: jump ADDR"); 3061 return 0; 3062 } 3063 used = dbg_parse_uint(addr_s, &addr); 3064 if (!used || addr_s[used] != '\0') { 3065 dbg_errf(s, "bad address '%.*s'", 3066 KIT_SLICE_ARG(kit_slice_cstr(addr_s))); 3067 return 0; 3068 } 3069 dbg_cmd_jump(s, addr); 3070 return 0; 3071 } 3072 if (driver_streq(cmd, "ignore")) { 3073 char* id_s; 3074 char* cnt_s; 3075 uint64_t id; 3076 uint64_t cnt; 3077 size_t used; 3078 rest = dbg_take_word(rest, &id_s); 3079 dbg_take_word(rest, &cnt_s); 3080 if (!*id_s || !*cnt_s) { 3081 dbg_errf(s, "usage: ignore N COUNT"); 3082 return 0; 3083 } 3084 used = dbg_parse_uint(id_s, &id); 3085 if (!used || id_s[used] != '\0') { 3086 dbg_errf(s, "expected breakpoint id"); 3087 return 0; 3088 } 3089 used = dbg_parse_uint(cnt_s, &cnt); 3090 if (!used || cnt_s[used] != '\0') { 3091 dbg_errf(s, "expected hit count"); 3092 return 0; 3093 } 3094 dbg_cmd_ignore(s, (int)id, cnt); 3095 return 0; 3096 } 3097 if (driver_streq(cmd, "d") || driver_streq(cmd, "delete")) { 3098 char* arg; 3099 uint64_t id; 3100 size_t used; 3101 dbg_take_word(rest, &arg); 3102 if (!*arg) { 3103 dbg_errf(s, "usage: d <id>"); 3104 return 0; 3105 } 3106 used = dbg_parse_uint(arg, &id); 3107 if (!used || arg[used] != '\0') { 3108 dbg_errf(s, "expected breakpoint id"); 3109 return 0; 3110 } 3111 dbg_cmd_delete(s, (int)id); 3112 return 0; 3113 } 3114 if (driver_streq(cmd, "enable") || driver_streq(cmd, "disable")) { 3115 char* arg; 3116 uint64_t id; 3117 size_t used; 3118 dbg_take_word(rest, &arg); 3119 used = dbg_parse_uint(arg, &id); 3120 if (!used || arg[used] != '\0') { 3121 dbg_errf(s, "expected breakpoint id"); 3122 return 0; 3123 } 3124 dbg_cmd_set_enabled(s, (int)id, driver_streq(cmd, "enable")); 3125 return 0; 3126 } 3127 if (driver_streq(cmd, "p") || driver_streq(cmd, "print")) { 3128 char* name; 3129 dbg_take_word(rest, &name); 3130 if (!*name) { 3131 dbg_errf(s, "usage: p <name>"); 3132 return 0; 3133 } 3134 dbg_cmd_print(s, name); 3135 return 0; 3136 } 3137 if (driver_streq(cmd, "list") || driver_streq(cmd, "l")) { 3138 char* loc; 3139 dbg_take_word(rest, &loc); 3140 if (!*loc) { 3141 dbg_errf(s, "usage: list file:line"); 3142 return 0; 3143 } 3144 dbg_cmd_list(s, loc); 3145 return 0; 3146 } 3147 if (driver_streq(cmd, "disasm") || driver_streq(cmd, "x/i")) { 3148 char* addr_s; 3149 char* count_s; 3150 uint64_t addr = s->has_stop ? s->last_stop.regs.pc : 0; 3151 uint64_t count = 8; 3152 size_t used; 3153 rest = dbg_take_word(rest, &addr_s); 3154 if (*addr_s) { 3155 used = dbg_parse_uint(addr_s, &addr); 3156 if (!used || addr_s[used] != '\0') { 3157 dbg_errf(s, "bad address '%.*s'", 3158 KIT_SLICE_ARG(kit_slice_cstr(addr_s))); 3159 return 0; 3160 } 3161 dbg_take_word(rest, &count_s); 3162 if (*count_s) { 3163 used = dbg_parse_uint(count_s, &count); 3164 if (!used || count_s[used] != '\0') { 3165 dbg_errf(s, "bad count '%.*s'", 3166 KIT_SLICE_ARG(kit_slice_cstr(count_s))); 3167 return 0; 3168 } 3169 } 3170 } 3171 dbg_cmd_disasm(s, addr, (size_t)count); 3172 return 0; 3173 } 3174 if (driver_streq(cmd, "x") || driver_streq(cmd, "examine")) { 3175 char* addr_s; 3176 char* count_s; 3177 uint64_t addr; 3178 uint64_t count = 16; 3179 size_t used; 3180 rest = dbg_take_word(rest, &addr_s); 3181 if (!*addr_s) { 3182 dbg_errf(s, "usage: x <addr> [count]"); 3183 return 0; 3184 } 3185 used = dbg_parse_uint(addr_s, &addr); 3186 if (!used || addr_s[used] != '\0') { 3187 dbg_errf(s, "bad address '%.*s'", 3188 KIT_SLICE_ARG(kit_slice_cstr(addr_s))); 3189 return 0; 3190 } 3191 dbg_take_word(rest, &count_s); 3192 if (*count_s) { 3193 used = dbg_parse_uint(count_s, &count); 3194 if (!used || count_s[used] != '\0') { 3195 dbg_errf(s, "bad count '%.*s'", 3196 KIT_SLICE_ARG(kit_slice_cstr(count_s))); 3197 return 0; 3198 } 3199 } 3200 dbg_cmd_examine(s, addr, (size_t)count); 3201 return 0; 3202 } 3203 3204 if (cmd[0] == '{') { 3205 dbg_cmd_jit(s, raw); 3206 return 0; 3207 } 3208 3209 if (s->session) { 3210 dbg_cmd_expr(s, raw); 3211 } else { 3212 dbg_errf(s, "unknown command: %.*s (try 'h')", 3213 KIT_SLICE_ARG(kit_slice_cstr(cmd))); 3214 } 3215 return 0; 3216 } 3217 3218 /* ============================================================ 3219 * Completion 3220 * ============================================================ */ 3221 3222 static int dbg_slice_has_prefix(KitSlice s, const char* prefix, 3223 size_t prefix_len) { 3224 return s.len >= prefix_len && memcmp(s.s, prefix, prefix_len) == 0; 3225 } 3226 3227 static int dbg_cstr_has_prefix(const char* s, const char* prefix, 3228 size_t prefix_len) { 3229 return driver_strlen(s) >= prefix_len && memcmp(s, prefix, prefix_len) == 0; 3230 } 3231 3232 static int dbg_completion_seen(DriverLineCompletionList* out, const char* text, 3233 size_t len) { 3234 uint32_t i; 3235 for (i = 0; i < out->count; ++i) { 3236 if (driver_strlen(out->items[i].text) == len && 3237 memcmp(out->items[i].text, text, len) == 0) 3238 return 1; 3239 } 3240 return 0; 3241 } 3242 3243 static void dbg_completion_add_cstr(DriverLineCompletionList* out, 3244 const char* prefix, size_t prefix_len, 3245 const char* text) { 3246 size_t len = driver_strlen(text); 3247 if (!dbg_cstr_has_prefix(text, prefix, prefix_len)) return; 3248 if (dbg_completion_seen(out, text, len)) return; 3249 (void)driver_line_completion_add(out, text, len); 3250 } 3251 3252 static void dbg_completion_add_slice(DriverLineCompletionList* out, 3253 const char* prefix, size_t prefix_len, 3254 KitSlice text) { 3255 if (!text.s || !dbg_slice_has_prefix(text, prefix, prefix_len)) return; 3256 if (dbg_completion_seen(out, text.s, text.len)) return; 3257 (void)driver_line_completion_add(out, text.s, text.len); 3258 } 3259 3260 static void dbg_completion_add_u64(DriverLineCompletionList* out, 3261 const char* prefix, size_t prefix_len, 3262 uint64_t v) { 3263 char buf[32]; 3264 size_t n = 0; 3265 char rev[32]; 3266 size_t r = 0; 3267 if (v == 0) { 3268 rev[r++] = '0'; 3269 } else { 3270 while (v && r < sizeof(rev)) { 3271 rev[r++] = (char)('0' + (v % 10u)); 3272 v /= 10u; 3273 } 3274 } 3275 while (r > 0 && n + 1u < sizeof(buf)) buf[n++] = rev[--r]; 3276 buf[n] = '\0'; 3277 dbg_completion_add_cstr(out, prefix, prefix_len, buf); 3278 } 3279 3280 static void dbg_word_bounds(const char* line, size_t cursor, size_t* start, 3281 size_t* end) { 3282 size_t len = driver_strlen(line); 3283 size_t s = cursor < len ? cursor : len; 3284 size_t e = s; 3285 while (s > 0 && !dbg_isspace((unsigned char)line[s - 1])) --s; 3286 while (e < len && !dbg_isspace((unsigned char)line[e])) ++e; 3287 *start = s; 3288 *end = e; 3289 } 3290 3291 static size_t dbg_read_word_at(const char* line, size_t start, char* out, 3292 size_t cap) { 3293 size_t i = start; 3294 size_t n = 0; 3295 while (line[i] && dbg_isspace((unsigned char)line[i])) ++i; 3296 while (line[i] && !dbg_isspace((unsigned char)line[i])) { 3297 if (n + 1u < cap) out[n++] = line[i]; 3298 ++i; 3299 } 3300 if (cap) out[n] = '\0'; 3301 return n; 3302 } 3303 3304 static void dbg_complete_commands(DriverLineCompletionList* out, 3305 const char* prefix, size_t prefix_len) { 3306 static const char* const cmds[] = { 3307 "help", "quit", "exit", "run", "cont", "continue", 3308 "step", "stepi", "next", "finish", "jit", "edit", 3309 "expr", "bt", "backtrace", "where", "break", "info", 3310 "ignore", "delete", "enable", "disable", "print", "set", 3311 "jump", "list", "disasm", "x", "x/i", ":language", 3312 ":lang", "language", "abort", "h", "q", "r", 3313 "c", "s", "si", "n", "b", "d", 3314 "p", "l", "e", 3315 }; 3316 size_t i; 3317 for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); ++i) 3318 dbg_completion_add_cstr(out, prefix, prefix_len, cmds[i]); 3319 } 3320 3321 static void dbg_complete_info(DriverLineCompletionList* out, const char* prefix, 3322 size_t prefix_len) { 3323 static const char* const words[] = { 3324 "b", "break", "breakpoints", "reg", "registers", "locals", 3325 "args", "functions", "func", "variables", "var", 3326 }; 3327 size_t i; 3328 for (i = 0; i < sizeof(words) / sizeof(words[0]); ++i) 3329 dbg_completion_add_cstr(out, prefix, prefix_len, words[i]); 3330 } 3331 3332 static void dbg_complete_languages(DriverLineCompletionList* out, 3333 const char* prefix, size_t prefix_len) { 3334 static const char* const langs[] = {"c", "toy", "asm", "wasm", "wat"}; 3335 size_t i; 3336 for (i = 0; i < sizeof(langs) / sizeof(langs[0]); ++i) 3337 dbg_completion_add_cstr(out, prefix, prefix_len, langs[i]); 3338 } 3339 3340 static void dbg_complete_symbols(DbgState* s, DriverLineCompletionList* out, 3341 const char* prefix, size_t prefix_len, 3342 int funcs, int objects) { 3343 KitJitSymIter* it = NULL; 3344 KitJitSym sym; 3345 if (!s->jit || kit_jit_sym_iter_new(s->jit, &it) != KIT_OK) return; 3346 for (;;) { 3347 KitIterResult r = kit_jit_sym_iter_next(it, &sym); 3348 if (r != KIT_ITER_ITEM) break; 3349 if ((sym.kind == KIT_SK_FUNC && funcs) || 3350 (sym.kind == KIT_SK_OBJ && objects)) 3351 dbg_completion_add_slice(out, prefix, prefix_len, sym.name); 3352 } 3353 kit_jit_sym_iter_free(it); 3354 } 3355 3356 static void dbg_complete_locals(DbgState* s, DriverLineCompletionList* out, 3357 const char* prefix, size_t prefix_len) { 3358 KitDwarfVarIter* it = NULL; 3359 KitDwarfVar v; 3360 if (!s->has_stop || !s->dwarf) return; 3361 if (kit_dwarf_vars_at_new(s->dwarf, dbg_pc_rt_to_img(s, s->last_stop.regs.pc), 3362 KIT_DVRM_LOCAL | KIT_DVRM_ARG, &it) != KIT_OK) 3363 return; 3364 for (;;) { 3365 KitIterResult r = kit_dwarf_vars_at_next(it, &v); 3366 if (r != KIT_ITER_ITEM) break; 3367 dbg_completion_add_slice(out, prefix, prefix_len, v.name); 3368 } 3369 kit_dwarf_vars_at_free(it); 3370 } 3371 3372 static void dbg_complete_files(DbgState* s, DriverLineCompletionList* out, 3373 const char* prefix, size_t prefix_len) { 3374 KitDwarfCuIter* cui = NULL; 3375 KitDwarfCu cu; 3376 if (!s->dwarf) return; 3377 if (kit_dwarf_cu_iter_new(s->dwarf, &cui) != KIT_OK) return; 3378 for (;;) { 3379 KitDwarfLineIter* li = NULL; 3380 KitDwarfLineRow row; 3381 KitIterResult cr = kit_dwarf_cu_iter_next(cui, &cu); 3382 if (cr != KIT_ITER_ITEM) break; 3383 if (kit_dwarf_line_iter_new(s->dwarf, cu.offset, &li) != KIT_OK) continue; 3384 for (;;) { 3385 KitSlice file = KIT_SLICE_NULL; 3386 KitIterResult lr = kit_dwarf_line_iter_next(li, &row); 3387 if (lr != KIT_ITER_ITEM) break; 3388 if (kit_dwarf_line_file(s->dwarf, cu.offset, row.file_index, &file) == 3389 KIT_OK) 3390 dbg_completion_add_slice(out, prefix, prefix_len, file); 3391 } 3392 kit_dwarf_line_iter_free(li); 3393 } 3394 kit_dwarf_cu_iter_free(cui); 3395 } 3396 3397 static void dbg_complete_breakpoint_ids(DbgState* s, 3398 DriverLineCompletionList* out, 3399 const char* prefix, size_t prefix_len) { 3400 uint32_t i; 3401 for (i = 0; i < s->nbps; ++i) 3402 dbg_completion_add_u64(out, prefix, prefix_len, (uint64_t)s->bps[i].id); 3403 } 3404 3405 static void dbg_complete(void* user, const char* line, size_t cursor, 3406 DriverLineCompletionList* out) { 3407 DbgState* s = (DbgState*)user; 3408 char cmd[WORD_CAP]; 3409 char arg1[WORD_CAP]; 3410 size_t start, end; 3411 size_t prefix_len; 3412 const char* prefix; 3413 3414 dbg_word_bounds(line, cursor, &start, &end); 3415 out->replace_start = start; 3416 out->replace_end = end; 3417 prefix = line + start; 3418 prefix_len = cursor > start ? cursor - start : 0; 3419 3420 dbg_read_word_at(line, 0, cmd, sizeof(cmd)); 3421 if (start == 0 || cmd[0] == '\0') { 3422 dbg_complete_commands(out, prefix, prefix_len); 3423 return; 3424 } 3425 3426 if (driver_streq(cmd, "info")) { 3427 dbg_read_word_at(line, start == 0 ? 0 : driver_strlen(cmd), arg1, 3428 sizeof(arg1)); 3429 if (arg1[0] == '\0' || start <= driver_strlen(cmd) + 1u) { 3430 dbg_complete_info(out, prefix, prefix_len); 3431 return; 3432 } 3433 } 3434 3435 if (driver_streq(cmd, ":language") || driver_streq(cmd, ":lang") || 3436 driver_streq(cmd, "language")) { 3437 dbg_complete_languages(out, prefix, prefix_len); 3438 return; 3439 } 3440 if (driver_streq(cmd, "jit") || driver_streq(cmd, "edit") || 3441 driver_streq(cmd, "e")) { 3442 dbg_complete_languages(out, prefix, prefix_len); 3443 dbg_complete_symbols(s, out, prefix, prefix_len, 1, 0); 3444 return; 3445 } 3446 if (driver_streq(cmd, "b") || driver_streq(cmd, "break")) { 3447 dbg_complete_symbols(s, out, prefix, prefix_len, 1, 0); 3448 dbg_complete_files(s, out, prefix, prefix_len); 3449 return; 3450 } 3451 if (driver_streq(cmd, "list") || driver_streq(cmd, "l")) { 3452 dbg_complete_files(s, out, prefix, prefix_len); 3453 return; 3454 } 3455 if (driver_streq(cmd, "p") || driver_streq(cmd, "print") || 3456 driver_streq(cmd, "set")) { 3457 dbg_complete_locals(s, out, prefix, prefix_len); 3458 dbg_complete_symbols(s, out, prefix, prefix_len, 0, 1); 3459 return; 3460 } 3461 if (driver_streq(cmd, "d") || driver_streq(cmd, "delete") || 3462 driver_streq(cmd, "enable") || driver_streq(cmd, "disable") || 3463 driver_streq(cmd, "ignore")) { 3464 dbg_complete_breakpoint_ids(s, out, prefix, prefix_len); 3465 return; 3466 } 3467 3468 dbg_complete_locals(s, out, prefix, prefix_len); 3469 dbg_complete_symbols(s, out, prefix, prefix_len, 1, 1); 3470 } 3471 3472 /* ============================================================ 3473 * Script source helpers 3474 * ============================================================ */ 3475 3476 /* Execute a single command string as if typed at the REPL. 3477 * Returns 1 if the REPL should exit (quit command), 0 otherwise. */ 3478 static int dbg_run_script_cmd(DbgState* s, const char* cmd) { 3479 char line[LINE_CAP]; 3480 size_t n = driver_strlen(cmd); 3481 if (n >= LINE_CAP) n = LINE_CAP - 1; 3482 driver_memcpy(line, cmd, n); 3483 line[n] = '\0'; 3484 return dbg_dispatch(s, line); 3485 } 3486 3487 /* Execute debugger commands from a file, one per line. 3488 * Returns 1 if the REPL should exit (quit command), 0 otherwise. */ 3489 static int dbg_run_script_file(DbgState* s, const char* path) { 3490 DriverLoad load = {0}; 3491 KitSlice bytes; 3492 const char* p; 3493 const char* end; 3494 char line[LINE_CAP]; 3495 if (driver_load_bytes(&s->env->file_io, DBG_TOOL, path, &load, &bytes) != 0) 3496 return 0; /* driver_load_bytes already emitted an error */ 3497 p = (const char*)bytes.data; 3498 end = p + bytes.len; 3499 while (p < end) { 3500 const char* nl = p; 3501 size_t len; 3502 while (nl < end && *nl != '\n') nl++; 3503 len = (size_t)(nl - p); 3504 /* Strip trailing carriage return. */ 3505 if (len > 0 && p[len - 1] == '\r') len--; 3506 if (len >= LINE_CAP) len = LINE_CAP - 1; 3507 driver_memcpy(line, p, len); 3508 line[len] = '\0'; 3509 p = (nl < end) ? nl + 1 : end; 3510 if (dbg_dispatch(s, line)) { 3511 driver_release_bytes(&s->env->file_io, &load); 3512 return 1; 3513 } 3514 } 3515 driver_release_bytes(&s->env->file_io, &load); 3516 return 0; 3517 } 3518 3519 /* ============================================================ 3520 * REPL 3521 * ============================================================ */ 3522 3523 static void dbg_repl(DbgState* s) { 3524 char line[LINE_CAP]; 3525 uint32_t i; 3526 3527 if (!s->batch_mode) driver_printf("kit dbg — 'h' for help, 'q' to quit\n"); 3528 3529 /* Phase 1: drain --script / --command sources in order. */ 3530 for (i = 0; i < s->nscript_entries; i++) { 3531 DbgScriptEntry* e = &s->script_entries[i]; 3532 int quit = (e->kind == DBG_ENTRY_FILE) 3533 ? dbg_run_script_file(s, e->value) 3534 : dbg_run_script_cmd(s, e->value); 3535 if (quit) return; 3536 } 3537 3538 /* Phase 2: in --batch mode, exit without falling through to stdin. */ 3539 if (s->batch_mode) return; 3540 3541 /* Phase 3: interactive loop. */ 3542 for (;;) { 3543 int n; 3544 n = driver_read_line_edit(s->env, "(kit) ", line, sizeof(line), 3545 &s->line_history, dbg_complete, s); 3546 if (n == 0) { /* EOF — Ctrl-D */ 3547 driver_printf("\n"); 3548 return; 3549 } 3550 if (n == -1) { 3551 dbg_errf(s, "stdin read error"); 3552 return; 3553 } 3554 if (n == -2) { /* SIGINT during prompt */ 3555 driver_printf("\n"); 3556 continue; 3557 } 3558 if (dbg_dispatch(s, line)) return; 3559 } 3560 } 3561 3562 /* ============================================================ 3563 * Top-level entry 3564 * ============================================================ */ 3565 3566 int driver_dbg(int argc, char** argv) { 3567 DriverEnv env; 3568 DbgOpts o = {0}; 3569 KitCompiler* compiler = NULL; 3570 KitTarget* target = NULL; 3571 KitJit* jit = NULL; 3572 DbgState st = {0}; 3573 KitContext ctx; 3574 KitJitHost jhost; 3575 KitDbgHost dhost; 3576 int rc; 3577 3578 if (driver_argv_wants_help(argc, argv, 1)) { 3579 driver_help_dbg(); 3580 return 0; 3581 } 3582 3583 driver_env_init(&env); 3584 o.env = &env; 3585 3586 if (dbg_parse(argc, argv, &o) != 0) { 3587 dbg_options_release(&o); 3588 driver_env_fini(&env); 3589 return 2; 3590 } 3591 3592 ctx = driver_env_to_context(&env); 3593 jhost = driver_env_to_jit_host(&env); 3594 dhost = driver_env_to_dbg_host(&env); 3595 { 3596 KitTargetOptions topts; 3597 memset(&topts, 0, sizeof topts); 3598 topts.spec = driver_host_target(); 3599 if (kit_target_new(&ctx, &topts, &target) != KIT_OK || 3600 driver_compiler_new(target, &ctx, &compiler) != KIT_OK) { 3601 driver_errf(DBG_TOOL, "failed to initialize compiler"); 3602 kit_target_free(target); 3603 dbg_options_release(&o); 3604 driver_env_fini(&env); 3605 return 1; 3606 } 3607 } 3608 3609 rc = dbg_compile_and_jit(&o, compiler, &jhost, &jit); 3610 if (rc != 0) { 3611 driver_compiler_free(compiler); 3612 kit_target_free(target); 3613 dbg_options_release(&o); 3614 driver_env_fini(&env); 3615 return rc; 3616 } 3617 3618 st.env = &env; 3619 st.compiler = compiler; 3620 st.ctx = ctx; 3621 dbg_fill_compile_options(&o, &st.copts, &st.pp); 3622 st.jit = jit; 3623 st.default_jit_lang = dbg_default_language_from_inputs(compiler, &o); 3624 st.default_jit_name = dbg_jit_default_name( 3625 st.compiler, st.default_jit_lang, st.default_jit_name_buf, 3626 sizeof st.default_jit_name_buf); 3627 st.prog_argc = (int)o.prog_argc; 3628 st.prog_argv = o.prog_argv; 3629 st.entry_name = o.entry; 3630 st.script_entries = o.script_entries; 3631 st.nscript_entries = o.nscript_entries; 3632 st.batch_mode = o.batch_mode; 3633 3634 if (driver_inputs_count(&o.inputs) != 0) { 3635 st.entry_addr = kit_jit_lookup(jit, kit_slice_cstr(o.entry)); 3636 if (!st.entry_addr) { 3637 driver_errf(DBG_TOOL, "entry symbol not found: %.*s", 3638 KIT_SLICE_ARG(kit_slice_cstr(o.entry))); 3639 kit_jit_free(jit); 3640 driver_compiler_free(compiler); 3641 kit_target_free(target); 3642 dbg_options_release(&o); 3643 driver_env_fini(&env); 3644 return 1; 3645 } 3646 } 3647 3648 if (kit_jit_session_new(jit, &dhost, &st.session) != KIT_OK) { 3649 driver_errf(DBG_TOOL, 3650 "JIT session not yet implemented in libkit — " 3651 "REPL will start in degraded mode (commands will surface " 3652 "'session implementation pending' until the lib lands)"); 3653 st.session = NULL; 3654 /* Keep going so the surrounding driver path is exercised. */ 3655 } 3656 3657 st.view = kit_jit_view(jit); 3658 if (st.view) { 3659 if (kit_dwarf_open(&ctx, st.view, &st.dwarf) != KIT_OK) st.dwarf = NULL; 3660 if (st.dwarf && st.session) { 3661 kit_jit_session_attach_dwarf(st.session, st.dwarf); 3662 } 3663 } 3664 3665 dbg_repl(&st); 3666 3667 driver_line_history_fini(&env, &st.line_history); 3668 dbg_bps_release_all(&st); 3669 dbg_compile_sessions_release(&st); 3670 dbg_sources_release_all(&st); 3671 if (st.dwarf) kit_dwarf_free(st.dwarf); 3672 if (st.session) kit_jit_session_free(st.session); 3673 kit_jit_free(jit); 3674 driver_compiler_free(compiler); 3675 kit_target_free(target); 3676 dbg_options_release(&o); 3677 driver_env_fini(&env); 3678 return (st.batch_mode && st.error_count > 0) ? 1 : 0; 3679 }