dwarf_open.c (24948B)
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 /* Two-pass scan: do skipping reads, but capture base attrs. We must 352 * be careful: dw_read_form for strx forms uses cu->str_offsets_base, 353 * so we read in two passes. */ 354 off = cu->die_start_off; 355 (void)dw_uleb(d->info.data, d->info.size, &off); /* re-skip code */ 356 /* Pass 1: only read str_offsets_base / addr_base (forms that don't 357 * themselves need those bases). */ 358 for (i = 0; i < ab->nattrs; ++i) { 359 DwAbbrevAttr* aa = &ab->attrs[i]; 360 if (aa->attr == DW_AT_str_offsets_base || aa->attr == DW_AT_addr_base || 361 aa->attr == DW_AT_loclists_base || aa->attr == DW_AT_rnglists_base) { 362 dw_read_form(d, cu, aa->form, aa->implicit_const, &off, &v); 363 if (aa->attr == DW_AT_str_offsets_base) 364 cu->str_offsets_base = (u32)v.u; 365 else if (aa->attr == DW_AT_addr_base) 366 cu->addr_base = (u32)v.u; 367 else if (aa->attr == DW_AT_loclists_base) 368 cu->loclists_base = (u32)v.u; 369 else if (aa->attr == DW_AT_rnglists_base) 370 cu->rnglists_base = (u32)v.u; 371 } else { 372 dw_skip_form(d, cu, aa->form, aa->implicit_const, &off); 373 } 374 } 375 /* Pass 2: read remaining attrs (stmt_list, name, comp_dir). */ 376 off = cu->die_start_off; 377 (void)dw_uleb(d->info.data, d->info.size, &off); 378 for (i = 0; i < ab->nattrs; ++i) { 379 DwAbbrevAttr* aa = &ab->attrs[i]; 380 if (aa->attr == DW_AT_stmt_list) { 381 dw_read_form(d, cu, aa->form, aa->implicit_const, &off, &v); 382 cu->stmt_list = (u32)v.u; 383 cu->has_stmt_list = 1; 384 } else if (aa->attr == DW_AT_name) { 385 dw_read_form(d, cu, aa->form, aa->implicit_const, &off, &v); 386 cu->name = v.str ? v.str : ""; 387 } else if (aa->attr == DW_AT_comp_dir) { 388 dw_read_form(d, cu, aa->form, aa->implicit_const, &off, &v); 389 cu->comp_dir = v.str ? v.str : ""; 390 } else { 391 dw_skip_form(d, cu, aa->form, aa->implicit_const, &off); 392 } 393 } 394 } 395 396 void dw_parse_all_cus(KitDebugInfo* d) { 397 u32 off = 0; 398 /* Idempotent: a successful kit_dwarf_open already populates d->cus, and 399 * the structural-enumeration iterators call this again. Re-parsing would 400 * append duplicate CUs, so bail once the table is built. */ 401 if (d->ncus) return; 402 while (off < d->info.size) { 403 DwCu cu; 404 u32 next = dw_cu_parse_header(d, off, &cu); 405 if (next <= off) break; 406 if (cu.is_64bit) { 407 off = next; 408 continue; 409 } 410 if (cu.version < 2 || cu.version > 5) { 411 off = next; 412 continue; 413 } 414 if (d->ncus == d->cus_cap) { 415 u32 ncap = d->cus_cap ? d->cus_cap * 2 : 4; 416 DwCu* na = 417 (DwCu*)d->h->realloc(d->h, d->cus, d->cus_cap * sizeof(*d->cus), 418 ncap * sizeof(*d->cus), _Alignof(DwCu)); 419 if (!na) break; 420 d->cus = na; 421 d->cus_cap = ncap; 422 } 423 d->cus[d->ncus++] = cu; 424 /* Capture root attrs now. */ 425 cu_read_root_attrs(d, &d->cus[d->ncus - 1]); 426 off = next; 427 } 428 } 429 430 DwCu* dw_cu_at_die_offset(KitDebugInfo* d, u32 die_offset) { 431 u32 i; 432 for (i = 0; i < d->ncus; ++i) { 433 DwCu* cu = &d->cus[i]; 434 if (die_offset >= cu->hdr_offset && 435 die_offset < cu->hdr_offset + cu->unit_total_size) { 436 return cu; 437 } 438 } 439 return NULL; 440 } 441 442 /* ---- form decoding ---------------------------------------------------- */ 443 444 /* Section-parameterized form decoder. Inline form bytes are pulled from 445 * `sec` (.debug_info for DIE attributes, .debug_line for line-program 446 * file/dir entry-format values); strp/line_strp/strx still resolve into the 447 * shared string sections via the CU. This is the single source of truth — 448 * dw_read_form wires it to .debug_info; the line decoder passes &d->line. */ 449 void dw_read_form_in(KitDebugInfo* d, const DwCu* cu, const DwSection* sec, 450 u32 form, i64 implicit_const, u32* off, DwAttrValue* out) { 451 out->form = form; 452 out->u = 0; 453 out->s = 0; 454 out->str = ""; 455 out->block = NULL; 456 out->block_len = 0; 457 switch (form) { 458 case DW_FORM_addr: 459 if (cu->address_size == 8) 460 out->u = dw_u64(sec->data, sec->size, off); 461 else 462 out->u = dw_u32(sec->data, sec->size, off); 463 break; 464 case DW_FORM_data1: 465 case DW_FORM_ref1: 466 case DW_FORM_flag: 467 case DW_FORM_strx1: 468 case DW_FORM_addrx1: 469 out->u = dw_u8(sec->data, sec->size, off); 470 out->s = (i64)(i8)out->u; 471 if (form == DW_FORM_strx1) out->str = dw_strx(d, cu, out->u); 472 break; 473 case DW_FORM_data2: 474 case DW_FORM_ref2: 475 case DW_FORM_strx2: 476 case DW_FORM_addrx2: 477 out->u = dw_u16(sec->data, sec->size, off); 478 out->s = (i64)(i16)out->u; 479 if (form == DW_FORM_strx2) out->str = dw_strx(d, cu, out->u); 480 break; 481 case DW_FORM_strx3: 482 case DW_FORM_addrx3: 483 out->u = dw_u24(sec->data, sec->size, off); 484 if (form == DW_FORM_strx3) out->str = dw_strx(d, cu, out->u); 485 break; 486 case DW_FORM_data4: 487 case DW_FORM_ref4: 488 case DW_FORM_strx4: 489 case DW_FORM_addrx4: 490 out->u = dw_u32(sec->data, sec->size, off); 491 out->s = (i64)(i32)out->u; 492 if (form == DW_FORM_strx4) out->str = dw_strx(d, cu, out->u); 493 break; 494 case DW_FORM_data8: 495 case DW_FORM_ref8: 496 case DW_FORM_ref_sig8: 497 case DW_FORM_ref_sup8: 498 out->u = dw_u64(sec->data, sec->size, off); 499 out->s = (i64)out->u; 500 break; 501 case DW_FORM_data16: 502 /* Skip 16 bytes; not commonly needed. */ 503 *off += 16; 504 break; 505 case DW_FORM_sdata: 506 out->s = dw_sleb(sec->data, sec->size, off); 507 out->u = (u64)out->s; 508 break; 509 case DW_FORM_udata: 510 case DW_FORM_ref_udata: 511 case DW_FORM_strx: 512 case DW_FORM_addrx: 513 case DW_FORM_loclistx: 514 case DW_FORM_rnglistx: 515 out->u = dw_uleb(sec->data, sec->size, off); 516 if (form == DW_FORM_strx) out->str = dw_strx(d, cu, out->u); 517 break; 518 case DW_FORM_string: 519 out->str = dw_cstr(sec->data, sec->size, off); 520 break; 521 case DW_FORM_strp: 522 out->u = dw_u32(sec->data, sec->size, off); 523 out->str = dw_str(d, (u32)out->u); 524 break; 525 case DW_FORM_line_strp: 526 out->u = dw_u32(sec->data, sec->size, off); 527 out->str = dw_line_str(d, (u32)out->u); 528 break; 529 case DW_FORM_strp_sup: 530 case DW_FORM_ref_sup4: 531 out->u = dw_u32(sec->data, sec->size, off); 532 break; 533 case DW_FORM_sec_offset: 534 out->u = dw_u32(sec->data, sec->size, off); 535 break; 536 case DW_FORM_ref_addr: 537 /* DWARF 5: 4 bytes for 32-bit DWARF (we don't support DWARF64). */ 538 out->u = dw_u32(sec->data, sec->size, off); 539 break; 540 case DW_FORM_flag_present: 541 out->u = 1; 542 break; 543 case DW_FORM_implicit_const: 544 out->s = implicit_const; 545 out->u = (u64)implicit_const; 546 break; 547 case DW_FORM_block1: { 548 u32 n = dw_u8(sec->data, sec->size, off); 549 out->block = sec->data + *off; 550 out->block_len = n; 551 out->u = n; 552 *off += n; 553 } break; 554 case DW_FORM_block2: { 555 u32 n = dw_u16(sec->data, sec->size, off); 556 out->block = sec->data + *off; 557 out->block_len = n; 558 out->u = n; 559 *off += n; 560 } break; 561 case DW_FORM_block4: { 562 u32 n = dw_u32(sec->data, sec->size, off); 563 out->block = sec->data + *off; 564 out->block_len = n; 565 out->u = n; 566 *off += n; 567 } break; 568 case DW_FORM_block: 569 case DW_FORM_exprloc: { 570 u32 n = (u32)dw_uleb(sec->data, sec->size, off); 571 out->block = sec->data + *off; 572 out->block_len = n; 573 out->u = n; 574 *off += n; 575 } break; 576 case DW_FORM_indirect: { 577 u32 ifrm = (u32)dw_uleb(sec->data, sec->size, off); 578 dw_read_form_in(d, cu, sec, ifrm, 0, off, out); 579 } break; 580 default: 581 /* Unknown form — best effort: skip nothing. */ 582 break; 583 } 584 } 585 586 void dw_read_form(KitDebugInfo* d, const DwCu* cu, u32 form, i64 implicit_const, 587 u32* off, DwAttrValue* out) { 588 dw_read_form_in(d, cu, &d->info, form, implicit_const, off, out); 589 } 590 591 void dw_skip_form(KitDebugInfo* d, const DwCu* cu, u32 form, i64 implicit_const, 592 u32* off) { 593 DwAttrValue tmp; 594 dw_read_form(d, cu, form, implicit_const, off, &tmp); 595 } 596 597 /* ---- DIE iteration ---------------------------------------------------- */ 598 599 int dw_read_die(KitDebugInfo* d, const DwCu* cu, u32* off, DwDie* out) { 600 u64 code; 601 out->die_off = *off; 602 if (*off >= d->info.size || *off >= cu->hdr_offset + cu->unit_total_size) { 603 out->abbrev_code = 0; 604 out->abbrev = NULL; 605 out->attrs_off = *off; 606 return 0; 607 } 608 code = dw_uleb(d->info.data, d->info.size, off); 609 out->abbrev_code = code; 610 out->attrs_off = *off; 611 out->next_sibling_off = 0; 612 if (code == 0) { 613 out->abbrev = NULL; 614 return 0; 615 } 616 out->abbrev = dw_abbrev_lookup(&d->abbrevs[cu->abbrev_table_idx], code); 617 return 1; 618 } 619 620 void dw_skip_die_attrs(KitDebugInfo* d, const DwCu* cu, DwDie* die, u32* off) { 621 u32 i; 622 if (!die->abbrev) return; 623 for (i = 0; i < die->abbrev->nattrs; ++i) { 624 DwAbbrevAttr* aa = &die->abbrev->attrs[i]; 625 dw_skip_form(d, cu, aa->form, aa->implicit_const, off); 626 } 627 } 628 629 void dw_skip_die_subtree(KitDebugInfo* d, const DwCu* cu, DwDie* die, 630 u32* off) { 631 if (!die->abbrev) return; 632 dw_skip_die_attrs(d, cu, die, off); 633 if (die->abbrev->has_children) { 634 for (;;) { 635 DwDie child; 636 if (!dw_read_die(d, cu, off, &child)) break; 637 dw_skip_die_subtree(d, cu, &child, off); 638 } 639 } 640 } 641 642 int dw_die_attr(KitDebugInfo* d, const DwCu* cu, DwDie* die, u32 attr, 643 DwAttrValue* out) { 644 u32 off = die->attrs_off; 645 u32 i; 646 if (!die->abbrev) return 0; 647 for (i = 0; i < die->abbrev->nattrs; ++i) { 648 DwAbbrevAttr* aa = &die->abbrev->attrs[i]; 649 if (aa->attr == attr) { 650 dw_read_form(d, cu, aa->form, aa->implicit_const, &off, out); 651 return 1; 652 } 653 dw_skip_form(d, cu, aa->form, aa->implicit_const, &off); 654 } 655 return 0; 656 } 657 658 /* ---- public open/close ----------------------------------------------- */ 659 660 KitStatus kit_dwarf_open(const KitContext* ctx, const KitObjFile* obj, 661 KitDebugInfo** out) { 662 Heap* h; 663 KitDebugInfo* d; 664 if (!out) return KIT_INVALID; 665 *out = NULL; 666 if (!ctx || !ctx->heap || !obj) return KIT_INVALID; 667 h = ctx->heap; 668 d = (KitDebugInfo*)h->alloc(h, sizeof(*d), _Alignof(KitDebugInfo)); 669 if (!d) return KIT_NOMEM; 670 memset(d, 0, sizeof(*d)); 671 d->ctx = ctx; 672 d->h = h; 673 d->obj = obj; 674 d->strs = (Pool*)h->alloc(h, sizeof(*d->strs), _Alignof(Pool)); 675 if (!d->strs) { 676 kit_dwarf_free(d); 677 return KIT_NOMEM; 678 } 679 pool_init(d->strs, h); 680 681 dw_find_section(d, ".debug_abbrev", &d->abbrev); 682 dw_find_section(d, ".debug_info", &d->info); 683 dw_find_section(d, ".debug_line", &d->line); 684 dw_find_section(d, ".debug_str", &d->str); 685 dw_find_section(d, ".debug_line_str", &d->line_str); 686 dw_find_section(d, ".debug_str_offsets", &d->str_offsets); 687 dw_find_section(d, ".debug_addr", &d->addr); 688 dw_find_section(d, ".debug_loclists", &d->loclists); 689 dw_find_section(d, ".debug_rnglists", &d->rnglists); 690 dw_find_section(d, ".eh_frame", &d->eh_frame); 691 dw_find_section(d, ".debug_aranges", &d->aranges); 692 693 if (d->abbrev.sec_idx == UINT32_MAX || d->info.sec_idx == UINT32_MAX || 694 d->line.sec_idx == UINT32_MAX || d->str.sec_idx == UINT32_MAX || 695 d->line_str.sec_idx == UINT32_MAX) { 696 kit_dwarf_free(d); 697 return KIT_NOT_FOUND; 698 } 699 700 /* str_offsets_base default: in the absence of DW_AT_str_offsets_base, the 701 * offsets section starts with an 8-byte header (uniform for DW5). */ 702 dw_parse_all_cus(d); 703 if (d->ncus == 0) { 704 kit_dwarf_free(d); 705 return KIT_MALFORMED; 706 } 707 708 /* Allocate per-CU lazy line-program state. */ 709 if (d->ncus) { 710 d->lines_by_cu = (DwLineProgram*)h->alloc( 711 h, d->ncus * sizeof(DwLineProgram), _Alignof(DwLineProgram)); 712 d->lines_built = (u8*)h->alloc(h, d->ncus, 1); 713 if (!d->lines_by_cu || !d->lines_built) { 714 kit_dwarf_free(d); 715 return KIT_NOMEM; 716 } 717 memset(d->lines_by_cu, 0, d->ncus * sizeof(DwLineProgram)); 718 memset(d->lines_built, 0, d->ncus); 719 } 720 721 *out = d; 722 return KIT_OK; 723 } 724 725 static void free_subprog(Heap* h, DwSubprog* sp) { 726 if (sp->params) h->free(h, sp->params, sp->nparams * sizeof(DwLocal)); 727 if (sp->locals) h->free(h, sp->locals, sp->nlocals * sizeof(DwLocal)); 728 } 729 730 void kit_dwarf_free(KitDebugInfo* d) { 731 Heap* h; 732 u32 i; 733 if (!d) return; 734 h = d->h; 735 for (i = 0; i < d->nabbrevs; ++i) { 736 u32 j; 737 DwAbbrevTable* t = &d->abbrevs[i]; 738 for (j = 0; j < t->nabbrevs; ++j) { 739 if (t->abbrevs[j].attrs) 740 h->free(h, t->abbrevs[j].attrs, 741 t->abbrevs[j].nattrs * sizeof(DwAbbrevAttr)); 742 } 743 if (t->abbrevs) h->free(h, t->abbrevs, t->cap * sizeof(DwAbbrev)); 744 } 745 if (d->abbrevs) 746 h->free(h, d->abbrevs, d->abbrevs_cap * sizeof(DwAbbrevTable)); 747 if (d->cus) h->free(h, d->cus, d->cus_cap * sizeof(DwCu)); 748 749 if (d->lines_by_cu) { 750 for (i = 0; i < d->ncus; ++i) { 751 DwLineProgram* lp = &d->lines_by_cu[i]; 752 if (lp->rows) h->free(h, lp->rows, lp->cap * sizeof(DwLineRow)); 753 if (lp->files) h->free(h, lp->files, lp->nfiles * sizeof(DwLineFile)); 754 if (lp->dirs) h->free(h, lp->dirs, lp->ndirs * sizeof(const char*)); 755 if (lp->file_norm) 756 h->free(h, lp->file_norm, lp->nfile_norm * sizeof(const char*)); 757 } 758 h->free(h, d->lines_by_cu, d->ncus * sizeof(DwLineProgram)); 759 } 760 if (d->lines_built) h->free(h, d->lines_built, d->ncus); 761 762 for (i = 0; i < d->nsubs; ++i) free_subprog(h, &d->subs[i]); 763 if (d->subs) h->free(h, d->subs, d->subs_cap * sizeof(DwSubprog)); 764 765 for (i = 0; i < d->ntypes; ++i) { 766 KitDwarfType* t = d->types_by_off[i]; 767 if (!t) continue; 768 if (t->fields) h->free(h, t->fields, t->nfields * sizeof(DwField)); 769 if (t->evals) h->free(h, t->evals, t->nevals * sizeof(DwEnumVal)); 770 h->free(h, t, sizeof(*t)); 771 } 772 if (d->types_by_off) 773 h->free(h, d->types_by_off, d->types_cap * sizeof(KitDwarfType*)); 774 if (d->types_off) h->free(h, d->types_off, d->types_cap * sizeof(u32)); 775 776 if (d->globals) h->free(h, d->globals, d->globals_cap * sizeof(DwLocal)); 777 778 if (d->strs) { 779 pool_fini(d->strs); 780 h->free(h, d->strs, sizeof(*d->strs)); 781 } 782 783 h->free(h, d, sizeof(*d)); 784 }