dwarf_query.c (14577B)
1 /* dwarf_query.c — public kit_dwarf_* query entry points. 2 * 3 * Implements the consumer half of doc/DWARF.md: 4 * subprogram_at / func_at, var_at, vars_at_*, param_iter_*, loc_read. 5 */ 6 7 #include <kit/arch.h> 8 #include <kit/dwarf.h> 9 #include <stddef.h> 10 #include <stdint.h> 11 #include <string.h> 12 13 #include "core/core.h" 14 #include "core/heap.h" 15 #include "debug/dwarf_internal.h" 16 17 static void fill_subprogram(KitDebugInfo* d, DwSubprog* sp, 18 KitDwarfSubprogram* out) { 19 memset(out, 0, sizeof(*out)); 20 out->name = sp->name ? kit_slice_cstr(sp->name) : KIT_SLICE_NULL; 21 out->low_pc = sp->low_pc; 22 out->high_pc = sp->high_pc; 23 out->decl_file = 24 sp->decl_file ? kit_slice_cstr(sp->decl_file) : KIT_SLICE_NULL; 25 out->decl_line = sp->decl_line; 26 out->return_type = sp->type_die_offset 27 ? dw_type_from_die(d, sp->cu_idx, sp->type_die_offset) 28 : dw_void_type(d); 29 out->inlined = sp->inlined; 30 } 31 32 KitStatus kit_dwarf_subprogram_at(KitDebugInfo* d, uint64_t pc, 33 KitDwarfSubprogram* out) { 34 DwSubprog* sp; 35 if (!d || !out) return KIT_INVALID; 36 sp = dw_find_subprog(d, pc); 37 if (!sp) return KIT_NOT_FOUND; 38 fill_subprogram(d, sp, out); 39 return KIT_OK; 40 } 41 42 static DwSubprog* dw_find_subprog_named(KitDebugInfo* d, const char* name) { 43 u32 i; 44 if (!d || !name) return NULL; 45 dw_build_subs(d); 46 for (i = 0; i < d->nsubs; ++i) { 47 DwSubprog* sp = &d->subs[i]; 48 if (sp->inlined) continue; 49 if (!sp->name || !dw_streq(sp->name, name)) continue; 50 if (sp->high_pc > sp->low_pc) return sp; 51 } 52 for (i = 0; i < d->nsubs; ++i) { 53 DwSubprog* sp = &d->subs[i]; 54 if (sp->inlined) continue; 55 if (sp->name && dw_streq(sp->name, name)) return sp; 56 } 57 return NULL; 58 } 59 60 KitStatus kit_dwarf_subprogram_named(KitDebugInfo* d, KitSlice name, 61 KitDwarfSubprogram* out) { 62 DwSubprog* sp; 63 if (!d || !name.s || !out) return KIT_INVALID; 64 sp = dw_find_subprog_named(d, name.s); 65 if (!sp) return KIT_NOT_FOUND; 66 fill_subprogram(d, sp, out); 67 return KIT_OK; 68 } 69 70 KitStatus kit_dwarf_func_at(KitDebugInfo* d, uint64_t pc, KitSlice* name_out, 71 uint64_t* low_out, uint64_t* high_out) { 72 KitDwarfSubprogram sp; 73 KitStatus st = kit_dwarf_subprogram_at(d, pc, &sp); 74 if (st != KIT_OK) return st; 75 if (name_out) *name_out = sp.name; 76 if (low_out) *low_out = sp.low_pc; 77 if (high_out) *high_out = sp.high_pc; 78 return KIT_OK; 79 } 80 81 KitStatus kit_dwarf_resolve(KitDebugInfo* d, uint64_t addr, int want_func, 82 KitDwarfResolve* out) { 83 KitSlice file; 84 uint32_t line = 0, col = 0; 85 if (!d || !out) return KIT_INVALID; 86 memset(out, 0, sizeof(*out)); 87 88 if (kit_dwarf_addr_to_line(d, addr, &file, &line, &col) == KIT_OK) { 89 out->have_line = 1; 90 out->file = file; 91 out->line = line; 92 out->col = col; 93 } 94 95 if (want_func) { 96 KitSlice func; 97 uint64_t func_lo = 0, func_hi = 0; 98 if (kit_dwarf_func_at(d, addr, &func, &func_lo, &func_hi) == KIT_OK) { 99 out->have_func = 1; 100 out->func = func; 101 } 102 } 103 return KIT_OK; 104 } 105 106 /* ---- variable resolution -------------------------------------------- */ 107 108 static void fill_varloc(KitDebugInfo* d, u32 cu_idx, const DwLocal* v, u64 pc, 109 KitDwarfVarLoc* out) { 110 const u8* lbytes = v->loc; 111 u32 llen = v->loc_len; 112 memset(out, 0, sizeof(*out)); 113 out->kind = KIT_DLOC_EXPR; 114 out->byte_size = 0; 115 out->type = NULL; 116 if (v->type_die_offset) { 117 out->type = dw_type_from_die(d, cu_idx, v->type_die_offset); 118 if (out->type) out->byte_size = out->type->byte_size; 119 } 120 /* If the variable was emitted with a loclistx, resolve it now. The 121 * resolved bytes get the same single-op fast-path treatment below. */ 122 if (v->has_loclist && cu_idx < d->ncus) { 123 const u8* lb = NULL; 124 u32 ll = 0; 125 if (dw_loclist_resolve(d, &d->cus[cu_idx], v->loclist_index, pc, &lb, 126 &ll)) { 127 lbytes = lb; 128 llen = ll; 129 } else { 130 /* No active entry for this PC — variable is currently unavailable. */ 131 out->kind = KIT_DLOC_EXPR; 132 out->v.expr.bytes = NULL; 133 out->v.expr.len = 0; 134 return; 135 } 136 } 137 /* Inspect the loc bytes — if it's a single op of a recognized form, 138 * we expose the structured kind so callers can fast-path. Otherwise 139 * we surface the raw bytes as EXPR. */ 140 if (lbytes && llen > 0) { 141 const u8* e = lbytes; 142 if (llen == 1 && e[0] >= DW_OP_reg0 && e[0] <= DW_OP_reg0 + 31) { 143 out->kind = KIT_DLOC_REG; 144 out->v.reg = e[0] - DW_OP_reg0; 145 return; 146 } 147 if (e[0] == DW_OP_regx) { 148 u32 off = 1; 149 u64 r = dw_uleb(e, llen, &off); 150 if (off == llen) { 151 out->kind = KIT_DLOC_REG; 152 out->v.reg = (u32)r; 153 return; 154 } 155 } 156 if (e[0] == DW_OP_fbreg) { 157 u32 off = 1; 158 i64 ofs = dw_sleb(e, llen, &off); 159 if (off == llen) { 160 out->kind = KIT_DLOC_FRAME_OFS; 161 out->v.frame_ofs = (i32)ofs; 162 return; 163 } 164 } 165 if (e[0] == DW_OP_addr && cu_idx < d->ncus && 166 llen == 1u + d->cus[cu_idx].address_size) { 167 u32 off = 1; 168 out->kind = KIT_DLOC_GLOBAL; 169 out->v.global = d->cus[cu_idx].address_size == 4 ? dw_u32(e, llen, &off) 170 : dw_u64(e, llen, &off); 171 return; 172 } 173 /* Fallback: opaque expression bytes. */ 174 out->kind = KIT_DLOC_EXPR; 175 out->v.expr.bytes = lbytes; 176 out->v.expr.len = llen; 177 return; 178 } 179 /* No location at all — leave kind=EXPR with NULL/0. */ 180 out->kind = KIT_DLOC_EXPR; 181 out->v.expr.bytes = NULL; 182 out->v.expr.len = 0; 183 } 184 185 KitStatus kit_dwarf_var_at(KitDebugInfo* d, uint64_t pc, KitSlice name, 186 KitDwarfVarLoc* out) { 187 /* Status codes: 188 * KIT_OK — found; *out filled. 189 * KIT_INVALID — bad args. 190 * KIT_NOT_FOUND — pc inside a subprog but no var named `name`, or 191 * pc outside any subprogram and not a global. 192 */ 193 DwSubprog* sp; 194 u32 i; 195 if (!d || !name.s || !out) return KIT_INVALID; 196 memset(out, 0, sizeof(*out)); 197 sp = dw_find_subprog(d, pc); 198 if (sp) { 199 dw_build_locals(d, sp); 200 /* Deepest scope first: walk locals from end (innermost blocks added 201 * after enclosing). */ 202 for (i = sp->nlocals; i > 0; --i) { 203 DwLocal* v = &sp->locals[i - 1]; 204 if (!v->name || !dw_streq(v->name, name.s)) continue; 205 if (v->has_scope && (pc < v->scope_lo || pc >= v->scope_hi)) continue; 206 fill_varloc(d, sp->cu_idx, v, pc, out); 207 return KIT_OK; 208 } 209 /* Then params. */ 210 for (i = 0; i < sp->nparams; ++i) { 211 DwLocal* v = &sp->params[i]; 212 if (!v->name || !dw_streq(v->name, name.s)) continue; 213 fill_varloc(d, sp->cu_idx, v, pc, out); 214 return KIT_OK; 215 } 216 } 217 /* Globals. */ 218 dw_build_globals(d); 219 for (i = 0; i < d->nglobals; ++i) { 220 DwLocal* v = &d->globals[i]; 221 if (!v->name || !dw_streq(v->name, name.s)) continue; 222 fill_varloc(d, 0, v, pc, out); 223 return KIT_OK; 224 } 225 return KIT_NOT_FOUND; 226 } 227 228 KitStatus kit_dwarf_loc_read(KitDebugInfo* d, const KitDwarfVarLoc* loc, 229 const KitUnwindFrame* frame, 230 KitDwarfReadMemFn read_mem, void* read_user, 231 void* dst, size_t cap, size_t* read_out) { 232 size_t want; 233 if (read_out) *read_out = 0; 234 if (!d || !loc || !frame || !dst) return KIT_INVALID; 235 want = loc->byte_size ? loc->byte_size : cap; 236 if (want > cap) want = cap; 237 switch (loc->kind) { 238 case KIT_DLOC_REG: { 239 uint64_t v = (loc->v.reg < 32) ? frame->regs[loc->v.reg] : 0; 240 size_t n = want > sizeof(v) ? sizeof(v) : want; 241 memcpy(dst, &v, n); 242 if (read_out) *read_out = n; 243 return KIT_OK; 244 } 245 case KIT_DLOC_FRAME_OFS: { 246 uint64_t addr = frame->cfa + (uint64_t)(int64_t)loc->v.frame_ofs; 247 KitStatus st; 248 if (!read_mem) return KIT_INVALID; 249 st = read_mem(read_user, addr, dst, want); 250 if (st != KIT_OK) return st; 251 if (read_out) *read_out = want; 252 return KIT_OK; 253 } 254 case KIT_DLOC_GLOBAL: { 255 uint64_t addr = loc->v.global; 256 KitStatus st; 257 if (!read_mem) return KIT_INVALID; 258 st = read_mem(read_user, addr, dst, want); 259 if (st != KIT_OK) return st; 260 if (read_out) *read_out = want; 261 return KIT_OK; 262 } 263 case KIT_DLOC_EXPR: { 264 /* Evaluate. We don't have direct access to the variable's 265 * subprogram's frame_base here — caller-supplied frame must already 266 * carry the right CFA. The expression itself may be DW_OP_call_frame_cfa 267 * + DW_OP_consts + DW_OP_plus, etc. */ 268 DwExprResult r; 269 if (loc->v.expr.bytes == NULL || loc->v.expr.len == 0) 270 return KIT_NOT_FOUND; 271 if (dw_eval_expr(d, loc->v.expr.bytes, (u32)loc->v.expr.len, NULL, 0, 272 frame, &r) != 0) 273 return KIT_UNSUPPORTED; 274 if (r.kind == 0) { 275 KitStatus st; 276 if (!read_mem) return KIT_INVALID; 277 st = read_mem(read_user, r.value, dst, want); 278 if (st != KIT_OK) return st; 279 if (read_out) *read_out = want; 280 return KIT_OK; 281 } else if (r.kind == 1) { 282 size_t n = want > sizeof(r.value) ? sizeof(r.value) : want; 283 memcpy(dst, &r.value, n); 284 if (read_out) *read_out = n; 285 return KIT_OK; 286 } else if (r.kind == 2) { 287 u64 v = (r.value < 32) ? frame->regs[r.value] : 0; 288 size_t n = want > sizeof(v) ? sizeof(v) : want; 289 memcpy(dst, &v, n); 290 if (read_out) *read_out = n; 291 return KIT_OK; 292 } 293 return KIT_UNSUPPORTED; 294 } 295 } 296 return KIT_UNSUPPORTED; 297 } 298 299 /* ---- vars_at_* iterator --------------------------------------------- */ 300 301 struct KitDwarfVarIter { 302 KitDebugInfo* d; 303 DwSubprog* sp; 304 u64 pc; 305 u32 mask; 306 u32 phase; /* 0 = locals, 1 = params, 2 = globals, 3 = done */ 307 u32 idx; 308 }; 309 310 KitStatus kit_dwarf_vars_at_new(KitDebugInfo* d, uint64_t pc, uint32_t mask, 311 KitDwarfVarIter** out) { 312 KitDwarfVarIter* it; 313 if (!out) return KIT_INVALID; 314 *out = NULL; 315 if (!d) return KIT_INVALID; 316 it = (KitDwarfVarIter*)d->h->alloc(d->h, sizeof(*it), 317 _Alignof(KitDwarfVarIter)); 318 if (!it) return KIT_NOMEM; 319 it->d = d; 320 it->pc = pc; 321 it->mask = mask; 322 it->sp = dw_find_subprog(d, pc); 323 if (it->sp) dw_build_locals(d, it->sp); 324 it->phase = 0; 325 it->idx = it->sp ? it->sp->nlocals : 0; 326 *out = it; 327 return KIT_OK; 328 } 329 330 KitIterResult kit_dwarf_vars_at_next(KitDwarfVarIter* it, KitDwarfVar* out) { 331 if (!it || !out) return KIT_ITER_ERROR; 332 for (;;) { 333 switch (it->phase) { 334 case 0: { 335 if (!(it->mask & (1u << KIT_DVR_LOCAL))) { 336 it->phase = 1; 337 it->idx = 0; 338 break; 339 } 340 if (it->idx == 0) { 341 it->phase = 1; 342 it->idx = 0; 343 break; 344 } 345 { 346 DwLocal* v = &it->sp->locals[--it->idx]; 347 if (v->has_scope && (it->pc < v->scope_lo || it->pc >= v->scope_hi)) 348 break; 349 out->name = v->name ? kit_slice_cstr(v->name) : KIT_SLICE_NULL; 350 out->role = KIT_DVR_LOCAL; 351 fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); 352 return KIT_ITER_ITEM; 353 } 354 } 355 case 1: { 356 if (!it->sp || !(it->mask & (1u << KIT_DVR_ARG))) { 357 it->phase = 2; 358 it->idx = 0; 359 break; 360 } 361 if (it->idx >= it->sp->nparams) { 362 it->phase = 2; 363 it->idx = 0; 364 break; 365 } 366 { 367 DwLocal* v = &it->sp->params[it->idx++]; 368 out->name = v->name ? kit_slice_cstr(v->name) : KIT_SLICE_NULL; 369 out->role = KIT_DVR_ARG; 370 fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); 371 return KIT_ITER_ITEM; 372 } 373 } 374 case 2: { 375 if (!(it->mask & (1u << KIT_DVR_GLOBAL))) { 376 it->phase = 3; 377 break; 378 } 379 dw_build_globals(it->d); 380 if (it->idx >= it->d->nglobals) { 381 it->phase = 3; 382 break; 383 } 384 { 385 DwLocal* v = &it->d->globals[it->idx++]; 386 out->name = v->name ? kit_slice_cstr(v->name) : KIT_SLICE_NULL; 387 out->role = KIT_DVR_GLOBAL; 388 fill_varloc(it->d, 0, v, it->pc, &out->loc); 389 return KIT_ITER_ITEM; 390 } 391 } 392 default: 393 return KIT_ITER_END; 394 } 395 } 396 } 397 398 void kit_dwarf_vars_at_free(KitDwarfVarIter* it) { 399 if (!it) return; 400 it->d->h->free(it->d->h, it, sizeof(*it)); 401 } 402 403 /* ---- param_iter_* --------------------------------------------------- */ 404 405 struct KitDwarfParamIter { 406 KitDebugInfo* d; 407 DwSubprog* sp; 408 u64 pc; 409 u32 idx; 410 }; 411 412 KitStatus kit_dwarf_param_iter_new(KitDebugInfo* d, uint64_t pc, 413 KitDwarfParamIter** out) { 414 KitDwarfParamIter* it; 415 DwSubprog* sp; 416 if (!out) return KIT_INVALID; 417 *out = NULL; 418 if (!d) return KIT_INVALID; 419 sp = dw_find_subprog(d, pc); 420 if (!sp) return KIT_NOT_FOUND; 421 dw_build_locals(d, sp); 422 it = (KitDwarfParamIter*)d->h->alloc(d->h, sizeof(*it), 423 _Alignof(KitDwarfParamIter)); 424 if (!it) return KIT_NOMEM; 425 it->d = d; 426 it->sp = sp; 427 it->pc = pc; 428 it->idx = 0; 429 *out = it; 430 return KIT_OK; 431 } 432 433 KitStatus kit_dwarf_param_iter_new_named(KitDebugInfo* d, KitSlice name, 434 KitDwarfParamIter** out) { 435 KitDwarfParamIter* it; 436 DwSubprog* sp; 437 if (!out) return KIT_INVALID; 438 *out = NULL; 439 if (!d || !name.s) return KIT_INVALID; 440 sp = dw_find_subprog_named(d, name.s); 441 if (!sp) return KIT_NOT_FOUND; 442 dw_build_locals(d, sp); 443 it = (KitDwarfParamIter*)d->h->alloc(d->h, sizeof(*it), 444 _Alignof(KitDwarfParamIter)); 445 if (!it) return KIT_NOMEM; 446 it->d = d; 447 it->sp = sp; 448 it->pc = sp->low_pc; 449 it->idx = 0; 450 *out = it; 451 return KIT_OK; 452 } 453 454 KitIterResult kit_dwarf_param_iter_next(KitDwarfParamIter* it, 455 KitDwarfVar* out) { 456 if (!it || !out) return KIT_ITER_ERROR; 457 if (it->idx >= it->sp->nparams) return KIT_ITER_END; 458 { 459 DwLocal* v = &it->sp->params[it->idx++]; 460 out->name = v->name ? kit_slice_cstr(v->name) : KIT_SLICE_NULL; 461 out->role = KIT_DVR_ARG; 462 fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); 463 } 464 return KIT_ITER_ITEM; 465 } 466 467 void kit_dwarf_param_iter_free(KitDwarfParamIter* it) { 468 if (!it) return; 469 it->d->h->free(it->d->h, it, sizeof(*it)); 470 }