dwarf_dump.c (13361B)
1 /* dwarf_dump.c — structural enumeration of DWARF sections. 2 * 3 * Implements the kit_dwarf_*_iter API used by `objdump --dwarf` and 4 * similar dumpers. Unlike the PC/name-keyed query API, these walk the raw 5 * .debug_info / .debug_abbrev / .debug_line / .debug_str structure and 6 * hand back numeric DWARF codes; symbolic rendering is the caller's job. 7 * 8 * The iterators are thin cursors over the consumer state already built by 9 * dwarf_open.c (CUs, abbrev tables) and dwarf_line.c (decoded line rows). 10 */ 11 12 #include <kit/dwarf.h> 13 #include <stddef.h> 14 #include <stdint.h> 15 16 #include "core/core.h" 17 #include "core/heap.h" 18 #include "debug/dwarf_defs.h" 19 #include "debug/dwarf_internal.h" 20 21 /* ---- shared helpers --------------------------------------------------- */ 22 23 #define DW_ITER_ALLOC(d, T) ((T*)(d)->h->alloc((d)->h, sizeof(T), _Alignof(T))) 24 25 static void dw_iter_free(KitDebugInfo* d, void* p, size_t n) { 26 if (p) d->h->free(d->h, p, n); 27 } 28 29 /* Find the CU index whose header sits at `cu_offset`, or UINT32_MAX. */ 30 static u32 dw_cu_index_at(KitDebugInfo* d, u32 cu_offset) { 31 u32 i; 32 for (i = 0; i < d->ncus; ++i) { 33 if (d->cus[i].hdr_offset == cu_offset) return i; 34 } 35 return UINT32_MAX; 36 } 37 38 /* ---- CU iterator ------------------------------------------------------ */ 39 40 struct KitDwarfCuIter { 41 KitDebugInfo* d; 42 u32 idx; 43 }; 44 45 KitStatus kit_dwarf_cu_iter_new(KitDebugInfo* d, KitDwarfCuIter** out) { 46 KitDwarfCuIter* it; 47 if (!out) return KIT_INVALID; 48 *out = NULL; 49 if (!d) return KIT_INVALID; 50 dw_parse_all_cus(d); 51 it = DW_ITER_ALLOC(d, KitDwarfCuIter); 52 if (!it) return KIT_NOMEM; 53 it->d = d; 54 it->idx = 0; 55 *out = it; 56 return KIT_OK; 57 } 58 59 KitIterResult kit_dwarf_cu_iter_next(KitDwarfCuIter* it, KitDwarfCu* out) { 60 DwCu* cu; 61 if (!it || !out) return KIT_ITER_ERROR; 62 if (it->idx >= it->d->ncus) return KIT_ITER_END; 63 cu = &it->d->cus[it->idx++]; 64 out->offset = cu->hdr_offset; 65 out->length = cu->hdr_length; 66 out->version = cu->version; 67 out->address_size = cu->address_size; 68 out->unit_type = cu->unit_type; 69 out->abbrev_offset = cu->abbrev_offset; 70 out->is_64bit = cu->is_64bit != 0; 71 return KIT_ITER_ITEM; 72 } 73 74 void kit_dwarf_cu_iter_free(KitDwarfCuIter* it) { 75 if (it) dw_iter_free(it->d, it, sizeof(*it)); 76 } 77 78 /* ---- DIE iterator (depth-first across all CUs) ------------------------ */ 79 80 struct KitDwarfDieIter { 81 KitDebugInfo* d; 82 u32 cu_idx; /* current CU */ 83 u32 off; /* cursor into .debug_info */ 84 u32 depth; /* current nesting level */ 85 }; 86 87 KitStatus kit_dwarf_die_iter_new(KitDebugInfo* d, KitDwarfDieIter** out) { 88 KitDwarfDieIter* it; 89 if (!out) return KIT_INVALID; 90 *out = NULL; 91 if (!d) return KIT_INVALID; 92 dw_parse_all_cus(d); 93 it = DW_ITER_ALLOC(d, KitDwarfDieIter); 94 if (!it) return KIT_NOMEM; 95 it->d = d; 96 it->cu_idx = 0; 97 it->depth = 0; 98 it->off = d->ncus ? d->cus[0].die_start_off : 0; 99 *out = it; 100 return KIT_OK; 101 } 102 103 KitIterResult kit_dwarf_die_iter_next(KitDwarfDieIter* it, KitDwarfDie* out) { 104 KitDebugInfo* d; 105 if (!it || !out) return KIT_ITER_ERROR; 106 d = it->d; 107 for (;;) { 108 DwCu* cu; 109 DwDie die; 110 if (it->cu_idx >= d->ncus) return KIT_ITER_END; 111 cu = &d->cus[it->cu_idx]; 112 if (!dw_read_die(d, cu, &it->off, &die)) { 113 /* Null entry or end-of-CU: close one level, or advance to the next 114 * CU when we have unwound back past the root. */ 115 if (it->depth > 0) { 116 it->depth--; 117 continue; 118 } 119 it->cu_idx++; 120 it->depth = 0; 121 if (it->cu_idx < d->ncus) it->off = d->cus[it->cu_idx].die_start_off; 122 continue; 123 } 124 out->offset = die.die_off; 125 out->cu_offset = cu->hdr_offset; 126 out->tag = die.abbrev ? die.abbrev->tag : 0; 127 out->depth = it->depth; 128 out->has_children = die.abbrev && die.abbrev->has_children; 129 dw_skip_die_attrs(d, cu, &die, &it->off); 130 if (die.abbrev && die.abbrev->has_children) it->depth++; 131 return KIT_ITER_ITEM; 132 } 133 } 134 135 void kit_dwarf_die_iter_free(KitDwarfDieIter* it) { 136 if (it) dw_iter_free(it->d, it, sizeof(*it)); 137 } 138 139 /* ---- DIE attribute iterator ------------------------------------------- */ 140 141 struct KitDwarfAttrIter { 142 KitDebugInfo* d; 143 const DwCu* cu; 144 DwAbbrev* abbrev; 145 u32 attr_idx; /* index into abbrev->attrs */ 146 u32 off; /* running cursor in .debug_info */ 147 }; 148 149 static KitDwarfFormClass dw_form_class(u32 form) { 150 switch (form) { 151 case DW_FORM_string: 152 case DW_FORM_strp: 153 case DW_FORM_line_strp: 154 case DW_FORM_strx: 155 case DW_FORM_strx1: 156 case DW_FORM_strx2: 157 case DW_FORM_strx3: 158 case DW_FORM_strx4: 159 return KIT_DWARF_FC_STRING; 160 case DW_FORM_addr: 161 case DW_FORM_addrx: 162 case DW_FORM_addrx1: 163 case DW_FORM_addrx2: 164 case DW_FORM_addrx3: 165 case DW_FORM_addrx4: 166 return KIT_DWARF_FC_ADDR; 167 case DW_FORM_ref1: 168 case DW_FORM_ref2: 169 case DW_FORM_ref4: 170 case DW_FORM_ref8: 171 case DW_FORM_ref_udata: 172 case DW_FORM_ref_addr: 173 case DW_FORM_ref_sig8: 174 case DW_FORM_ref_sup4: 175 case DW_FORM_ref_sup8: 176 return KIT_DWARF_FC_REF; 177 case DW_FORM_sdata: 178 return KIT_DWARF_FC_SDATA; 179 case DW_FORM_flag: 180 case DW_FORM_flag_present: 181 return KIT_DWARF_FC_FLAG; 182 case DW_FORM_block: 183 case DW_FORM_block1: 184 case DW_FORM_block2: 185 case DW_FORM_block4: 186 case DW_FORM_exprloc: 187 case DW_FORM_data16: 188 return KIT_DWARF_FC_BLOCK; 189 case DW_FORM_data1: 190 case DW_FORM_data2: 191 case DW_FORM_data4: 192 case DW_FORM_data8: 193 case DW_FORM_udata: 194 case DW_FORM_sec_offset: 195 case DW_FORM_loclistx: 196 case DW_FORM_rnglistx: 197 case DW_FORM_implicit_const: 198 return KIT_DWARF_FC_UDATA; 199 default: 200 return KIT_DWARF_FC_UNKNOWN; 201 } 202 } 203 204 KitStatus kit_dwarf_attr_iter_new(KitDebugInfo* d, uint32_t die_offset, 205 KitDwarfAttrIter** out) { 206 KitDwarfAttrIter* it; 207 DwCu* cu; 208 DwDie die; 209 u32 off; 210 if (!out) return KIT_INVALID; 211 *out = NULL; 212 if (!d) return KIT_INVALID; 213 dw_parse_all_cus(d); 214 cu = dw_cu_at_die_offset(d, die_offset); 215 if (!cu) return KIT_NOT_FOUND; 216 off = die_offset; 217 if (!dw_read_die(d, cu, &off, &die) || !die.abbrev) return KIT_NOT_FOUND; 218 it = DW_ITER_ALLOC(d, KitDwarfAttrIter); 219 if (!it) return KIT_NOMEM; 220 it->d = d; 221 it->cu = cu; 222 it->abbrev = die.abbrev; 223 it->attr_idx = 0; 224 it->off = die.attrs_off; 225 *out = it; 226 return KIT_OK; 227 } 228 229 KitIterResult kit_dwarf_attr_iter_next(KitDwarfAttrIter* it, 230 KitDwarfAttr* out) { 231 DwAbbrevAttr* spec; 232 DwAttrValue v; 233 if (!it || !out) return KIT_ITER_ERROR; 234 if (it->attr_idx >= it->abbrev->nattrs) return KIT_ITER_END; 235 spec = &it->abbrev->attrs[it->attr_idx++]; 236 dw_read_form(it->d, it->cu, spec->form, spec->implicit_const, &it->off, &v); 237 out->attr = spec->attr; 238 out->form = spec->form; 239 out->form_class = dw_form_class(spec->form); 240 out->u = v.u; 241 out->s = v.s; 242 out->str = v.str ? kit_slice_cstr(v.str) : KIT_SLICE_NULL; 243 out->block = v.block; 244 out->block_len = v.block_len; 245 return KIT_ITER_ITEM; 246 } 247 248 void kit_dwarf_attr_iter_free(KitDwarfAttrIter* it) { 249 if (it) dw_iter_free(it->d, it, sizeof(*it)); 250 } 251 252 /* ---- abbrev iterators ------------------------------------------------- */ 253 254 struct KitDwarfAbbrevIter { 255 KitDebugInfo* d; 256 u32 tbl; /* index into d->abbrevs */ 257 u32 slot; /* index into table->abbrevs */ 258 }; 259 260 /* Ensure every CU's abbrev table is materialized before walking them. */ 261 static void dw_ensure_abbrevs(KitDebugInfo* d) { 262 u32 i; 263 dw_parse_all_cus(d); 264 for (i = 0; i < d->ncus; ++i) dw_abbrev_get(d, d->cus[i].abbrev_offset); 265 } 266 267 KitStatus kit_dwarf_abbrev_iter_new(KitDebugInfo* d, KitDwarfAbbrevIter** out) { 268 KitDwarfAbbrevIter* it; 269 if (!out) return KIT_INVALID; 270 *out = NULL; 271 if (!d) return KIT_INVALID; 272 dw_ensure_abbrevs(d); 273 it = DW_ITER_ALLOC(d, KitDwarfAbbrevIter); 274 if (!it) return KIT_NOMEM; 275 it->d = d; 276 it->tbl = 0; 277 it->slot = 0; 278 *out = it; 279 return KIT_OK; 280 } 281 282 KitIterResult kit_dwarf_abbrev_iter_next(KitDwarfAbbrevIter* it, 283 KitDwarfAbbrev* out) { 284 KitDebugInfo* d; 285 if (!it || !out) return KIT_ITER_ERROR; 286 d = it->d; 287 while (it->tbl < d->nabbrevs) { 288 DwAbbrevTable* t = &d->abbrevs[it->tbl]; 289 if (it->slot >= t->nabbrevs) { 290 it->tbl++; 291 it->slot = 0; 292 continue; 293 } 294 { 295 DwAbbrev* a = &t->abbrevs[it->slot++]; 296 if (a->code == 0) continue; /* unused slot */ 297 out->table_offset = t->cu_abbrev_offset; 298 out->code = a->code; 299 out->tag = a->tag; 300 out->has_children = a->has_children != 0; 301 return KIT_ITER_ITEM; 302 } 303 } 304 return KIT_ITER_END; 305 } 306 307 void kit_dwarf_abbrev_iter_free(KitDwarfAbbrevIter* it) { 308 if (it) dw_iter_free(it->d, it, sizeof(*it)); 309 } 310 311 struct KitDwarfAbbrevAttrIter { 312 KitDebugInfo* d; 313 DwAbbrev* abbrev; 314 u32 idx; 315 }; 316 317 KitStatus kit_dwarf_abbrev_attr_iter_new(KitDebugInfo* d, uint32_t table_offset, 318 uint64_t code, 319 KitDwarfAbbrevAttrIter** out) { 320 KitDwarfAbbrevAttrIter* it; 321 DwAbbrevTable* t; 322 DwAbbrev* a; 323 if (!out) return KIT_INVALID; 324 *out = NULL; 325 if (!d) return KIT_INVALID; 326 dw_ensure_abbrevs(d); 327 t = dw_abbrev_get(d, table_offset); 328 if (!t) return KIT_NOT_FOUND; 329 a = dw_abbrev_lookup(t, code); 330 if (!a) return KIT_NOT_FOUND; 331 it = DW_ITER_ALLOC(d, KitDwarfAbbrevAttrIter); 332 if (!it) return KIT_NOMEM; 333 it->d = d; 334 it->abbrev = a; 335 it->idx = 0; 336 *out = it; 337 return KIT_OK; 338 } 339 340 KitIterResult kit_dwarf_abbrev_attr_iter_next(KitDwarfAbbrevAttrIter* it, 341 KitDwarfAbbrevAttr* out) { 342 DwAbbrevAttr* aa; 343 if (!it || !out) return KIT_ITER_ERROR; 344 if (it->idx >= it->abbrev->nattrs) return KIT_ITER_END; 345 aa = &it->abbrev->attrs[it->idx++]; 346 out->attr = aa->attr; 347 out->form = aa->form; 348 out->implicit_const = aa->implicit_const; 349 return KIT_ITER_ITEM; 350 } 351 352 void kit_dwarf_abbrev_attr_iter_free(KitDwarfAbbrevAttrIter* it) { 353 if (it) dw_iter_free(it->d, it, sizeof(*it)); 354 } 355 356 /* ---- line row iterator ------------------------------------------------ */ 357 358 struct KitDwarfLineIter { 359 KitDebugInfo* d; 360 u32 cu_idx; 361 u32 row; 362 }; 363 364 KitStatus kit_dwarf_line_iter_new(KitDebugInfo* d, uint32_t cu_offset, 365 KitDwarfLineIter** out) { 366 KitDwarfLineIter* it; 367 u32 cu_idx; 368 if (!out) return KIT_INVALID; 369 *out = NULL; 370 if (!d) return KIT_INVALID; 371 dw_parse_all_cus(d); 372 cu_idx = dw_cu_index_at(d, cu_offset); 373 if (cu_idx == UINT32_MAX) return KIT_NOT_FOUND; 374 if (!d->cus[cu_idx].has_stmt_list) return KIT_NOT_FOUND; 375 if (!d->lines_built[cu_idx]) dw_build_line(d, cu_idx); 376 it = DW_ITER_ALLOC(d, KitDwarfLineIter); 377 if (!it) return KIT_NOMEM; 378 it->d = d; 379 it->cu_idx = cu_idx; 380 it->row = 0; 381 *out = it; 382 return KIT_OK; 383 } 384 385 KitIterResult kit_dwarf_line_iter_next(KitDwarfLineIter* it, 386 KitDwarfLineRow* out) { 387 DwLineProgram* lp; 388 DwLineRow* r; 389 if (!it || !out) return KIT_ITER_ERROR; 390 lp = &it->d->lines_by_cu[it->cu_idx]; 391 if (it->row >= lp->nrows) return KIT_ITER_END; 392 r = &lp->rows[it->row++]; 393 out->address = r->address; 394 out->file_index = r->file_index; 395 out->line = r->line; 396 out->column = r->column; 397 out->is_stmt = r->is_stmt != 0; 398 out->end_sequence = r->end_sequence != 0; 399 return KIT_ITER_ITEM; 400 } 401 402 void kit_dwarf_line_iter_free(KitDwarfLineIter* it) { 403 if (it) dw_iter_free(it->d, it, sizeof(*it)); 404 } 405 406 KitStatus kit_dwarf_line_file(KitDebugInfo* d, uint32_t cu_offset, 407 uint32_t file_index, KitSlice* out) { 408 u32 cu_idx; 409 DwLineProgram* lp; 410 const char* path = NULL; 411 if (!out) return KIT_INVALID; 412 *out = KIT_SLICE_NULL; 413 if (!d) return KIT_INVALID; 414 dw_parse_all_cus(d); 415 cu_idx = dw_cu_index_at(d, cu_offset); 416 if (cu_idx == UINT32_MAX) return KIT_NOT_FOUND; 417 if (!d->cus[cu_idx].has_stmt_list) return KIT_NOT_FOUND; 418 if (!d->lines_built[cu_idx]) dw_build_line(d, cu_idx); 419 lp = &d->lines_by_cu[cu_idx]; 420 if (file_index < lp->nfile_norm && lp->file_norm[file_index]) 421 path = lp->file_norm[file_index]; 422 else if (file_index < lp->nfiles) 423 path = lp->files[file_index].path; 424 if (!path) return KIT_NOT_FOUND; 425 *out = kit_slice_cstr(path); 426 return KIT_OK; 427 } 428 429 /* ---- .debug_str iterator ---------------------------------------------- */ 430 431 struct KitDwarfStrIter { 432 KitDebugInfo* d; 433 u32 off; 434 }; 435 436 KitStatus kit_dwarf_str_iter_new(KitDebugInfo* d, KitDwarfStrIter** out) { 437 KitDwarfStrIter* it; 438 if (!out) return KIT_INVALID; 439 *out = NULL; 440 if (!d) return KIT_INVALID; 441 it = DW_ITER_ALLOC(d, KitDwarfStrIter); 442 if (!it) return KIT_NOMEM; 443 it->d = d; 444 it->off = 0; 445 *out = it; 446 return KIT_OK; 447 } 448 449 KitIterResult kit_dwarf_str_iter_next(KitDwarfStrIter* it, KitDwarfStr* out) { 450 KitDebugInfo* d; 451 const u8* base; 452 u32 size, start, n; 453 if (!it || !out) return KIT_ITER_ERROR; 454 d = it->d; 455 base = d->str.data; 456 size = d->str.size; 457 if (!base || it->off >= size) return KIT_ITER_END; 458 start = it->off; 459 n = 0; 460 while (it->off < size && base[it->off] != 0) { 461 it->off++; 462 n++; 463 } 464 if (it->off < size) it->off++; /* step over the NUL */ 465 out->offset = start; 466 out->str.s = (const char*)(base + start); 467 out->str.len = n; 468 return KIT_ITER_ITEM; 469 } 470 471 void kit_dwarf_str_iter_free(KitDwarfStrIter* it) { 472 if (it) dw_iter_free(it->d, it, sizeof(*it)); 473 }