symbolic.c (28985B)
1 /* Symbolic inspection layer over a stopped KitDebugSession. 2 * 3 * The control substrate (session.c/bp.c/step.c/mem.c) moves bytes and raw 4 * registers. This TU composes that substrate with the session's attached DWARF 5 * (s->dwarf) and JIT image (s->jit) into the operations an interactive debugger 6 * performs: PC symbolization, frame-pointer backtraces, typed variable values 7 * with navigation, scope enumeration, location resolution, and disassembly at 8 * the stopped PC. 9 * 10 * Two pieces of glue every caller would otherwise repeat live here, once: 11 * - address-space translation: DWARF queries key off image vaddrs while the 12 * session reads/writes runtime addresses (sym_pc_rt_to_img / _img_to_rt / 13 * sym_translate_loc); 14 * - the memory provider: kit_dwarf_loc_read wants a KitDwarfReadMemFn, which 15 * here just forwards into the session (sym_read_mem). 16 * 17 * KitDebugValue byte storage comes from the session's stop-epoch arena 18 * (s->values), reset by session.c on every call/resume. Backtraces and variable 19 * iterators are heap-allocated cursors with explicit frees; the KitSlice names 20 * they expose borrow from the DWARF / JIT image. */ 21 22 #include <stdarg.h> 23 #include <stdio.h> 24 #include <string.h> 25 26 #include "dbg/dbg.h" 27 28 /* ---- address-space + memory glue ------------------------------------- */ 29 30 static uint64_t sym_pc_rt_to_img(KitDebugSession* s, uint64_t rt) { 31 uint64_t v = kit_jit_runtime_to_image(s->jit, rt); 32 return v ? v : rt; 33 } 34 35 static uint64_t sym_pc_img_to_rt(KitDebugSession* s, uint64_t img) { 36 uint64_t v = kit_jit_image_to_runtime(s->jit, img); 37 return v ? v : img; 38 } 39 40 /* Only DLOC_GLOBAL carries an absolute address straight from .debug_info; the 41 * other kinds derive their effective address from live (runtime) register 42 * state or are evaluated against the frame. */ 43 static void sym_translate_loc(KitDebugSession* s, KitDwarfVarLoc* loc) { 44 if (loc && loc->kind == KIT_DLOC_GLOBAL) 45 loc->v.global = sym_pc_img_to_rt(s, loc->v.global); 46 } 47 48 static KitStatus sym_read_mem(void* user, uint64_t addr, void* dst, size_t n) { 49 return kit_dbg_session_read_mem((KitDebugSession*)user, addr, dst, n); 50 } 51 52 /* ---- little-endian scalar loads -------------------------------------- */ 53 54 static uint64_t sym_load_u(const uint8_t* b, size_t n) { 55 uint64_t v = 0; 56 size_t i; 57 for (i = 0; i < n && i < 8; ++i) v |= ((uint64_t)b[i]) << (8 * i); 58 return v; 59 } 60 61 static int64_t sym_load_s(const uint8_t* b, size_t n) { 62 uint64_t v = sym_load_u(b, n); 63 if (n > 0 && n < 8) { 64 uint64_t sign = (uint64_t)1 << (8 * n - 1); 65 if (v & sign) v |= ~((sign << 1) - 1); 66 } 67 return (int64_t)v; 68 } 69 70 /* ---- per-arch frame-pointer walk knobs -------------------------------- */ 71 72 static int sym_fp_reg(KitArchKind a) { 73 switch (a) { 74 case KIT_ARCH_ARM_64: 75 return 29; 76 case KIT_ARCH_X86_64: 77 return 6; 78 case KIT_ARCH_RV32: 79 case KIT_ARCH_RV64: 80 return 8; 81 default: 82 return -1; 83 } 84 } 85 86 static int sym_ptr_size(KitArchKind a) { 87 switch (a) { 88 case KIT_ARCH_ARM_64: 89 case KIT_ARCH_X86_64: 90 case KIT_ARCH_RV64: 91 return 8; 92 case KIT_ARCH_RV32: 93 return 4; 94 default: 95 return 0; 96 } 97 } 98 99 /* Advance `fr` to its caller via the uniform fp record (fp[0]=caller fp, 100 * fp[1]=saved return address). Returns 1 on a valid in-image caller, 0 at the 101 * chain terminator / image boundary / garbage. */ 102 static int sym_unwind_next(KitDebugSession* s, KitUnwindFrame* fr, 103 int fpreg, int ptr) { 104 uint64_t fp, ra = 0, nfp = 0, align; 105 if (fpreg < 0 || ptr <= 0) return 0; 106 fp = fr->regs[fpreg]; 107 if (fp == 0) return 0; 108 align = (uint64_t)ptr - 1u; 109 if (fp & align) return 0; 110 if (kit_dbg_session_read_mem(s, fp + (uint64_t)ptr, &ra, (size_t)ptr) != KIT_OK) 111 return 0; 112 if (kit_dbg_session_read_mem(s, fp, &nfp, (size_t)ptr) != KIT_OK) return 0; 113 if (ra == 0) return 0; 114 if (nfp <= fp) return 0; 115 if (nfp & align) return 0; 116 if (kit_jit_runtime_to_image(s->jit, ra) == 0) return 0; /* left the image */ 117 fr->pc = ra; 118 fr->regs[fpreg] = nfp; 119 fr->cfa = nfp + 2u * (uint64_t)ptr; /* just above the saved pair */ 120 return 1; 121 } 122 123 /* ---- single-PC symbolization ----------------------------------------- */ 124 125 static void sym_describe(KitJit* jit, KitDebugInfo* dwarf, uint64_t pc, 126 KitDebugFrame* f) { 127 /* Image vaddr for DWARF queries; fall back to the runtime pc when the image 128 * translation yields 0 (it overloads 0 as "not in image", which also covers 129 * a symbol sitting exactly at the image base). in_image is reported for the 130 * caller's benefit (e.g. a crash reporter suppressing foreign frames) but is 131 * NOT used to gate symbolization: kit_jit_addr_to_sym already returns nothing 132 * for an address its table does not cover. */ 133 uint64_t v = jit ? kit_jit_runtime_to_image(jit, pc) : 0; 134 uint64_t img = v ? v : pc; 135 f->pc = pc; 136 f->in_image = jit ? (v != 0) : true; 137 138 if (jit) { 139 KitSlice sym = KIT_SLICE_NULL; 140 uint64_t off = 0; 141 if (kit_jit_addr_to_sym(jit, pc, &sym, &off) == KIT_OK && sym.s) { 142 f->sym = sym; 143 f->sym_offset = off; 144 } 145 } 146 if (dwarf) { 147 KitDwarfSubprogram sp; 148 KitSlice file = KIT_SLICE_NULL; 149 uint32_t line = 0, col = 0; 150 if (kit_dwarf_subprogram_at(dwarf, img, &sp) == KIT_OK && sp.name.s) { 151 f->func = sp.name; 152 f->inlined = sp.inlined; 153 f->func_offset = (img >= sp.low_pc) ? (img - sp.low_pc) : 0; 154 } 155 if (kit_dwarf_addr_to_line(dwarf, img, &file, &line, &col) == KIT_OK && 156 file.s) { 157 f->file = file; 158 f->line = line; 159 f->col = col; 160 } 161 } 162 } 163 164 KitStatus kit_dbg_symbolize_pc(KitJit* jit, KitDebugInfo* dwarf, uint64_t pc, 165 KitDebugFrame* out) { 166 if (!jit || !out) return KIT_INVALID; 167 memset(out, 0, sizeof(*out)); 168 sym_describe(jit, dwarf, pc, out); 169 return KIT_OK; 170 } 171 172 /* ---- backtrace -------------------------------------------------------- */ 173 174 struct KitDebugBacktrace { 175 Heap* heap; 176 KitDebugFrame* frames; 177 uint32_t count; 178 }; 179 180 #define SYM_BT_MAX 256u 181 182 KitStatus kit_dbg_backtrace_new(KitDebugSession* s, const KitUnwindFrame* top, 183 KitDebugBacktrace** out) { 184 KitArchKind arch; 185 int fpreg, ptr; 186 KitUnwindFrame walk, start; 187 KitDebugBacktrace* bt; 188 uint32_t n, i; 189 190 if (!s || !out) return KIT_INVALID; 191 *out = NULL; 192 arch = kit_jit_image_arch(s->jit); 193 fpreg = sym_fp_reg(arch); 194 ptr = sym_ptr_size(arch); 195 start = top ? *top : s->stop.regs; 196 197 /* Pass 1: count the chain (bounded). */ 198 n = 1; 199 walk = start; 200 while (n < SYM_BT_MAX && sym_unwind_next(s, &walk, fpreg, ptr)) ++n; 201 202 bt = (KitDebugBacktrace*)s->heap->alloc(s->heap, sizeof(*bt), _Alignof(KitDebugBacktrace)); 203 if (!bt) return KIT_NOMEM; 204 bt->heap = s->heap; 205 bt->count = n; 206 bt->frames = (KitDebugFrame*)s->heap->alloc( 207 s->heap, (size_t)n * sizeof(KitDebugFrame), _Alignof(KitDebugFrame)); 208 if (!bt->frames) { 209 s->heap->free(s->heap, bt, sizeof(*bt)); 210 return KIT_NOMEM; 211 } 212 213 /* Pass 2: fill. */ 214 walk = start; 215 for (i = 0; i < n; ++i) { 216 KitDebugFrame* f = &bt->frames[i]; 217 memset(f, 0, sizeof(*f)); 218 f->regs = walk; 219 f->cfa = walk.cfa; 220 sym_describe(s->jit, s->dwarf, walk.pc, f); 221 if (i + 1 < n) sym_unwind_next(s, &walk, fpreg, ptr); 222 } 223 *out = bt; 224 return KIT_OK; 225 } 226 227 uint32_t kit_dbg_backtrace_count(const KitDebugBacktrace* bt) { 228 return bt ? bt->count : 0; 229 } 230 231 KitStatus kit_dbg_backtrace_frame(const KitDebugBacktrace* bt, uint32_t level, 232 KitDebugFrame* out) { 233 if (!bt || !out || level >= bt->count) return KIT_INVALID; 234 *out = bt->frames[level]; 235 return KIT_OK; 236 } 237 238 void kit_dbg_backtrace_free(KitDebugBacktrace* bt) { 239 if (!bt) return; 240 bt->heap->free(bt->heap, bt->frames, (size_t)bt->count * sizeof(KitDebugFrame)); 241 bt->heap->free(bt->heap, bt, sizeof(*bt)); 242 } 243 244 /* ---- typed values ----------------------------------------------------- */ 245 246 /* Resolve through DW_TAG_typedef chains to the underlying type. */ 247 static const KitDwarfType* sym_strip_typedef(const KitDwarfType* t) { 248 while (t) { 249 KitDwarfTypeInfo ti = kit_dwarf_type_info(t); 250 if (ti.kind != KIT_DT_TYPEDEF || !ti.inner) break; 251 t = ti.inner; 252 } 253 return t; 254 } 255 256 static void* sym_value_buf(KitDebugSession* s, size_t sz) { 257 return arena_alloc(&s->values, sz ? sz : 1, 16); 258 } 259 260 /* Materialize a translated loc against `fr` (runtime regs/cfa) into the 261 * stop-epoch arena. */ 262 static KitStatus sym_materialize(KitDebugSession* s, const KitDwarfVarLoc* loc, 263 const KitUnwindFrame* fr, KitDebugValue* out) { 264 size_t cap = loc->byte_size ? loc->byte_size : 8; 265 uint8_t* buf = (uint8_t*)sym_value_buf(s, cap); 266 size_t got = 0; 267 if (!buf) return KIT_NOMEM; 268 if (kit_dwarf_loc_read(s->dwarf, loc, fr, sym_read_mem, s, buf, cap, &got) != 269 KIT_OK) 270 return KIT_ERR; 271 out->type = loc->type; 272 out->bytes = buf; 273 out->len = got; 274 out->has_address = false; 275 out->address = 0; 276 if (loc->kind == KIT_DLOC_GLOBAL) { 277 out->has_address = true; 278 out->address = loc->v.global; 279 } else if (loc->kind == KIT_DLOC_FRAME_OFS) { 280 out->has_address = true; 281 out->address = fr->cfa + (uint64_t)(int64_t)loc->v.frame_ofs; 282 } 283 return KIT_OK; 284 } 285 286 KitStatus kit_dbg_var_read(KitDebugSession* s, const KitUnwindFrame* frame, 287 KitSlice name, KitDebugValue* out) { 288 KitUnwindFrame fr; 289 if (!s || !out) return KIT_INVALID; 290 memset(out, 0, sizeof(*out)); 291 fr = frame ? *frame : s->stop.regs; 292 293 if (s->dwarf) { 294 KitDwarfVarLoc loc; 295 if (kit_dwarf_var_at(s->dwarf, sym_pc_rt_to_img(s, fr.pc), name, &loc) == 296 KIT_OK) { 297 sym_translate_loc(s, &loc); 298 return sym_materialize(s, &loc, &fr, out); 299 } 300 } 301 302 /* DWARF didn't know it — fall back to a JIT global symbol. The value bytes 303 * hold the symbol's runtime address; type stays NULL. */ 304 { 305 void* p = kit_jit_lookup(s->jit, name); 306 if (p) { 307 union { 308 void* p; 309 uint64_t u; 310 } cv; 311 uint8_t* buf = (uint8_t*)sym_value_buf(s, sizeof(uint64_t)); 312 if (!buf) return KIT_NOMEM; 313 cv.p = p; 314 memcpy(buf, &cv.u, sizeof(cv.u)); 315 out->type = NULL; 316 out->bytes = buf; 317 out->len = sizeof(uint64_t); 318 out->has_address = false; 319 out->address = 0; 320 return KIT_OK; 321 } 322 } 323 return KIT_NOT_FOUND; 324 } 325 326 KitStatus kit_dbg_value_at(KitDebugSession* s, uint64_t addr, 327 const KitDwarfType* type, KitDebugValue* out) { 328 KitDwarfTypeInfo ti; 329 size_t sz = 8; 330 uint8_t* buf; 331 if (!s || !out) return KIT_INVALID; 332 memset(out, 0, sizeof(*out)); 333 if (type) { 334 ti = kit_dwarf_type_info(type); 335 if (ti.byte_size) sz = ti.byte_size; 336 } 337 buf = (uint8_t*)sym_value_buf(s, sz); 338 if (!buf) return KIT_NOMEM; 339 if (kit_dbg_session_read_mem(s, addr, buf, sz) != KIT_OK) return KIT_ERR; 340 out->type = type; 341 out->bytes = buf; 342 out->len = sz; 343 out->has_address = true; 344 out->address = addr; 345 return KIT_OK; 346 } 347 348 KitStatus kit_dbg_value_field(KitDebugSession* s, const KitDebugValue* v, 349 KitSlice field, KitDebugValue* out) { 350 const KitDwarfType* t; 351 KitDwarfTypeInfo ti; 352 KitDwarfFieldIter* it = NULL; 353 KitDwarfField f; 354 if (!s || !v || !out) return KIT_INVALID; 355 t = sym_strip_typedef(v->type); 356 if (!t) return KIT_INVALID; 357 ti = kit_dwarf_type_info(t); 358 if (ti.kind != KIT_DT_STRUCT && ti.kind != KIT_DT_UNION) return KIT_INVALID; 359 if (kit_dwarf_field_iter_new(s->dwarf, t, &it) != KIT_OK) return KIT_ERR; 360 for (;;) { 361 KitIterResult r = kit_dwarf_field_iter_next(it, &f); 362 if (r != KIT_ITER_ITEM) break; 363 if (f.name.len == field.len && f.name.len && 364 memcmp(f.name.s, field.s, field.len) == 0) { 365 size_t fsz = 0; 366 kit_dwarf_field_iter_free(it); 367 if (f.bit_size) return KIT_UNSUPPORTED; /* bitfields: not sub-sliceable */ 368 if (f.type) { 369 KitDwarfTypeInfo fti = kit_dwarf_type_info(f.type); 370 fsz = fti.byte_size; 371 } 372 if (!fsz || (size_t)f.byte_offset + fsz > v->len) return KIT_ERR; 373 memset(out, 0, sizeof(*out)); 374 out->type = f.type; 375 out->bytes = v->bytes + f.byte_offset; 376 out->len = fsz; 377 out->has_address = v->has_address; 378 out->address = v->has_address ? v->address + f.byte_offset : 0; 379 return KIT_OK; 380 } 381 } 382 kit_dwarf_field_iter_free(it); 383 return KIT_NOT_FOUND; 384 } 385 386 KitStatus kit_dbg_value_index(KitDebugSession* s, const KitDebugValue* v, 387 uint64_t index, KitDebugValue* out) { 388 const KitDwarfType* t; 389 KitDwarfTypeInfo ti, ei; 390 size_t esz; 391 if (!s || !v || !out) return KIT_INVALID; 392 t = sym_strip_typedef(v->type); 393 if (!t) return KIT_INVALID; 394 ti = kit_dwarf_type_info(t); 395 if ((ti.kind != KIT_DT_ARRAY && ti.kind != KIT_DT_PTR) || !ti.inner) 396 return KIT_INVALID; 397 ei = kit_dwarf_type_info(ti.inner); 398 esz = ei.byte_size ? ei.byte_size : 1; 399 if (ti.kind == KIT_DT_ARRAY) { 400 size_t off = (size_t)index * esz; 401 if (off + esz > v->len) return KIT_INVALID; 402 memset(out, 0, sizeof(*out)); 403 out->type = ti.inner; 404 out->bytes = v->bytes + off; 405 out->len = esz; 406 out->has_address = v->has_address; 407 out->address = v->has_address ? v->address + off : 0; 408 return KIT_OK; 409 } 410 /* pointer: read element[index] through the session. */ 411 { 412 uint64_t base = sym_load_u(v->bytes, v->len < 8 ? v->len : 8); 413 return kit_dbg_value_at(s, base + index * esz, ti.inner, out); 414 } 415 } 416 417 KitStatus kit_dbg_value_deref(KitDebugSession* s, const KitDebugValue* v, 418 KitDebugValue* out) { 419 const KitDwarfType* t; 420 KitDwarfTypeInfo ti; 421 uint64_t ptr; 422 if (!s || !v || !out) return KIT_INVALID; 423 t = sym_strip_typedef(v->type); 424 if (!t) return KIT_INVALID; 425 ti = kit_dwarf_type_info(t); 426 if (ti.kind != KIT_DT_PTR) return KIT_INVALID; 427 ptr = sym_load_u(v->bytes, v->len < 8 ? v->len : 8); 428 return kit_dbg_value_at(s, ptr, ti.inner, out); 429 } 430 431 KitStatus kit_dbg_value_as_u64(const KitDebugValue* v, uint64_t* out) { 432 if (!v || !out || !v->bytes) return KIT_INVALID; 433 *out = sym_load_u(v->bytes, v->len); 434 return KIT_OK; 435 } 436 437 KitStatus kit_dbg_value_as_i64(const KitDebugValue* v, int64_t* out) { 438 if (!v || !out || !v->bytes) return KIT_INVALID; 439 *out = sym_load_s(v->bytes, v->len); 440 return KIT_OK; 441 } 442 443 KitStatus kit_dbg_value_as_f64(const KitDebugValue* v, double* out) { 444 if (!v || !out || !v->bytes) return KIT_INVALID; 445 if (v->len == 4) { 446 union { 447 uint32_t u; 448 float f; 449 } cv; 450 cv.u = (uint32_t)sym_load_u(v->bytes, 4); 451 *out = (double)cv.f; 452 return KIT_OK; 453 } 454 if (v->len == 8) { 455 union { 456 uint64_t u; 457 double d; 458 } cv; 459 cv.u = sym_load_u(v->bytes, 8); 460 *out = cv.d; 461 return KIT_OK; 462 } 463 return KIT_UNSUPPORTED; 464 } 465 466 /* ---- value formatting ------------------------------------------------- */ 467 468 typedef struct SymFmt { 469 KitWriter* w; 470 KitDebugSession* s; 471 KitStatus st; 472 } SymFmt; 473 474 static void fw(SymFmt* f, const void* p, size_t n) { 475 if (f->st == KIT_OK) f->st = kit_writer_write(f->w, p, n); 476 } 477 static void fw_cstr(SymFmt* f, const char* s) { fw(f, s, strlen(s)); } 478 static void fw_slice(SymFmt* f, KitSlice s) { 479 if (s.s) fw(f, s.s, s.len); 480 } 481 static void fw_fmt(SymFmt* f, const char* fmt, ...) { 482 char b[64]; 483 va_list ap; 484 int n; 485 va_start(ap, fmt); 486 n = vsnprintf(b, sizeof(b), fmt, ap); 487 va_end(ap); 488 if (n < 0) return; 489 if ((size_t)n >= sizeof(b)) n = (int)sizeof(b) - 1; 490 fw(f, b, (size_t)n); 491 } 492 static void fw_dec_u(SymFmt* f, uint64_t v) { 493 fw_fmt(f, "%llu", (unsigned long long)v); 494 } 495 static void fw_dec_i(SymFmt* f, int64_t v) { 496 fw_fmt(f, "%lld", (long long)v); 497 } 498 static void fw_hex(SymFmt* f, uint64_t v) { 499 fw_fmt(f, "0x%llx", (unsigned long long)v); 500 } 501 static void fw_f64(SymFmt* f, double v) { fw_fmt(f, "%g", v); } 502 static void fw_byte(SymFmt* f, uint8_t b) { 503 static const char H[] = "0123456789abcdef"; 504 char two[3]; 505 two[0] = ' '; 506 two[1] = H[b >> 4]; 507 two[2] = H[b & 0xf]; 508 fw(f, two, 3); 509 } 510 static void fw_indent(SymFmt* f, int n) { 511 int i; 512 for (i = 0; i < n; ++i) fw(f, " ", 2); 513 } 514 515 /* Recursively render `buf[0..got)` as a value of `type`. Mirrors the driver's 516 * historical dbg_print_value byte-for-byte for the non-float kinds (the dbg 517 * golden tests pin them); floats render via snprintf "%g". */ 518 static void sym_fmt(SymFmt* f, const KitDwarfType* type, const uint8_t* buf, 519 size_t got, int depth) { 520 KitDwarfTypeInfo ti; 521 522 if (!type) { 523 if (got == 0) { 524 fw_cstr(f, "<empty>"); 525 return; 526 } 527 if (got <= 8) { 528 uint64_t v = sym_load_u(buf, got); 529 fw_hex(f, v); 530 fw_cstr(f, " ("); 531 fw_dec_u(f, v); 532 fw_cstr(f, ")"); 533 return; 534 } 535 { 536 size_t i; 537 fw_cstr(f, "{"); 538 for (i = 0; i < got; ++i) fw_byte(f, buf[i]); 539 fw_cstr(f, " }"); 540 return; 541 } 542 } 543 544 ti = kit_dwarf_type_info(type); 545 switch (ti.kind) { 546 case KIT_DT_VOID: 547 fw_cstr(f, "void"); 548 return; 549 case KIT_DT_SINT: 550 case KIT_DT_CHAR: 551 fw_dec_i(f, sym_load_s(buf, got)); 552 return; 553 case KIT_DT_UINT: 554 case KIT_DT_BOOL: 555 fw_dec_u(f, sym_load_u(buf, got)); 556 return; 557 case KIT_DT_PTR: 558 fw_hex(f, sym_load_u(buf, got)); 559 return; 560 case KIT_DT_FLOAT: 561 if (got == 4) { 562 union { 563 uint32_t u; 564 float f; 565 } cv; 566 cv.u = (uint32_t)sym_load_u(buf, 4); 567 fw_f64(f, (double)cv.f); 568 } else if (got == 8) { 569 union { 570 uint64_t u; 571 double d; 572 } cv; 573 cv.u = sym_load_u(buf, 8); 574 fw_f64(f, cv.d); 575 } else { 576 size_t i; 577 fw_cstr(f, "<float-"); 578 fw_dec_u(f, got); 579 for (i = 0; i < got; ++i) fw_byte(f, buf[i]); 580 fw_cstr(f, ">"); 581 } 582 return; 583 case KIT_DT_ENUM: { 584 int64_t v = sym_load_s(buf, got); 585 KitDwarfEnumIter* it = NULL; 586 KitDwarfEnumVal ev; 587 KitSlice match = KIT_SLICE_NULL; 588 if (kit_dwarf_enum_iter_new(f->s->dwarf, type, &it) == KIT_OK) { 589 for (;;) { 590 KitIterResult r = kit_dwarf_enum_iter_next(it, &ev); 591 if (r != KIT_ITER_ITEM) break; 592 if (ev.value == v) { 593 match = ev.name; 594 break; 595 } 596 } 597 kit_dwarf_enum_iter_free(it); 598 } 599 if (match.s) { 600 fw_slice(f, match); 601 fw_cstr(f, " ("); 602 fw_dec_i(f, v); 603 fw_cstr(f, ")"); 604 } else { 605 fw_dec_i(f, v); 606 } 607 return; 608 } 609 case KIT_DT_TYPEDEF: 610 sym_fmt(f, ti.inner, buf, got, depth); 611 return; 612 case KIT_DT_ARRAY: { 613 uint32_t n = ti.element_count; 614 size_t esz = 0; 615 uint32_t i; 616 if (ti.inner) { 617 KitDwarfTypeInfo ein = kit_dwarf_type_info(ti.inner); 618 esz = ein.byte_size; 619 } 620 if (esz == 0 || n == 0 || (size_t)n * esz > got) { 621 size_t k; 622 fw_cstr(f, "{"); 623 for (k = 0; k < got; ++k) fw_byte(f, buf[k]); 624 fw_cstr(f, " }"); 625 return; 626 } 627 fw_cstr(f, "{\n"); 628 for (i = 0; i < n; ++i) { 629 fw_indent(f, depth + 1); 630 fw_cstr(f, "["); 631 fw_dec_u(f, i); 632 fw_cstr(f, "] = "); 633 sym_fmt(f, ti.inner, buf + (size_t)i * esz, esz, depth + 1); 634 fw_cstr(f, ",\n"); 635 } 636 fw_indent(f, depth); 637 fw_cstr(f, "}"); 638 return; 639 } 640 case KIT_DT_STRUCT: 641 case KIT_DT_UNION: { 642 KitDwarfFieldIter* it = NULL; 643 KitDwarfField fld; 644 fw_cstr(f, "{\n"); 645 if (kit_dwarf_field_iter_new(f->s->dwarf, type, &it) == KIT_OK) { 646 for (;;) { 647 KitIterResult r = kit_dwarf_field_iter_next(it, &fld); 648 size_t fsz = 0; 649 if (r != KIT_ITER_ITEM) break; 650 fw_indent(f, depth + 1); 651 fw_cstr(f, "."); 652 fw_slice(f, fld.name.len ? fld.name : KIT_SLICE_LIT("<anon>")); 653 fw_cstr(f, " = "); 654 if (fld.bit_size) { 655 size_t off = fld.byte_offset; 656 size_t take = (off + 8 <= got) ? 8 : (off < got ? got - off : 0); 657 uint64_t raw = take ? sym_load_u(buf + off, take) : 0; 658 uint64_t mask = (fld.bit_size >= 64) 659 ? (uint64_t)-1 660 : (((uint64_t)1 << fld.bit_size) - 1); 661 uint64_t v = (raw >> fld.bit_offset) & mask; 662 fw_dec_u(f, v); 663 } else { 664 if (fld.type) { 665 KitDwarfTypeInfo fti = kit_dwarf_type_info(fld.type); 666 fsz = fti.byte_size; 667 } 668 if (fld.type && fsz > 0 && (size_t)fld.byte_offset + fsz <= got) { 669 sym_fmt(f, fld.type, buf + fld.byte_offset, fsz, depth + 1); 670 } else { 671 fw_cstr(f, "<truncated>"); 672 } 673 } 674 fw_cstr(f, ",\n"); 675 } 676 kit_dwarf_field_iter_free(it); 677 } 678 fw_indent(f, depth); 679 fw_cstr(f, "}"); 680 return; 681 } 682 case KIT_DT_FUNC: 683 fw_cstr(f, "<function@"); 684 fw_hex(f, sym_load_u(buf, got)); 685 fw_cstr(f, ">"); 686 return; 687 } 688 fw_cstr(f, "<?>"); 689 } 690 691 KitStatus kit_dbg_value_format(KitDebugSession* s, const KitDebugValue* v, 692 KitWriter* out, 693 const KitDebugFormatOptions* opt) { 694 SymFmt f; 695 if (!s || !v || !out) return KIT_INVALID; 696 f.w = out; 697 f.s = s; 698 f.st = KIT_OK; 699 sym_fmt(&f, v->type, v->bytes, v->len, opt ? (int)opt->indent : 0); 700 return f.st; 701 } 702 703 KitStatus kit_dbg_var_write_u64(KitDebugSession* s, const KitUnwindFrame* frame, 704 KitSlice name, uint64_t value) { 705 KitUnwindFrame fr; 706 KitDwarfVarLoc loc; 707 uint8_t buf[8]; 708 size_t sz, i; 709 if (!s) return KIT_INVALID; 710 if (!s->dwarf) return KIT_NOT_FOUND; 711 fr = frame ? *frame : s->stop.regs; 712 if (kit_dwarf_var_at(s->dwarf, sym_pc_rt_to_img(s, fr.pc), name, &loc) != 713 KIT_OK) 714 return KIT_NOT_FOUND; 715 sym_translate_loc(s, &loc); 716 sz = (loc.byte_size == 0 || loc.byte_size > 8) ? 8 : loc.byte_size; 717 for (i = 0; i < sz; ++i) buf[i] = (uint8_t)(value >> (8 * i)); 718 719 switch (loc.kind) { 720 case KIT_DLOC_FRAME_OFS: 721 return kit_dbg_session_write_mem( 722 s, fr.cfa + (uint64_t)(int64_t)loc.v.frame_ofs, buf, sz); 723 case KIT_DLOC_GLOBAL: 724 return kit_dbg_session_write_mem(s, loc.v.global, buf, sz); 725 case KIT_DLOC_REG: { 726 KitUnwindFrame w = s->stop.regs; 727 if (loc.v.reg >= 32) return KIT_INVALID; 728 w.regs[loc.v.reg] = value; 729 return kit_dbg_session_set_regs(s, &w); 730 } 731 case KIT_DLOC_EXPR: 732 return KIT_UNSUPPORTED; 733 } 734 return KIT_UNSUPPORTED; 735 } 736 737 /* ---- scope enumeration ------------------------------------------------ */ 738 739 struct KitDebugVarIter { 740 KitDebugSession* s; 741 KitUnwindFrame frame; 742 KitDwarfVarIter* inner; 743 }; 744 745 KitStatus kit_dbg_vars_new(KitDebugSession* s, const KitUnwindFrame* frame, 746 uint32_t roles, KitDebugVarIter** out) { 747 KitDebugVarIter* it; 748 KitDwarfVarIter* inner = NULL; 749 KitStatus st; 750 if (!s || !out) return KIT_INVALID; 751 *out = NULL; 752 if (!s->dwarf) return KIT_NOT_FOUND; 753 it = (KitDebugVarIter*)s->heap->alloc(s->heap, sizeof(*it), 754 _Alignof(KitDebugVarIter)); 755 if (!it) return KIT_NOMEM; 756 it->s = s; 757 it->frame = frame ? *frame : s->stop.regs; 758 st = kit_dwarf_vars_at_new(s->dwarf, sym_pc_rt_to_img(s, it->frame.pc), roles, 759 &inner); 760 if (st != KIT_OK) { 761 s->heap->free(s->heap, it, sizeof(*it)); 762 return st; 763 } 764 it->inner = inner; 765 *out = it; 766 return KIT_OK; 767 } 768 769 KitIterResult kit_dbg_vars_next(KitDebugVarIter* it, KitSlice* name_out, 770 KitDebugValue* value_out) { 771 KitDwarfVar v; 772 KitIterResult r; 773 if (!it || !value_out) return KIT_ITER_END; 774 r = kit_dwarf_vars_at_next(it->inner, &v); 775 if (r != KIT_ITER_ITEM) return r; 776 if (name_out) *name_out = v.name; 777 memset(value_out, 0, sizeof(*value_out)); 778 value_out->type = v.loc.type; 779 sym_translate_loc(it->s, &v.loc); 780 /* On a read failure leave bytes NULL: the caller renders "<unreadable>" but 781 * the enumeration continues. */ 782 (void)sym_materialize(it->s, &v.loc, &it->frame, value_out); 783 return KIT_ITER_ITEM; 784 } 785 786 void kit_dbg_vars_free(KitDebugVarIter* it) { 787 if (!it) return; 788 kit_dwarf_vars_at_free(it->inner); 789 it->s->heap->free(it->s->heap, it, sizeof(*it)); 790 } 791 792 /* ---- location resolution + breakpoints -------------------------------- */ 793 794 static int sym_is_digit(int c) { return c >= '0' && c <= '9'; } 795 796 /* Parse a decimal or 0x-hex integer from [s, s+n); returns bytes consumed (0 on 797 * no digits) and writes the value. */ 798 static size_t sym_parse_u64(const char* s, size_t n, uint64_t* out) { 799 uint64_t v = 0; 800 size_t i = 0; 801 int any = 0; 802 if (n >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { 803 i = 2; 804 for (; i < n; ++i) { 805 int c = s[i], d; 806 if (sym_is_digit(c)) 807 d = c - '0'; 808 else if (c >= 'a' && c <= 'f') 809 d = c - 'a' + 10; 810 else if (c >= 'A' && c <= 'F') 811 d = c - 'A' + 10; 812 else 813 break; 814 v = (v << 4) | (uint64_t)d; 815 any = 1; 816 } 817 } else { 818 for (; i < n; ++i) { 819 if (!sym_is_digit(s[i])) break; 820 v = v * 10u + (uint64_t)(s[i] - '0'); 821 any = 1; 822 } 823 } 824 if (!any) return 0; 825 *out = v; 826 return i; 827 } 828 829 KitStatus kit_dbg_resolve(KitDebugSession* s, KitSlice spec, uint64_t* addr_out, 830 KitDwarfLineMatch* cands, uint32_t cap, 831 uint32_t* ncand) { 832 const char* p; 833 size_t n, i; 834 if (!s || !addr_out || !spec.s || spec.len == 0) return KIT_INVALID; 835 if (ncand) *ncand = 0; 836 p = spec.s; 837 n = spec.len; 838 839 /* file:line — a ':' immediately followed by a digit. */ 840 for (i = 0; i < n; ++i) { 841 if (p[i] == ':' && i + 1 < n && sym_is_digit((unsigned char)p[i + 1])) { 842 KitSlice file = {.s = p, .len = i}; 843 uint64_t line = 0; 844 uint64_t pc = 0; 845 KitStatus rc; 846 size_t used = sym_parse_u64(p + i + 1, n - i - 1, &line); 847 if (i == 0 || used != n - i - 1) return KIT_INVALID; 848 if (!s->dwarf) return KIT_NOT_FOUND; 849 rc = kit_dwarf_line_to_addr(s->dwarf, file, (uint32_t)line, &pc); 850 if (rc == KIT_AMBIGUOUS) { 851 if (cands && cap) 852 kit_dwarf_line_to_addr_all(s->dwarf, file, (uint32_t)line, cands, cap, 853 ncand); 854 else if (ncand) 855 kit_dwarf_line_to_addr_all(s->dwarf, file, (uint32_t)line, NULL, 0, 856 ncand); 857 return KIT_AMBIGUOUS; 858 } 859 if (rc != KIT_OK) return rc; 860 *addr_out = sym_pc_img_to_rt(s, pc); 861 return KIT_OK; 862 } 863 } 864 865 /* 0xADDR or decimal address. */ 866 if ((n >= 1 && sym_is_digit((unsigned char)p[0]))) { 867 uint64_t v = 0; 868 size_t used = sym_parse_u64(p, n, &v); 869 if (!used || used != n) return KIT_INVALID; 870 *addr_out = v; 871 return KIT_OK; 872 } 873 874 /* NAME[+off] */ 875 { 876 size_t name_n = n; 877 uint64_t off = 0; 878 void* resolved; 879 KitSlice name; 880 for (i = 0; i < n; ++i) { 881 if (p[i] == '+') { 882 name_n = i; 883 break; 884 } 885 } 886 if (name_n == 0) return KIT_INVALID; 887 if (name_n < n) { 888 size_t used = sym_parse_u64(p + name_n + 1, n - name_n - 1, &off); 889 if (!used || used != n - name_n - 1) return KIT_INVALID; 890 } 891 name.s = p; 892 name.len = name_n; 893 resolved = kit_jit_lookup(s->jit, name); 894 if (!resolved) return KIT_NOT_FOUND; 895 { 896 union { 897 void* p; 898 uint64_t u; 899 } cv; 900 cv.p = resolved; 901 *addr_out = cv.u + off; 902 } 903 return KIT_OK; 904 } 905 } 906 907 KitStatus kit_dbg_break(KitDebugSession* s, KitSlice spec, 908 uint32_t* bp_id_out) { 909 uint64_t addr = 0; 910 KitStatus rc = kit_dbg_resolve(s, spec, &addr, NULL, 0, NULL); 911 if (rc != KIT_OK) return rc; 912 return kit_dbg_session_breakpoint_set(s, addr, bp_id_out); 913 } 914 915 /* ---- disassemble at the stopped PC ------------------------------------ */ 916 917 KitStatus kit_dbg_disasm_new(KitDebugSession* s, uint64_t addr, uint32_t count, 918 KitDisasmIter** out) { 919 KitDisasmContext* dctx; 920 uint8_t* buf; 921 size_t bytec; 922 if (!s || !out || count == 0) return KIT_INVALID; 923 *out = NULL; 924 if (count > SYM_BT_MAX) count = SYM_BT_MAX; 925 bytec = (size_t)count * 16u; /* generous upper bound per instruction */ 926 buf = (uint8_t*)arena_alloc(&s->values, bytec, 16); 927 if (!buf) return KIT_NOMEM; 928 if (kit_dbg_session_read_mem(s, addr, buf, bytec) != KIT_OK) return KIT_ERR; 929 /* The disasm iterator's compiler keeps a pointer into this KitDisasmContext, 930 * so it must outlive the iterator: park it in the stop-epoch arena (freed at 931 * the next resume, after the caller has freed the iterator). */ 932 dctx = arena_znew(&s->values, KitDisasmContext); 933 if (!dctx) return KIT_NOMEM; 934 dctx->target = kit_compiler_target(s->c); 935 dctx->context = *s->c->ctx; 936 return kit_disasm_iter_new(dctx, buf, bytec, addr, kit_jit_view(s->jit), out); 937 }