dwarf_query.c (13763B)
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 /* ---- variable resolution -------------------------------------------- */ 82 83 static void fill_varloc(KitDebugInfo* d, u32 cu_idx, const DwLocal* v, u64 pc, 84 KitDwarfVarLoc* out) { 85 const u8* lbytes = v->loc; 86 u32 llen = v->loc_len; 87 memset(out, 0, sizeof(*out)); 88 out->kind = KIT_DLOC_EXPR; 89 out->byte_size = 0; 90 out->type = NULL; 91 if (v->type_die_offset) { 92 out->type = dw_type_from_die(d, cu_idx, v->type_die_offset); 93 if (out->type) out->byte_size = out->type->byte_size; 94 } 95 /* If the variable was emitted with a loclistx, resolve it now. The 96 * resolved bytes get the same single-op fast-path treatment below. */ 97 if (v->has_loclist && cu_idx < d->ncus) { 98 const u8* lb = NULL; 99 u32 ll = 0; 100 if (dw_loclist_resolve(d, &d->cus[cu_idx], v->loclist_index, pc, &lb, 101 &ll)) { 102 lbytes = lb; 103 llen = ll; 104 } else { 105 /* No active entry for this PC — variable is currently unavailable. */ 106 out->kind = KIT_DLOC_EXPR; 107 out->v.expr.bytes = NULL; 108 out->v.expr.len = 0; 109 return; 110 } 111 } 112 /* Inspect the loc bytes — if it's a single op of a recognized form, 113 * we expose the structured kind so callers can fast-path. Otherwise 114 * we surface the raw bytes as EXPR. */ 115 if (lbytes && llen > 0) { 116 const u8* e = lbytes; 117 if (llen == 1 && e[0] >= DW_OP_reg0 && e[0] <= DW_OP_reg0 + 31) { 118 out->kind = KIT_DLOC_REG; 119 out->v.reg = e[0] - DW_OP_reg0; 120 return; 121 } 122 if (e[0] == DW_OP_regx) { 123 u32 off = 1; 124 u64 r = dw_uleb(e, llen, &off); 125 if (off == llen) { 126 out->kind = KIT_DLOC_REG; 127 out->v.reg = (u32)r; 128 return; 129 } 130 } 131 if (e[0] == DW_OP_fbreg) { 132 u32 off = 1; 133 i64 ofs = dw_sleb(e, llen, &off); 134 if (off == llen) { 135 out->kind = KIT_DLOC_FRAME_OFS; 136 out->v.frame_ofs = (i32)ofs; 137 return; 138 } 139 } 140 if (e[0] == DW_OP_addr && llen == 9) { 141 u32 off = 1; 142 out->kind = KIT_DLOC_GLOBAL; 143 out->v.global = dw_u64(e, llen, &off); 144 return; 145 } 146 /* Fallback: opaque expression bytes. */ 147 out->kind = KIT_DLOC_EXPR; 148 out->v.expr.bytes = lbytes; 149 out->v.expr.len = llen; 150 return; 151 } 152 /* No location at all — leave kind=EXPR with NULL/0. */ 153 out->kind = KIT_DLOC_EXPR; 154 out->v.expr.bytes = NULL; 155 out->v.expr.len = 0; 156 } 157 158 KitStatus kit_dwarf_var_at(KitDebugInfo* d, uint64_t pc, KitSlice name, 159 KitDwarfVarLoc* out) { 160 /* Status codes: 161 * KIT_OK — found; *out filled. 162 * KIT_INVALID — bad args. 163 * KIT_NOT_FOUND — pc inside a subprog but no var named `name`, or 164 * pc outside any subprogram and not a global. 165 */ 166 DwSubprog* sp; 167 u32 i; 168 if (!d || !name.s || !out) return KIT_INVALID; 169 memset(out, 0, sizeof(*out)); 170 sp = dw_find_subprog(d, pc); 171 if (sp) { 172 dw_build_locals(d, sp); 173 /* Deepest scope first: walk locals from end (innermost blocks added 174 * after enclosing). */ 175 for (i = sp->nlocals; i > 0; --i) { 176 DwLocal* v = &sp->locals[i - 1]; 177 if (!v->name || !dw_streq(v->name, name.s)) continue; 178 if (v->has_scope && (pc < v->scope_lo || pc >= v->scope_hi)) continue; 179 fill_varloc(d, sp->cu_idx, v, pc, out); 180 return KIT_OK; 181 } 182 /* Then params. */ 183 for (i = 0; i < sp->nparams; ++i) { 184 DwLocal* v = &sp->params[i]; 185 if (!v->name || !dw_streq(v->name, name.s)) continue; 186 fill_varloc(d, sp->cu_idx, v, pc, out); 187 return KIT_OK; 188 } 189 } 190 /* Globals. */ 191 dw_build_globals(d); 192 for (i = 0; i < d->nglobals; ++i) { 193 DwLocal* v = &d->globals[i]; 194 if (!v->name || !dw_streq(v->name, name.s)) continue; 195 fill_varloc(d, 0, v, pc, out); 196 return KIT_OK; 197 } 198 return KIT_NOT_FOUND; 199 } 200 201 KitStatus kit_dwarf_loc_read(KitDebugInfo* d, const KitDwarfVarLoc* loc, 202 const KitUnwindFrame* frame, 203 KitDwarfReadMemFn read_mem, void* read_user, 204 void* dst, size_t cap, size_t* read_out) { 205 size_t want; 206 if (read_out) *read_out = 0; 207 if (!d || !loc || !frame || !dst) return KIT_INVALID; 208 want = loc->byte_size ? loc->byte_size : cap; 209 if (want > cap) want = cap; 210 switch (loc->kind) { 211 case KIT_DLOC_REG: { 212 uint64_t v = (loc->v.reg < 32) ? frame->regs[loc->v.reg] : 0; 213 size_t n = want > sizeof(v) ? sizeof(v) : want; 214 memcpy(dst, &v, n); 215 if (read_out) *read_out = n; 216 return KIT_OK; 217 } 218 case KIT_DLOC_FRAME_OFS: { 219 uint64_t addr = frame->cfa + (uint64_t)(int64_t)loc->v.frame_ofs; 220 KitStatus st; 221 if (!read_mem) return KIT_INVALID; 222 st = read_mem(read_user, addr, dst, want); 223 if (st != KIT_OK) return st; 224 if (read_out) *read_out = want; 225 return KIT_OK; 226 } 227 case KIT_DLOC_GLOBAL: { 228 uint64_t addr = loc->v.global; 229 KitStatus st; 230 if (!read_mem) return KIT_INVALID; 231 st = read_mem(read_user, addr, dst, want); 232 if (st != KIT_OK) return st; 233 if (read_out) *read_out = want; 234 return KIT_OK; 235 } 236 case KIT_DLOC_EXPR: { 237 /* Evaluate. We don't have direct access to the variable's 238 * subprogram's frame_base here — caller-supplied frame must already 239 * carry the right CFA. The expression itself may be DW_OP_call_frame_cfa 240 * + DW_OP_consts + DW_OP_plus, etc. */ 241 DwExprResult r; 242 if (loc->v.expr.bytes == NULL || loc->v.expr.len == 0) 243 return KIT_NOT_FOUND; 244 if (dw_eval_expr(d, loc->v.expr.bytes, (u32)loc->v.expr.len, NULL, 0, 245 frame, &r) != 0) 246 return KIT_UNSUPPORTED; 247 if (r.kind == 0) { 248 KitStatus st; 249 if (!read_mem) return KIT_INVALID; 250 st = read_mem(read_user, r.value, dst, want); 251 if (st != KIT_OK) return st; 252 if (read_out) *read_out = want; 253 return KIT_OK; 254 } else if (r.kind == 1) { 255 size_t n = want > sizeof(r.value) ? sizeof(r.value) : want; 256 memcpy(dst, &r.value, n); 257 if (read_out) *read_out = n; 258 return KIT_OK; 259 } else if (r.kind == 2) { 260 u64 v = (r.value < 32) ? frame->regs[r.value] : 0; 261 size_t n = want > sizeof(v) ? sizeof(v) : want; 262 memcpy(dst, &v, n); 263 if (read_out) *read_out = n; 264 return KIT_OK; 265 } 266 return KIT_UNSUPPORTED; 267 } 268 } 269 return KIT_UNSUPPORTED; 270 } 271 272 /* ---- vars_at_* iterator --------------------------------------------- */ 273 274 struct KitDwarfVarIter { 275 KitDebugInfo* d; 276 DwSubprog* sp; 277 u64 pc; 278 u32 mask; 279 u32 phase; /* 0 = locals, 1 = params, 2 = globals, 3 = done */ 280 u32 idx; 281 }; 282 283 KitStatus kit_dwarf_vars_at_new(KitDebugInfo* d, uint64_t pc, uint32_t mask, 284 KitDwarfVarIter** out) { 285 KitDwarfVarIter* it; 286 if (!out) return KIT_INVALID; 287 *out = NULL; 288 if (!d) return KIT_INVALID; 289 it = (KitDwarfVarIter*)d->h->alloc(d->h, sizeof(*it), 290 _Alignof(KitDwarfVarIter)); 291 if (!it) return KIT_NOMEM; 292 it->d = d; 293 it->pc = pc; 294 it->mask = mask; 295 it->sp = dw_find_subprog(d, pc); 296 if (it->sp) dw_build_locals(d, it->sp); 297 it->phase = 0; 298 it->idx = it->sp ? it->sp->nlocals : 0; 299 *out = it; 300 return KIT_OK; 301 } 302 303 KitIterResult kit_dwarf_vars_at_next(KitDwarfVarIter* it, KitDwarfVar* out) { 304 if (!it || !out) return KIT_ITER_ERROR; 305 for (;;) { 306 switch (it->phase) { 307 case 0: { 308 if (!(it->mask & (1u << KIT_DVR_LOCAL))) { 309 it->phase = 1; 310 it->idx = 0; 311 break; 312 } 313 if (it->idx == 0) { 314 it->phase = 1; 315 it->idx = 0; 316 break; 317 } 318 { 319 DwLocal* v = &it->sp->locals[--it->idx]; 320 if (v->has_scope && (it->pc < v->scope_lo || it->pc >= v->scope_hi)) 321 break; 322 out->name = v->name ? kit_slice_cstr(v->name) : KIT_SLICE_NULL; 323 out->role = KIT_DVR_LOCAL; 324 fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); 325 return KIT_ITER_ITEM; 326 } 327 } 328 case 1: { 329 if (!it->sp || !(it->mask & (1u << KIT_DVR_ARG))) { 330 it->phase = 2; 331 it->idx = 0; 332 break; 333 } 334 if (it->idx >= it->sp->nparams) { 335 it->phase = 2; 336 it->idx = 0; 337 break; 338 } 339 { 340 DwLocal* v = &it->sp->params[it->idx++]; 341 out->name = v->name ? kit_slice_cstr(v->name) : KIT_SLICE_NULL; 342 out->role = KIT_DVR_ARG; 343 fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); 344 return KIT_ITER_ITEM; 345 } 346 } 347 case 2: { 348 if (!(it->mask & (1u << KIT_DVR_GLOBAL))) { 349 it->phase = 3; 350 break; 351 } 352 dw_build_globals(it->d); 353 if (it->idx >= it->d->nglobals) { 354 it->phase = 3; 355 break; 356 } 357 { 358 DwLocal* v = &it->d->globals[it->idx++]; 359 out->name = v->name ? kit_slice_cstr(v->name) : KIT_SLICE_NULL; 360 out->role = KIT_DVR_GLOBAL; 361 fill_varloc(it->d, 0, v, it->pc, &out->loc); 362 return KIT_ITER_ITEM; 363 } 364 } 365 default: 366 return KIT_ITER_END; 367 } 368 } 369 } 370 371 void kit_dwarf_vars_at_free(KitDwarfVarIter* it) { 372 if (!it) return; 373 it->d->h->free(it->d->h, it, sizeof(*it)); 374 } 375 376 /* ---- param_iter_* --------------------------------------------------- */ 377 378 struct KitDwarfParamIter { 379 KitDebugInfo* d; 380 DwSubprog* sp; 381 u64 pc; 382 u32 idx; 383 }; 384 385 KitStatus kit_dwarf_param_iter_new(KitDebugInfo* d, uint64_t pc, 386 KitDwarfParamIter** out) { 387 KitDwarfParamIter* it; 388 DwSubprog* sp; 389 if (!out) return KIT_INVALID; 390 *out = NULL; 391 if (!d) return KIT_INVALID; 392 sp = dw_find_subprog(d, pc); 393 if (!sp) return KIT_NOT_FOUND; 394 dw_build_locals(d, sp); 395 it = (KitDwarfParamIter*)d->h->alloc(d->h, sizeof(*it), 396 _Alignof(KitDwarfParamIter)); 397 if (!it) return KIT_NOMEM; 398 it->d = d; 399 it->sp = sp; 400 it->pc = pc; 401 it->idx = 0; 402 *out = it; 403 return KIT_OK; 404 } 405 406 KitStatus kit_dwarf_param_iter_new_named(KitDebugInfo* d, KitSlice name, 407 KitDwarfParamIter** out) { 408 KitDwarfParamIter* it; 409 DwSubprog* sp; 410 if (!out) return KIT_INVALID; 411 *out = NULL; 412 if (!d || !name.s) return KIT_INVALID; 413 sp = dw_find_subprog_named(d, name.s); 414 if (!sp) return KIT_NOT_FOUND; 415 dw_build_locals(d, sp); 416 it = (KitDwarfParamIter*)d->h->alloc(d->h, sizeof(*it), 417 _Alignof(KitDwarfParamIter)); 418 if (!it) return KIT_NOMEM; 419 it->d = d; 420 it->sp = sp; 421 it->pc = sp->low_pc; 422 it->idx = 0; 423 *out = it; 424 return KIT_OK; 425 } 426 427 KitIterResult kit_dwarf_param_iter_next(KitDwarfParamIter* it, 428 KitDwarfVar* out) { 429 if (!it || !out) return KIT_ITER_ERROR; 430 if (it->idx >= it->sp->nparams) return KIT_ITER_END; 431 { 432 DwLocal* v = &it->sp->params[it->idx++]; 433 out->name = v->name ? kit_slice_cstr(v->name) : KIT_SLICE_NULL; 434 out->role = KIT_DVR_ARG; 435 fill_varloc(it->d, it->sp->cu_idx, v, it->pc, &out->loc); 436 } 437 return KIT_ITER_ITEM; 438 } 439 440 void kit_dwarf_param_iter_free(KitDwarfParamIter* it) { 441 if (!it) return; 442 it->d->h->free(it->d->h, it, sizeof(*it)); 443 }