dwarf_open.c (25370B)
1 /* dwarf_open.c — open/close, section lookup, primitives, abbrev cache. 2 * 3 * Per doc/DWARF.md §4.1: read .debug_abbrev / .debug_info / .debug_line / 4 * .debug_str / .debug_line_str by section name from the KitObjFile. 5 * Return NULL if any of those mandatory five are missing. 6 */ 7 8 #include <kit/arch.h> 9 #include <kit/dwarf.h> 10 #include <kit/object.h> 11 #include <stdint.h> 12 #include <string.h> 13 14 #include "core/core.h" 15 #include "core/heap.h" 16 #include "core/pool.h" 17 #include "core/slice.h" 18 #include "core/util.h" 19 #include "core/vec.h" 20 #include "debug/dwarf_internal.h" 21 #include "obj/obj.h" 22 23 /* ---- section lookup --------------------------------------------------- */ 24 25 void dw_find_section(KitDebugInfo* d, const char* name, DwSection* out) { 26 uint32_t i, n; 27 /* On Mach-O the obj layer reports DWARF sections as "__DWARF,__debug_*" 28 * (16-char-truncated) and .eh_frame as "__TEXT,__eh_frame", not the 29 * ELF ".debug_*"/".eh_frame" spelling. Precompute the Mach-O candidate 30 * for the requested section (via the shared name translator) so one lookup 31 * spans both formats. */ 32 char macho_full[40]; 33 int have_macho = 0; 34 out->data = NULL; 35 out->size = 0; 36 out->sec_idx = UINT32_MAX; 37 if (!d->obj) return; 38 { 39 size_t nl = (size_t)slice_from_cstr(name).len; 40 have_macho = obj_macho_native_secname(name, nl, macho_full); 41 } 42 n = kit_obj_nsections(d->obj); 43 for (i = 0; i < n; ++i) { 44 KitObjSecInfo info; 45 if (kit_obj_section(d->obj, i, &info) != KIT_OK) continue; 46 if (info.name.len && 47 (kit_slice_eq_cstr(info.name, name) || 48 (have_macho && kit_slice_eq_cstr(info.name, macho_full)))) { 49 size_t len = 0; 50 const uint8_t* p = NULL; 51 if (kit_obj_section_data(d->obj, i, &p, &len) != KIT_OK) continue; 52 out->data = p; 53 out->size = (u32)len; 54 out->sec_idx = i; 55 return; 56 } 57 } 58 } 59 60 /* ---- byte-stream primitives ------------------------------------------- */ 61 62 /* On EOF we return zero / empty. The decoder will detect malformed input 63 * via length checks elsewhere; for the consumer we just want to not 64 * crash on truncated bytes. */ 65 66 u8 dw_u8(const u8* base, u32 size, u32* off) { 67 if (*off >= size) return 0; 68 return base[(*off)++]; 69 } 70 u16 dw_u16(const u8* base, u32 size, u32* off) { 71 u16 v; 72 if (*off + 2 > size) { 73 *off = size; 74 return 0; 75 } 76 v = (u16)base[*off] | ((u16)base[*off + 1] << 8); 77 *off += 2; 78 return v; 79 } 80 u32 dw_u24(const u8* base, u32 size, u32* off) { 81 u32 v; 82 if (*off + 3 > size) { 83 *off = size; 84 return 0; 85 } 86 v = (u32)base[*off] | ((u32)base[*off + 1] << 8) | 87 ((u32)base[*off + 2] << 16); 88 *off += 3; 89 return v; 90 } 91 u32 dw_u32(const u8* base, u32 size, u32* off) { 92 u32 v; 93 if (*off + 4 > size) { 94 *off = size; 95 return 0; 96 } 97 v = (u32)base[*off] | ((u32)base[*off + 1] << 8) | 98 ((u32)base[*off + 2] << 16) | ((u32)base[*off + 3] << 24); 99 *off += 4; 100 return v; 101 } 102 u64 dw_u64(const u8* base, u32 size, u32* off) { 103 u64 v; 104 if (*off + 8 > size) { 105 *off = size; 106 return 0; 107 } 108 v = (u64)base[*off] | ((u64)base[*off + 1] << 8) | 109 ((u64)base[*off + 2] << 16) | ((u64)base[*off + 3] << 24) | 110 ((u64)base[*off + 4] << 32) | ((u64)base[*off + 5] << 40) | 111 ((u64)base[*off + 6] << 48) | ((u64)base[*off + 7] << 56); 112 *off += 8; 113 return v; 114 } 115 u64 dw_uleb(const u8* base, u32 size, u32* off) { 116 u64 v = 0; 117 int shift = 0; 118 while (*off < size) { 119 u8 b = base[(*off)++]; 120 v |= ((u64)(b & 0x7f)) << shift; 121 if (!(b & 0x80)) break; 122 shift += 7; 123 if (shift > 63) break; 124 } 125 return v; 126 } 127 i64 dw_sleb(const u8* base, u32 size, u32* off) { 128 i64 v = 0; 129 int shift = 0; 130 u8 b = 0; 131 while (*off < size) { 132 b = base[(*off)++]; 133 v |= ((i64)(b & 0x7f)) << shift; 134 shift += 7; 135 if (!(b & 0x80)) break; 136 if (shift > 63) break; 137 } 138 if (shift < 64 && (b & 0x40)) { 139 v |= -((i64)1 << shift); 140 } 141 return v; 142 } 143 const char* dw_cstr(const u8* base, u32 size, u32* off) { 144 const char* s = (const char*)base + *off; 145 while (*off < size && base[*off] != 0) (*off)++; 146 if (*off < size) (*off)++; /* consume terminator */ 147 return s; 148 } 149 150 /* ---- string interning ------------------------------------------------- */ 151 152 const char* dw_intern(KitDebugInfo* d, const char* s, size_t len) { 153 Sym sym = pool_intern_slice(d->strs, (Slice){.s = s, .len = len}); 154 return pool_slice(d->strs, sym).s; 155 } 156 157 /* Resolve a .debug_str offset. */ 158 const char* dw_str(KitDebugInfo* d, u32 offset) { 159 if (offset >= d->str.size) return ""; 160 return (const char*)(d->str.data + offset); 161 } 162 163 /* Resolve a .debug_line_str offset. */ 164 const char* dw_line_str(KitDebugInfo* d, u32 offset) { 165 if (offset >= d->line_str.size) return ""; 166 return (const char*)(d->line_str.data + offset); 167 } 168 169 /* Resolve a strx index via .debug_str_offsets + cu->str_offsets_base. */ 170 const char* dw_strx(KitDebugInfo* d, const DwCu* cu, u64 idx) { 171 /* DW5 .debug_str_offsets has a header per contribution: 172 * unit_length (4 or 12), version (2), padding (2), then entries. 173 * cu->str_offsets_base points past the header to the first entry. 174 * If the base attribute is absent we fall back to base=0+8 (assume 32-bit 175 * header at start). */ 176 u32 base = cu->str_offsets_base; 177 u32 ent_size = 4; 178 u32 entry_off = base + (u32)idx * ent_size; 179 u32 str_off; 180 if (entry_off + ent_size > d->str_offsets.size) return ""; 181 { 182 u32 tmp = entry_off; 183 str_off = dw_u32(d->str_offsets.data, d->str_offsets.size, &tmp); 184 } 185 return dw_str(d, str_off); 186 } 187 188 /* ---- abbrev parsing --------------------------------------------------- */ 189 190 static void abbrev_parse_table(KitDebugInfo* d, u32 offset, DwAbbrevTable* t) { 191 u32 off = offset; 192 t->cu_abbrev_offset = offset; 193 t->abbrevs = NULL; 194 t->nabbrevs = 0; 195 t->cap = 0; 196 for (;;) { 197 u64 code; 198 DwAbbrev a; 199 DwAbbrevAttr* attrs = NULL; 200 u32 nattrs = 0, attrs_cap = 0; 201 if (off >= d->abbrev.size) break; 202 code = dw_uleb(d->abbrev.data, d->abbrev.size, &off); 203 if (code == 0) break; /* end-of-table marker */ 204 a.code = code; 205 a.tag = (u32)dw_uleb(d->abbrev.data, d->abbrev.size, &off); 206 a.has_children = dw_u8(d->abbrev.data, d->abbrev.size, &off); 207 a.attrs = NULL; 208 a.nattrs = 0; 209 /* Read (attr, form) pairs until (0,0). */ 210 for (;;) { 211 u32 at = (u32)dw_uleb(d->abbrev.data, d->abbrev.size, &off); 212 u32 fm = (u32)dw_uleb(d->abbrev.data, d->abbrev.size, &off); 213 i64 ic = 0; 214 if (at == 0 && fm == 0) break; 215 if (fm == DW_FORM_implicit_const) { 216 ic = dw_sleb(d->abbrev.data, d->abbrev.size, &off); 217 } 218 if (nattrs == attrs_cap) { 219 u32 ncap = attrs_cap ? attrs_cap * 2 : 4; 220 DwAbbrevAttr* na = (DwAbbrevAttr*)d->h->realloc( 221 d->h, attrs, attrs_cap * sizeof(*attrs), ncap * sizeof(*attrs), 222 _Alignof(DwAbbrevAttr)); 223 if (!na) { 224 if (attrs) d->h->free(d->h, attrs, attrs_cap * sizeof(*attrs)); 225 attrs = NULL; 226 attrs_cap = 0; 227 nattrs = 0; 228 break; 229 } 230 attrs = na; 231 attrs_cap = ncap; 232 } 233 attrs[nattrs].attr = at; 234 attrs[nattrs].form = fm; 235 attrs[nattrs].implicit_const = ic; 236 nattrs++; 237 } 238 a.attrs = attrs; 239 a.nattrs = nattrs; 240 if (t->nabbrevs == t->cap) { 241 u32 ncap = t->cap ? t->cap * 2 : 8; 242 DwAbbrev* na = (DwAbbrev*)d->h->realloc( 243 d->h, t->abbrevs, t->cap * sizeof(*t->abbrevs), 244 ncap * sizeof(*t->abbrevs), _Alignof(DwAbbrev)); 245 if (!na) break; 246 t->abbrevs = na; 247 t->cap = ncap; 248 } 249 t->abbrevs[t->nabbrevs++] = a; 250 } 251 } 252 253 DwAbbrevTable* dw_abbrev_get(KitDebugInfo* d, u32 offset) { 254 u32 i; 255 DwAbbrevTable* t; 256 for (i = 0; i < d->nabbrevs; ++i) { 257 if (d->abbrevs[i].cu_abbrev_offset == offset) return &d->abbrevs[i]; 258 } 259 if (d->nabbrevs == d->abbrevs_cap) { 260 u32 ncap = d->abbrevs_cap ? d->abbrevs_cap * 2 : 4; 261 DwAbbrevTable* na = (DwAbbrevTable*)d->h->realloc( 262 d->h, d->abbrevs, d->abbrevs_cap * sizeof(*d->abbrevs), 263 ncap * sizeof(*d->abbrevs), _Alignof(DwAbbrevTable)); 264 if (!na) return NULL; 265 d->abbrevs = na; 266 d->abbrevs_cap = ncap; 267 } 268 t = &d->abbrevs[d->nabbrevs++]; 269 abbrev_parse_table(d, offset, t); 270 return t; 271 } 272 273 DwAbbrev* dw_abbrev_lookup(DwAbbrevTable* t, u64 code) { 274 u32 i; 275 if (!t) return NULL; 276 for (i = 0; i < t->nabbrevs; ++i) { 277 if (t->abbrevs[i].code == code) return &t->abbrevs[i]; 278 } 279 return NULL; 280 } 281 282 /* ---- CU header parsing ----------------------------------------------- */ 283 284 u32 dw_cu_parse_header(KitDebugInfo* d, u32 off, DwCu* cu) { 285 u32 start = off; 286 u32 unit_length; 287 u32 hdr_after_len_off; 288 cu->hdr_offset = start; 289 cu->is_64bit = 0; 290 unit_length = dw_u32(d->info.data, d->info.size, &off); 291 if (unit_length == 0xffffffffu) { 292 /* DWARF64 — initial length followed by 8-byte length. We don't 293 * fully support DWARF64 ourselves, but skip the unit. */ 294 cu->is_64bit = 1; 295 cu->hdr_length = 0; 296 cu->unit_total_size = 0; 297 /* Skip past CU. */ 298 { 299 u64 ulen = dw_u64(d->info.data, d->info.size, &off); 300 cu->unit_total_size = 12 + (u32)ulen; 301 } 302 return start + cu->unit_total_size; 303 } 304 cu->hdr_length = unit_length; 305 cu->unit_total_size = 4 + unit_length; 306 hdr_after_len_off = off; /* points just past unit_length */ 307 cu->version = (u8)dw_u16(d->info.data, d->info.size, &off); 308 if (cu->version >= 5) { 309 cu->unit_type = dw_u8(d->info.data, d->info.size, &off); 310 cu->address_size = dw_u8(d->info.data, d->info.size, &off); 311 cu->abbrev_offset = dw_u32(d->info.data, d->info.size, &off); 312 } else { 313 /* DW4 layout: abbrev_offset, address_size. */ 314 cu->unit_type = 0; 315 cu->abbrev_offset = dw_u32(d->info.data, d->info.size, &off); 316 cu->address_size = dw_u8(d->info.data, d->info.size, &off); 317 } 318 cu->die_start_off = off; 319 cu->str_offsets_base = 0; 320 cu->addr_base = 0; 321 cu->loclists_base = 0; 322 cu->rnglists_base = 0; 323 cu->stmt_list = 0; 324 cu->has_stmt_list = 0; 325 cu->comp_dir = ""; 326 cu->name = ""; 327 /* Resolve abbrev table now (cheap & idempotent). */ 328 { 329 DwAbbrevTable* t = dw_abbrev_get(d, cu->abbrev_offset); 330 cu->abbrev_table_idx = (u32)(t ? (t - d->abbrevs) : 0); 331 } 332 (void)hdr_after_len_off; 333 return start + cu->unit_total_size; 334 } 335 336 /* Read the CU root DIE to capture base attributes (str_offsets_base, 337 * addr_base, stmt_list, name, comp_dir). Restores no state — leaves the 338 * CU in its parsed-header form. */ 339 static void cu_read_root_attrs(KitDebugInfo* d, DwCu* cu) { 340 u32 off = cu->die_start_off; 341 u64 code; 342 DwAbbrev* ab; 343 DwAttrValue v; 344 u32 i; 345 DwAbbrevTable* t = &d->abbrevs[cu->abbrev_table_idx]; 346 if (off >= d->info.size) return; 347 code = dw_uleb(d->info.data, d->info.size, &off); 348 if (code == 0) return; 349 ab = dw_abbrev_lookup(t, code); 350 if (!ab) return; 351 /* First pass: pull str_offsets_base if present (so subsequent strx 352 * resolutions work). */ 353 for (i = 0; i < ab->nattrs; ++i) { 354 DwAbbrevAttr* aa = &ab->attrs[i]; 355 if (aa->attr == DW_AT_str_offsets_base) { 356 u32 tmp = off; 357 /* Skip preceding attrs to locate this attr's payload — easier 358 * to do a full pass and remember offsets. We re-scan instead. */ 359 (void)tmp; 360 break; 361 } 362 } 363 /* Two-pass scan: do skipping reads, but capture base attrs. We must 364 * be careful: dw_read_form for strx forms uses cu->str_offsets_base, 365 * so we read in two passes. */ 366 off = cu->die_start_off; 367 (void)dw_uleb(d->info.data, d->info.size, &off); /* re-skip code */ 368 /* Pass 1: only read str_offsets_base / addr_base (forms that don't 369 * themselves need those bases). */ 370 for (i = 0; i < ab->nattrs; ++i) { 371 DwAbbrevAttr* aa = &ab->attrs[i]; 372 if (aa->attr == DW_AT_str_offsets_base || aa->attr == DW_AT_addr_base || 373 aa->attr == DW_AT_loclists_base || aa->attr == DW_AT_rnglists_base) { 374 dw_read_form(d, cu, aa->form, aa->implicit_const, &off, &v); 375 if (aa->attr == DW_AT_str_offsets_base) 376 cu->str_offsets_base = (u32)v.u; 377 else if (aa->attr == DW_AT_addr_base) 378 cu->addr_base = (u32)v.u; 379 else if (aa->attr == DW_AT_loclists_base) 380 cu->loclists_base = (u32)v.u; 381 else if (aa->attr == DW_AT_rnglists_base) 382 cu->rnglists_base = (u32)v.u; 383 } else { 384 dw_skip_form(d, cu, aa->form, aa->implicit_const, &off); 385 } 386 } 387 /* Pass 2: read remaining attrs (stmt_list, name, comp_dir). */ 388 off = cu->die_start_off; 389 (void)dw_uleb(d->info.data, d->info.size, &off); 390 for (i = 0; i < ab->nattrs; ++i) { 391 DwAbbrevAttr* aa = &ab->attrs[i]; 392 if (aa->attr == DW_AT_stmt_list) { 393 dw_read_form(d, cu, aa->form, aa->implicit_const, &off, &v); 394 cu->stmt_list = (u32)v.u; 395 cu->has_stmt_list = 1; 396 } else if (aa->attr == DW_AT_name) { 397 dw_read_form(d, cu, aa->form, aa->implicit_const, &off, &v); 398 cu->name = v.str ? v.str : ""; 399 } else if (aa->attr == DW_AT_comp_dir) { 400 dw_read_form(d, cu, aa->form, aa->implicit_const, &off, &v); 401 cu->comp_dir = v.str ? v.str : ""; 402 } else { 403 dw_skip_form(d, cu, aa->form, aa->implicit_const, &off); 404 } 405 } 406 } 407 408 void dw_parse_all_cus(KitDebugInfo* d) { 409 u32 off = 0; 410 /* Idempotent: a successful kit_dwarf_open already populates d->cus, and 411 * the structural-enumeration iterators call this again. Re-parsing would 412 * append duplicate CUs, so bail once the table is built. */ 413 if (d->ncus) return; 414 while (off < d->info.size) { 415 DwCu cu; 416 u32 next = dw_cu_parse_header(d, off, &cu); 417 if (next <= off) break; 418 if (cu.is_64bit) { 419 off = next; 420 continue; 421 } 422 if (cu.version < 2 || cu.version > 5) { 423 off = next; 424 continue; 425 } 426 if (d->ncus == d->cus_cap) { 427 u32 ncap = d->cus_cap ? d->cus_cap * 2 : 4; 428 DwCu* na = 429 (DwCu*)d->h->realloc(d->h, d->cus, d->cus_cap * sizeof(*d->cus), 430 ncap * sizeof(*d->cus), _Alignof(DwCu)); 431 if (!na) break; 432 d->cus = na; 433 d->cus_cap = ncap; 434 } 435 d->cus[d->ncus++] = cu; 436 /* Capture root attrs now. */ 437 cu_read_root_attrs(d, &d->cus[d->ncus - 1]); 438 off = next; 439 } 440 } 441 442 DwCu* dw_cu_at_die_offset(KitDebugInfo* d, u32 die_offset) { 443 u32 i; 444 for (i = 0; i < d->ncus; ++i) { 445 DwCu* cu = &d->cus[i]; 446 if (die_offset >= cu->hdr_offset && 447 die_offset < cu->hdr_offset + cu->unit_total_size) { 448 return cu; 449 } 450 } 451 return NULL; 452 } 453 454 /* ---- form decoding ---------------------------------------------------- */ 455 456 /* Section-parameterized form decoder. Inline form bytes are pulled from 457 * `sec` (.debug_info for DIE attributes, .debug_line for line-program 458 * file/dir entry-format values); strp/line_strp/strx still resolve into the 459 * shared string sections via the CU. This is the single source of truth — 460 * dw_read_form wires it to .debug_info; the line decoder passes &d->line. */ 461 void dw_read_form_in(KitDebugInfo* d, const DwCu* cu, const DwSection* sec, 462 u32 form, i64 implicit_const, u32* off, DwAttrValue* out) { 463 out->form = form; 464 out->u = 0; 465 out->s = 0; 466 out->str = ""; 467 out->block = NULL; 468 out->block_len = 0; 469 switch (form) { 470 case DW_FORM_addr: 471 if (cu->address_size == 8) 472 out->u = dw_u64(sec->data, sec->size, off); 473 else 474 out->u = dw_u32(sec->data, sec->size, off); 475 break; 476 case DW_FORM_data1: 477 case DW_FORM_ref1: 478 case DW_FORM_flag: 479 case DW_FORM_strx1: 480 case DW_FORM_addrx1: 481 out->u = dw_u8(sec->data, sec->size, off); 482 out->s = (i64)(i8)out->u; 483 if (form == DW_FORM_strx1) out->str = dw_strx(d, cu, out->u); 484 break; 485 case DW_FORM_data2: 486 case DW_FORM_ref2: 487 case DW_FORM_strx2: 488 case DW_FORM_addrx2: 489 out->u = dw_u16(sec->data, sec->size, off); 490 out->s = (i64)(i16)out->u; 491 if (form == DW_FORM_strx2) out->str = dw_strx(d, cu, out->u); 492 break; 493 case DW_FORM_strx3: 494 case DW_FORM_addrx3: 495 out->u = dw_u24(sec->data, sec->size, off); 496 if (form == DW_FORM_strx3) out->str = dw_strx(d, cu, out->u); 497 break; 498 case DW_FORM_data4: 499 case DW_FORM_ref4: 500 case DW_FORM_strx4: 501 case DW_FORM_addrx4: 502 out->u = dw_u32(sec->data, sec->size, off); 503 out->s = (i64)(i32)out->u; 504 if (form == DW_FORM_strx4) out->str = dw_strx(d, cu, out->u); 505 break; 506 case DW_FORM_data8: 507 case DW_FORM_ref8: 508 case DW_FORM_ref_sig8: 509 case DW_FORM_ref_sup8: 510 out->u = dw_u64(sec->data, sec->size, off); 511 out->s = (i64)out->u; 512 break; 513 case DW_FORM_data16: 514 /* Skip 16 bytes; not commonly needed. */ 515 *off += 16; 516 break; 517 case DW_FORM_sdata: 518 out->s = dw_sleb(sec->data, sec->size, off); 519 out->u = (u64)out->s; 520 break; 521 case DW_FORM_udata: 522 case DW_FORM_ref_udata: 523 case DW_FORM_strx: 524 case DW_FORM_addrx: 525 case DW_FORM_loclistx: 526 case DW_FORM_rnglistx: 527 out->u = dw_uleb(sec->data, sec->size, off); 528 if (form == DW_FORM_strx) out->str = dw_strx(d, cu, out->u); 529 break; 530 case DW_FORM_string: 531 out->str = dw_cstr(sec->data, sec->size, off); 532 break; 533 case DW_FORM_strp: 534 out->u = dw_u32(sec->data, sec->size, off); 535 out->str = dw_str(d, (u32)out->u); 536 break; 537 case DW_FORM_line_strp: 538 out->u = dw_u32(sec->data, sec->size, off); 539 out->str = dw_line_str(d, (u32)out->u); 540 break; 541 case DW_FORM_strp_sup: 542 case DW_FORM_ref_sup4: 543 out->u = dw_u32(sec->data, sec->size, off); 544 break; 545 case DW_FORM_sec_offset: 546 out->u = dw_u32(sec->data, sec->size, off); 547 break; 548 case DW_FORM_ref_addr: 549 /* DWARF 5: 4 bytes for 32-bit DWARF (we don't support DWARF64). */ 550 out->u = dw_u32(sec->data, sec->size, off); 551 break; 552 case DW_FORM_flag_present: 553 out->u = 1; 554 break; 555 case DW_FORM_implicit_const: 556 out->s = implicit_const; 557 out->u = (u64)implicit_const; 558 break; 559 case DW_FORM_block1: { 560 u32 n = dw_u8(sec->data, sec->size, off); 561 out->block = sec->data + *off; 562 out->block_len = n; 563 out->u = n; 564 *off += n; 565 } break; 566 case DW_FORM_block2: { 567 u32 n = dw_u16(sec->data, sec->size, off); 568 out->block = sec->data + *off; 569 out->block_len = n; 570 out->u = n; 571 *off += n; 572 } break; 573 case DW_FORM_block4: { 574 u32 n = dw_u32(sec->data, sec->size, off); 575 out->block = sec->data + *off; 576 out->block_len = n; 577 out->u = n; 578 *off += n; 579 } break; 580 case DW_FORM_block: 581 case DW_FORM_exprloc: { 582 u32 n = (u32)dw_uleb(sec->data, sec->size, off); 583 out->block = sec->data + *off; 584 out->block_len = n; 585 out->u = n; 586 *off += n; 587 } break; 588 case DW_FORM_indirect: { 589 u32 ifrm = (u32)dw_uleb(sec->data, sec->size, off); 590 dw_read_form_in(d, cu, sec, ifrm, 0, off, out); 591 } break; 592 default: 593 /* Unknown form — best effort: skip nothing. */ 594 break; 595 } 596 } 597 598 void dw_read_form(KitDebugInfo* d, const DwCu* cu, u32 form, i64 implicit_const, 599 u32* off, DwAttrValue* out) { 600 dw_read_form_in(d, cu, &d->info, form, implicit_const, off, out); 601 } 602 603 void dw_skip_form(KitDebugInfo* d, const DwCu* cu, u32 form, i64 implicit_const, 604 u32* off) { 605 DwAttrValue tmp; 606 dw_read_form(d, cu, form, implicit_const, off, &tmp); 607 } 608 609 /* ---- DIE iteration ---------------------------------------------------- */ 610 611 int dw_read_die(KitDebugInfo* d, const DwCu* cu, u32* off, DwDie* out) { 612 u64 code; 613 out->die_off = *off; 614 if (*off >= d->info.size || *off >= cu->hdr_offset + cu->unit_total_size) { 615 out->abbrev_code = 0; 616 out->abbrev = NULL; 617 out->attrs_off = *off; 618 return 0; 619 } 620 code = dw_uleb(d->info.data, d->info.size, off); 621 out->abbrev_code = code; 622 out->attrs_off = *off; 623 out->next_sibling_off = 0; 624 if (code == 0) { 625 out->abbrev = NULL; 626 return 0; 627 } 628 out->abbrev = dw_abbrev_lookup(&d->abbrevs[cu->abbrev_table_idx], code); 629 return 1; 630 } 631 632 void dw_skip_die_attrs(KitDebugInfo* d, const DwCu* cu, DwDie* die, u32* off) { 633 u32 i; 634 if (!die->abbrev) return; 635 for (i = 0; i < die->abbrev->nattrs; ++i) { 636 DwAbbrevAttr* aa = &die->abbrev->attrs[i]; 637 dw_skip_form(d, cu, aa->form, aa->implicit_const, off); 638 } 639 } 640 641 void dw_skip_die_subtree(KitDebugInfo* d, const DwCu* cu, DwDie* die, 642 u32* off) { 643 if (!die->abbrev) return; 644 dw_skip_die_attrs(d, cu, die, off); 645 if (die->abbrev->has_children) { 646 for (;;) { 647 DwDie child; 648 if (!dw_read_die(d, cu, off, &child)) break; 649 dw_skip_die_subtree(d, cu, &child, off); 650 } 651 } 652 } 653 654 int dw_die_attr(KitDebugInfo* d, const DwCu* cu, DwDie* die, u32 attr, 655 DwAttrValue* out) { 656 u32 off = die->attrs_off; 657 u32 i; 658 if (!die->abbrev) return 0; 659 for (i = 0; i < die->abbrev->nattrs; ++i) { 660 DwAbbrevAttr* aa = &die->abbrev->attrs[i]; 661 if (aa->attr == attr) { 662 dw_read_form(d, cu, aa->form, aa->implicit_const, &off, out); 663 return 1; 664 } 665 dw_skip_form(d, cu, aa->form, aa->implicit_const, &off); 666 } 667 return 0; 668 } 669 670 /* ---- public open/close ----------------------------------------------- */ 671 672 KitStatus kit_dwarf_open(const KitContext* ctx, const KitObjFile* obj, 673 KitDebugInfo** out) { 674 Heap* h; 675 KitDebugInfo* d; 676 if (!out) return KIT_INVALID; 677 *out = NULL; 678 if (!ctx || !ctx->heap || !obj) return KIT_INVALID; 679 h = ctx->heap; 680 d = (KitDebugInfo*)h->alloc(h, sizeof(*d), _Alignof(KitDebugInfo)); 681 if (!d) return KIT_NOMEM; 682 memset(d, 0, sizeof(*d)); 683 d->ctx = ctx; 684 d->h = h; 685 d->obj = obj; 686 d->strs = (Pool*)h->alloc(h, sizeof(*d->strs), _Alignof(Pool)); 687 if (!d->strs) { 688 kit_dwarf_free(d); 689 return KIT_NOMEM; 690 } 691 pool_init(d->strs, h); 692 693 dw_find_section(d, ".debug_abbrev", &d->abbrev); 694 dw_find_section(d, ".debug_info", &d->info); 695 dw_find_section(d, ".debug_line", &d->line); 696 dw_find_section(d, ".debug_str", &d->str); 697 dw_find_section(d, ".debug_line_str", &d->line_str); 698 dw_find_section(d, ".debug_str_offsets", &d->str_offsets); 699 dw_find_section(d, ".debug_addr", &d->addr); 700 dw_find_section(d, ".debug_loclists", &d->loclists); 701 dw_find_section(d, ".debug_rnglists", &d->rnglists); 702 dw_find_section(d, ".eh_frame", &d->eh_frame); 703 dw_find_section(d, ".debug_aranges", &d->aranges); 704 705 if (d->abbrev.sec_idx == UINT32_MAX || d->info.sec_idx == UINT32_MAX || 706 d->line.sec_idx == UINT32_MAX || d->str.sec_idx == UINT32_MAX || 707 d->line_str.sec_idx == UINT32_MAX) { 708 kit_dwarf_free(d); 709 return KIT_NOT_FOUND; 710 } 711 712 /* str_offsets_base default: in the absence of DW_AT_str_offsets_base, the 713 * offsets section starts with an 8-byte header (uniform for DW5). */ 714 dw_parse_all_cus(d); 715 if (d->ncus == 0) { 716 kit_dwarf_free(d); 717 return KIT_MALFORMED; 718 } 719 720 /* Allocate per-CU lazy line-program state. */ 721 if (d->ncus) { 722 d->lines_by_cu = (DwLineProgram*)h->alloc( 723 h, d->ncus * sizeof(DwLineProgram), _Alignof(DwLineProgram)); 724 d->lines_built = (u8*)h->alloc(h, d->ncus, 1); 725 if (!d->lines_by_cu || !d->lines_built) { 726 kit_dwarf_free(d); 727 return KIT_NOMEM; 728 } 729 memset(d->lines_by_cu, 0, d->ncus * sizeof(DwLineProgram)); 730 memset(d->lines_built, 0, d->ncus); 731 } 732 733 *out = d; 734 return KIT_OK; 735 } 736 737 static void free_subprog(Heap* h, DwSubprog* sp) { 738 if (sp->params) h->free(h, sp->params, sp->nparams * sizeof(DwLocal)); 739 if (sp->locals) h->free(h, sp->locals, sp->nlocals * sizeof(DwLocal)); 740 } 741 742 void kit_dwarf_free(KitDebugInfo* d) { 743 Heap* h; 744 u32 i; 745 if (!d) return; 746 h = d->h; 747 for (i = 0; i < d->nabbrevs; ++i) { 748 u32 j; 749 DwAbbrevTable* t = &d->abbrevs[i]; 750 for (j = 0; j < t->nabbrevs; ++j) { 751 if (t->abbrevs[j].attrs) 752 h->free(h, t->abbrevs[j].attrs, 753 t->abbrevs[j].nattrs * sizeof(DwAbbrevAttr)); 754 } 755 if (t->abbrevs) h->free(h, t->abbrevs, t->cap * sizeof(DwAbbrev)); 756 } 757 if (d->abbrevs) 758 h->free(h, d->abbrevs, d->abbrevs_cap * sizeof(DwAbbrevTable)); 759 if (d->cus) h->free(h, d->cus, d->cus_cap * sizeof(DwCu)); 760 761 if (d->lines_by_cu) { 762 for (i = 0; i < d->ncus; ++i) { 763 DwLineProgram* lp = &d->lines_by_cu[i]; 764 if (lp->rows) h->free(h, lp->rows, lp->cap * sizeof(DwLineRow)); 765 if (lp->files) h->free(h, lp->files, lp->nfiles * sizeof(DwLineFile)); 766 if (lp->dirs) h->free(h, lp->dirs, lp->ndirs * sizeof(const char*)); 767 if (lp->file_norm) 768 h->free(h, lp->file_norm, lp->nfile_norm * sizeof(const char*)); 769 } 770 h->free(h, d->lines_by_cu, d->ncus * sizeof(DwLineProgram)); 771 } 772 if (d->lines_built) h->free(h, d->lines_built, d->ncus); 773 774 for (i = 0; i < d->nsubs; ++i) free_subprog(h, &d->subs[i]); 775 if (d->subs) h->free(h, d->subs, d->subs_cap * sizeof(DwSubprog)); 776 777 for (i = 0; i < d->ntypes; ++i) { 778 KitDwarfType* t = d->types_by_off[i]; 779 if (!t) continue; 780 if (t->fields) h->free(h, t->fields, t->nfields * sizeof(DwField)); 781 if (t->evals) h->free(h, t->evals, t->nevals * sizeof(DwEnumVal)); 782 h->free(h, t, sizeof(*t)); 783 } 784 if (d->types_by_off) 785 h->free(h, d->types_by_off, d->types_cap * sizeof(KitDwarfType*)); 786 if (d->types_off) h->free(h, d->types_off, d->types_cap * sizeof(u32)); 787 788 if (d->globals) h->free(h, d->globals, d->globals_cap * sizeof(DwLocal)); 789 790 if (d->strs) { 791 pool_fini(d->strs); 792 h->free(h, d->strs, sizeof(*d->strs)); 793 } 794 795 h->free(h, d, sizeof(*d)); 796 }