debug_emit.c (46851B)
1 /* Linearize accumulated Debug state into ObjBuilder .debug_* sections. 2 * 3 * Wire-format choices made here are documented in DWARF.md / the agent 4 * report. Highlights: 5 * 6 * - DWARF 5 only. 7 * - 32-bit (DWARF32) section length form. 8 * - DW_FORM_strx4 used uniformly for string refs from .debug_info. 9 * - DW_FORM_line_strp for line program file/dir paths. 10 * - DW_FORM_ref4 for intra-CU DIE refs (CU-relative offset). 11 * - DW_AT_low_pc encoded as DW_FORM_addr with an address-width reloc against 12 * the function symbol; DW_AT_high_pc is DW_FORM_data4 holding func size. 13 * - DW_AT_frame_base is exprloc { DW_OP_call_frame_cfa }. 14 * - Abbrev codes are assigned in first-use order, starting at 1. 15 * - File 0 in .debug_line is the CU primary file (DW5 convention). */ 16 17 #include <string.h> 18 19 #include "arch/arch.h" 20 #include "core/buf.h" 21 #include "core/core.h" 22 #include "core/heap.h" 23 #include "core/pool.h" 24 #include "core/slice.h" 25 #include "core/vec.h" 26 #include "debug/debug_internal.h" 27 28 void abbrev_fini_heap(DebugAbbrevPool* p, Heap* h); 29 30 /* ---------------------------------------------------------------- */ 31 /* String tables. */ 32 33 typedef struct StrTab { 34 Buf buf; 35 SymToU32 by_sym; /* Sym → byte offset within buf */ 36 SymToU32 idx_by_sym; /* Sym → insertion index (== DW_FORM_strx value) */ 37 /* Insertion order — used to populate .debug_str_offsets. */ 38 Sym* syms; 39 u32 nsyms; 40 u32 syms_cap; 41 } StrTab; 42 43 static void str_init(StrTab* s, Heap* h) { 44 buf_init(&s->buf, h); 45 SymToU32_init(&s->by_sym, h); 46 SymToU32_init(&s->idx_by_sym, h); 47 s->syms = NULL; 48 s->nsyms = 0; 49 s->syms_cap = 0; 50 } 51 52 static void str_fini(StrTab* s, Heap* h) { 53 buf_fini(&s->buf); 54 SymToU32_fini(&s->by_sym); 55 SymToU32_fini(&s->idx_by_sym); 56 if (s->syms) h->free(h, s->syms, sizeof(Sym) * s->syms_cap); 57 s->syms = NULL; 58 s->nsyms = 0; 59 s->syms_cap = 0; 60 } 61 62 static u32 str_intern(StrTab* s, Heap* h, Pool* pool, Sym sym) { 63 u32* found; 64 u32 ofs; 65 size_t len; 66 const char* str; 67 if (sym == 0) sym = pool_intern_slice(pool, SLICE_LIT("")); 68 found = SymToU32_get(&s->by_sym, sym); 69 if (found) return *found; 70 ofs = buf_pos(&s->buf); 71 { 72 Slice sl = pool_slice(pool, sym); 73 str = sl.s; 74 len = sl.len; 75 } 76 if (str && len) buf_write(&s->buf, str, len); 77 { 78 u8 nul = 0; 79 buf_write(&s->buf, &nul, 1); 80 } 81 SymToU32_set(&s->by_sym, sym, ofs); 82 if (VEC_GROW(h, s->syms, s->syms_cap, s->nsyms + 1)) return ofs; 83 SymToU32_set(&s->idx_by_sym, sym, s->nsyms); 84 s->syms[s->nsyms++] = sym; 85 return ofs; 86 } 87 88 static u32 str_index_of(StrTab* s, Sym sym) { 89 u32* idx = SymToU32_get(&s->idx_by_sym, sym); 90 return idx ? *idx : 0; 91 } 92 93 /* ---------------------------------------------------------------- */ 94 /* DIE forward refs and address relocs. */ 95 96 typedef struct DieFixup { 97 u32 buf_offset; /* offset within EmitCtx.info_body */ 98 DebugTypeId target; 99 } DieFixup; 100 101 typedef struct AddrReloc { 102 u32 buf_offset; /* offset within the section (assigned at flush) */ 103 ObjSymId sym; 104 ObjSecId section; /* set on flush */ 105 } AddrReloc; 106 107 typedef struct EmitCtx { 108 Debug* d; 109 Heap* heap; 110 Pool* pool; 111 ObjBuilder* ob; 112 113 StrTab str; /* .debug_str */ 114 StrTab line_str; /* .debug_line_str */ 115 116 DebugAbbrevPool abbr; 117 118 /* Pre-resolved abbrev codes */ 119 u32 abbr_cu; 120 u32 abbr_base; 121 u32 abbr_ptr; 122 u32 abbr_typedef; 123 u32 abbr_qual_const; 124 u32 abbr_qual_volatile; 125 u32 abbr_qual_restrict; 126 u32 abbr_array; 127 u32 abbr_array_subrange; 128 u32 abbr_array_subrange_unbounded; 129 u32 abbr_func_type; 130 u32 abbr_func_type_param; 131 u32 abbr_struct; 132 u32 abbr_union; 133 u32 abbr_member; 134 u32 abbr_member_bitfield; 135 u32 abbr_enum; 136 u32 abbr_enum_val; 137 u32 abbr_subprogram; 138 u32 abbr_param; 139 u32 abbr_var; 140 u32 abbr_var_external; 141 u32 abbr_lexical_block; 142 143 /* CU body (post-CU-header DIE bytes). */ 144 Buf info_body; 145 146 /* Forward type-ref fixups (info_body-relative). */ 147 DieFixup* fixups; 148 u32 nfixups; 149 u32 fixups_cap; 150 151 /* low_pc relocs in .debug_info (info_body-relative offset). */ 152 AddrReloc* info_relocs; 153 u32 ninfo_relocs; 154 u32 info_relocs_cap; 155 156 /* line-program address relocs (.debug_line offset within program region). */ 157 AddrReloc* line_relocs; 158 u32 nline_relocs; 159 u32 line_relocs_cap; 160 161 /* aranges relocs (section-relative once we know offsets). */ 162 AddrReloc* aranges_relocs; 163 u32 naranges_relocs; 164 u32 aranges_relocs_cap; 165 166 /* rnglists relocs. */ 167 AddrReloc* rng_relocs; 168 u32 nrng_relocs; 169 u32 nrng_relocs_cap; 170 171 /* Section ids (pre-created up front so cross-section relocs can name 172 * their target before its bytes are written). */ 173 ObjSecId sec_str; 174 ObjSecId sec_line_str; 175 ObjSecId sec_str_off; 176 ObjSecId sec_abbrev; 177 ObjSecId sec_info; 178 ObjSecId sec_line; 179 ObjSecId sec_aranges; 180 ObjSecId sec_rnglists; 181 182 /* SK_SECTION ObjSyms over the same sections. They exist so the CU 183 * header + root DIE can encode cross-section offsets (debug_abbrev_offset, 184 * stmt_list, str_offsets_base, ranges) and the line / str-offsets 185 * payloads can encode their .debug_line_str / .debug_str references 186 * as relocations. The on-disk u32 stays zero; the relocation's addend 187 * carries the in-section offset. In a normal `.o` emit the linker 188 * applies R_ABS32 with S=section_vaddr=0 (debug sections are not laid 189 * out), so the written value equals the addend — byte-identical to the 190 * pre-reloc behaviour. In the JIT view, link_jit applies the same 191 * reloc against the section's accumulated prefix in the merged view, 192 * so concatenated multi-input debug bytes resolve to the right slot. */ 193 ObjSymId ssym_str; 194 ObjSymId ssym_line_str; 195 ObjSymId ssym_str_off; 196 ObjSymId ssym_abbrev; 197 ObjSymId ssym_line; 198 ObjSymId ssym_rnglists; 199 ObjSymId ssym_info; 200 201 /* Body-relative offsets of the three CU-root-DIE attributes whose 202 * payloads are cross-section offsets. Captured at the call sites in 203 * debug_emit() and consumed by emit_section_info() to emit R_ABS32 204 * relocs at cu_header_size + <at>. */ 205 u32 root_stmt_list_at; 206 u32 root_ranges_at; 207 u32 root_str_off_base_at; 208 } EmitCtx; 209 210 /* ---------------------------------------------------------------- */ 211 212 static void add_fixup(EmitCtx* e, u32 buf_offset, DebugTypeId target) { 213 DieFixup* fx; 214 if (VEC_GROW(e->heap, e->fixups, e->fixups_cap, e->nfixups + 1)) return; 215 fx = &e->fixups[e->nfixups++]; 216 fx->buf_offset = buf_offset; 217 fx->target = target; 218 } 219 220 /* Append a symbol-relative address reloc to one of the per-section AddrReloc 221 * arrays (info/line/aranges/rng). The arrays share an identical element 222 * layout and growth policy; only the backing array + count/cap differ. */ 223 static void add_addr_reloc(EmitCtx* e, AddrReloc** arr, u32* n, u32* cap, 224 u32 buf_offset, ObjSymId sym) { 225 AddrReloc* r; 226 if (VEC_GROW(e->heap, *arr, *cap, *n + 1)) return; 227 r = &(*arr)[(*n)++]; 228 r->buf_offset = buf_offset; 229 r->sym = sym; 230 r->section = OBJ_SEC_NONE; 231 } 232 233 static RelocKind debug_addr_reloc_kind(const Debug* d) { 234 return d && d->c && d->c->target.ptr_size == 4 ? R_ABS32 : R_ABS64; 235 } 236 237 /* ---------------------------------------------------------------- */ 238 /* String emit shortcuts. */ 239 240 static void emit_strx4(EmitCtx* e, Buf* b, Sym name) { 241 str_intern(&e->str, e->heap, e->pool, name); 242 { 243 Sym key = name ? name : pool_intern_slice(e->pool, SLICE_LIT("")); 244 u32 idx = str_index_of(&e->str, key); 245 form_u32(b, idx); 246 } 247 } 248 249 static u32 line_str_offset(EmitCtx* e, Sym sym) { 250 return str_intern(&e->line_str, e->heap, e->pool, sym); 251 } 252 253 /* ---------------------------------------------------------------- */ 254 /* Abbrev resolution. */ 255 256 static u32 abbr_intern(EmitCtx* e, u16 tag, u8 has_children, 257 const DebugAbbrevAttr* attrs, u32 nattrs) { 258 return abbrev_intern(&e->abbr, e->heap, tag, has_children, attrs, nattrs); 259 } 260 261 static void resolve_abbrevs(EmitCtx* e) { 262 /* Order of intern == order of code assignment. */ 263 { 264 DebugAbbrevAttr a[] = { 265 {DW_AT_producer, DW_FORM_strx4, 0}, 266 {DW_AT_language, DW_FORM_data2, 0}, 267 {DW_AT_name, DW_FORM_strx4, 0}, 268 {DW_AT_comp_dir, DW_FORM_strx4, 0}, 269 {DW_AT_stmt_list, DW_FORM_sec_offset, 0}, 270 {DW_AT_low_pc, DW_FORM_addr, 0}, 271 {DW_AT_ranges, DW_FORM_sec_offset, 0}, 272 {DW_AT_str_offsets_base, DW_FORM_sec_offset, 0}, 273 }; 274 e->abbr_cu = abbr_intern(e, DW_TAG_compile_unit, DW_CHILDREN_yes, a, 275 (u32)(sizeof(a) / sizeof(a[0]))); 276 } 277 { 278 DebugAbbrevAttr a[] = {{DW_AT_name, DW_FORM_strx4, 0}, 279 {DW_AT_encoding, DW_FORM_data1, 0}, 280 {DW_AT_byte_size, DW_FORM_data1, 0}}; 281 e->abbr_base = abbr_intern(e, DW_TAG_base_type, DW_CHILDREN_no, a, 3); 282 } 283 { 284 DebugAbbrevAttr a[] = {{DW_AT_byte_size, DW_FORM_data1, 0}, 285 {DW_AT_type, DW_FORM_ref4, 0}}; 286 e->abbr_ptr = abbr_intern(e, DW_TAG_pointer_type, DW_CHILDREN_no, a, 2); 287 } 288 { 289 DebugAbbrevAttr a[] = {{DW_AT_name, DW_FORM_strx4, 0}, 290 {DW_AT_type, DW_FORM_ref4, 0}}; 291 e->abbr_typedef = abbr_intern(e, DW_TAG_typedef, DW_CHILDREN_no, a, 2); 292 } 293 { 294 DebugAbbrevAttr a[] = {{DW_AT_type, DW_FORM_ref4, 0}}; 295 e->abbr_qual_const = 296 abbr_intern(e, DW_TAG_const_type, DW_CHILDREN_no, a, 1); 297 } 298 { 299 DebugAbbrevAttr a[] = {{DW_AT_type, DW_FORM_ref4, 0}}; 300 e->abbr_qual_volatile = 301 abbr_intern(e, DW_TAG_volatile_type, DW_CHILDREN_no, a, 1); 302 } 303 { 304 DebugAbbrevAttr a[] = {{DW_AT_type, DW_FORM_ref4, 0}}; 305 e->abbr_qual_restrict = 306 abbr_intern(e, DW_TAG_restrict_type, DW_CHILDREN_no, a, 1); 307 } 308 { 309 DebugAbbrevAttr a[] = {{DW_AT_type, DW_FORM_ref4, 0}}; 310 e->abbr_array = abbr_intern(e, DW_TAG_array_type, DW_CHILDREN_yes, a, 1); 311 } 312 { 313 DebugAbbrevAttr a[] = {{DW_AT_count, DW_FORM_udata, 0}}; 314 e->abbr_array_subrange = 315 abbr_intern(e, DW_TAG_subrange_type, DW_CHILDREN_no, a, 1); 316 } 317 { 318 e->abbr_array_subrange_unbounded = 319 abbr_intern(e, DW_TAG_subrange_type, DW_CHILDREN_no, NULL, 0); 320 } 321 { 322 DebugAbbrevAttr a[] = {{DW_AT_type, DW_FORM_ref4, 0}, 323 {DW_AT_prototyped, DW_FORM_flag_present, 0}}; 324 e->abbr_func_type = 325 abbr_intern(e, DW_TAG_subroutine_type, DW_CHILDREN_yes, a, 2); 326 } 327 { 328 DebugAbbrevAttr a[] = {{DW_AT_type, DW_FORM_ref4, 0}}; 329 e->abbr_func_type_param = 330 abbr_intern(e, DW_TAG_formal_parameter, DW_CHILDREN_no, a, 1); 331 } 332 { 333 DebugAbbrevAttr a[] = {{DW_AT_name, DW_FORM_strx4, 0}, 334 {DW_AT_byte_size, DW_FORM_udata, 0}}; 335 e->abbr_struct = 336 abbr_intern(e, DW_TAG_structure_type, DW_CHILDREN_yes, a, 2); 337 e->abbr_union = abbr_intern(e, DW_TAG_union_type, DW_CHILDREN_yes, a, 2); 338 } 339 { 340 DebugAbbrevAttr a[] = {{DW_AT_name, DW_FORM_strx4, 0}, 341 {DW_AT_type, DW_FORM_ref4, 0}, 342 {DW_AT_data_member_location, DW_FORM_udata, 0}}; 343 e->abbr_member = abbr_intern(e, DW_TAG_member, DW_CHILDREN_no, a, 3); 344 } 345 { 346 DebugAbbrevAttr a[] = {{DW_AT_name, DW_FORM_strx4, 0}, 347 {DW_AT_type, DW_FORM_ref4, 0}, 348 {DW_AT_data_member_location, DW_FORM_udata, 0}, 349 {DW_AT_data_bit_offset, DW_FORM_udata, 0}, 350 {DW_AT_bit_size, DW_FORM_udata, 0}}; 351 e->abbr_member_bitfield = 352 abbr_intern(e, DW_TAG_member, DW_CHILDREN_no, a, 5); 353 } 354 { 355 DebugAbbrevAttr a[] = {{DW_AT_name, DW_FORM_strx4, 0}, 356 {DW_AT_type, DW_FORM_ref4, 0}, 357 {DW_AT_byte_size, DW_FORM_udata, 0}}; 358 e->abbr_enum = 359 abbr_intern(e, DW_TAG_enumeration_type, DW_CHILDREN_yes, a, 3); 360 } 361 { 362 DebugAbbrevAttr a[] = {{DW_AT_name, DW_FORM_strx4, 0}, 363 {DW_AT_const_value, DW_FORM_sdata, 0}}; 364 e->abbr_enum_val = abbr_intern(e, DW_TAG_enumerator, DW_CHILDREN_no, a, 2); 365 } 366 { 367 /* Subprogram. We use a single abbrev with DW_AT_type even when 368 * return is void; emit_subprogram_die emits ref4=0 in that case 369 * (which the consumer interprets as void). */ 370 DebugAbbrevAttr a[] = {{DW_AT_external, DW_FORM_flag_present, 0}, 371 {DW_AT_name, DW_FORM_strx4, 0}, 372 {DW_AT_decl_file, DW_FORM_udata, 0}, 373 {DW_AT_decl_line, DW_FORM_udata, 0}, 374 {DW_AT_type, DW_FORM_ref4, 0}, 375 {DW_AT_low_pc, DW_FORM_addr, 0}, 376 {DW_AT_high_pc, DW_FORM_data4, 0}, 377 {DW_AT_frame_base, DW_FORM_exprloc, 0}}; 378 e->abbr_subprogram = 379 abbr_intern(e, DW_TAG_subprogram, DW_CHILDREN_yes, a, 8); 380 } 381 { 382 DebugAbbrevAttr a[] = {{DW_AT_name, DW_FORM_strx4, 0}, 383 {DW_AT_decl_file, DW_FORM_udata, 0}, 384 {DW_AT_decl_line, DW_FORM_udata, 0}, 385 {DW_AT_type, DW_FORM_ref4, 0}, 386 {DW_AT_location, DW_FORM_exprloc, 0}}; 387 e->abbr_param = 388 abbr_intern(e, DW_TAG_formal_parameter, DW_CHILDREN_no, a, 5); 389 e->abbr_var = abbr_intern(e, DW_TAG_variable, DW_CHILDREN_no, a, 5); 390 } 391 { 392 DebugAbbrevAttr a[] = {{DW_AT_external, DW_FORM_flag_present, 0}, 393 {DW_AT_name, DW_FORM_strx4, 0}, 394 {DW_AT_decl_file, DW_FORM_udata, 0}, 395 {DW_AT_decl_line, DW_FORM_udata, 0}, 396 {DW_AT_type, DW_FORM_ref4, 0}, 397 {DW_AT_location, DW_FORM_exprloc, 0}}; 398 e->abbr_var_external = 399 abbr_intern(e, DW_TAG_variable, DW_CHILDREN_no, a, 6); 400 } 401 { 402 e->abbr_lexical_block = 403 abbr_intern(e, DW_TAG_lexical_block, DW_CHILDREN_yes, NULL, 0); 404 } 405 } 406 407 /* ---------------------------------------------------------------- */ 408 /* Per-type DIE emission. */ 409 410 static void emit_type_die(EmitCtx* e, DebugTypeId id); 411 412 static void emit_type_ref(EmitCtx* e, DebugTypeId tid) { 413 u32 ofs = buf_pos(&e->info_body); 414 u32 placeholder = 0; 415 buf_write(&e->info_body, &placeholder, 4); 416 if (tid != DEBUG_TYPE_NONE) { 417 add_fixup(e, ofs, tid); 418 } 419 } 420 421 static u8 base_enc(DebugBaseEncoding enc) { 422 switch (enc) { 423 case DEBUG_BE_BOOL: 424 return DW_ATE_boolean; 425 case DEBUG_BE_SIGNED: 426 return DW_ATE_signed; 427 case DEBUG_BE_UNSIGNED: 428 return DW_ATE_unsigned; 429 case DEBUG_BE_SIGNED_CHAR: 430 return DW_ATE_signed_char; 431 case DEBUG_BE_UNSIGNED_CHAR: 432 return DW_ATE_unsigned_char; 433 case DEBUG_BE_FLOAT: 434 return DW_ATE_float; 435 case DEBUG_BE_UTF: 436 return DW_ATE_UTF; 437 case DEBUG_BE_ADDRESS: 438 return DW_ATE_address; 439 } 440 return DW_ATE_signed; 441 } 442 443 static void emit_type_die(EmitCtx* e, DebugTypeId id) { 444 DebugType* t; 445 Debug* d = e->d; 446 if (id == DEBUG_TYPE_NONE || id > d->ntypes) return; 447 t = &d->types[id - 1]; 448 if (t->die_offset != 0) return; 449 switch ((DebugTypeKind)t->kind) { 450 case DTK_VOID: 451 /* No DIE — t->die_offset stays 0; refs will encode as 0 (consumer 452 * interprets as void). */ 453 return; 454 case DTK_BASE: 455 t->die_offset = buf_pos(&e->info_body); 456 form_uleb(&e->info_body, e->abbr_base); 457 emit_strx4(e, &e->info_body, t->name); 458 form_u8(&e->info_body, base_enc((DebugBaseEncoding)t->base_encoding)); 459 form_u8(&e->info_body, (u8)t->byte_size); 460 return; 461 case DTK_PTR: 462 t->die_offset = buf_pos(&e->info_body); 463 form_uleb(&e->info_body, e->abbr_ptr); 464 form_u8(&e->info_body, (u8)t->byte_size); 465 emit_type_ref(e, t->inner); 466 return; 467 case DTK_TYPEDEF: 468 t->die_offset = buf_pos(&e->info_body); 469 form_uleb(&e->info_body, e->abbr_typedef); 470 emit_strx4(e, &e->info_body, t->name); 471 emit_type_ref(e, t->inner); 472 return; 473 case DTK_CONST: 474 t->die_offset = buf_pos(&e->info_body); 475 form_uleb(&e->info_body, e->abbr_qual_const); 476 emit_type_ref(e, t->inner); 477 return; 478 case DTK_VOLATILE: 479 t->die_offset = buf_pos(&e->info_body); 480 form_uleb(&e->info_body, e->abbr_qual_volatile); 481 emit_type_ref(e, t->inner); 482 return; 483 case DTK_RESTRICT: 484 t->die_offset = buf_pos(&e->info_body); 485 form_uleb(&e->info_body, e->abbr_qual_restrict); 486 emit_type_ref(e, t->inner); 487 return; 488 case DTK_ARRAY: 489 t->die_offset = buf_pos(&e->info_body); 490 form_uleb(&e->info_body, e->abbr_array); 491 emit_type_ref(e, t->inner); 492 if (t->array_count) { 493 form_uleb(&e->info_body, e->abbr_array_subrange); 494 form_uleb(&e->info_body, t->array_count); 495 } else { 496 form_uleb(&e->info_body, e->abbr_array_subrange_unbounded); 497 } 498 form_uleb(&e->info_body, 0); 499 return; 500 case DTK_FUNC: { 501 u32 i; 502 t->die_offset = buf_pos(&e->info_body); 503 form_uleb(&e->info_body, e->abbr_func_type); 504 emit_type_ref(e, t->inner); 505 /* DW_AT_prototyped flag_present has no body */ 506 for (i = 0; i < t->nparams; ++i) { 507 form_uleb(&e->info_body, e->abbr_func_type_param); 508 emit_type_ref(e, t->params[i]); 509 } 510 form_uleb(&e->info_body, 0); 511 return; 512 } 513 case DTK_RECORD: { 514 u32 i; 515 t->die_offset = buf_pos(&e->info_body); 516 form_uleb(&e->info_body, t->is_union ? e->abbr_union : e->abbr_struct); 517 emit_strx4(e, &e->info_body, t->name); 518 form_uleb(&e->info_body, t->byte_size); 519 for (i = 0; i < t->nfields; ++i) { 520 DebugRecField* f = &t->fields[i]; 521 form_uleb(&e->info_body, 522 f->bit_width ? e->abbr_member_bitfield : e->abbr_member); 523 emit_strx4(e, &e->info_body, f->name); 524 emit_type_ref(e, f->type); 525 form_uleb(&e->info_body, f->byte_offset); 526 if (f->bit_width) { 527 form_uleb(&e->info_body, f->bit_offset); 528 form_uleb(&e->info_body, f->bit_width); 529 } 530 } 531 form_uleb(&e->info_body, 0); 532 return; 533 } 534 case DTK_ENUM: { 535 u32 i; 536 DebugType* base; 537 t->die_offset = buf_pos(&e->info_body); 538 form_uleb(&e->info_body, e->abbr_enum); 539 emit_strx4(e, &e->info_body, t->name); 540 emit_type_ref(e, t->inner); 541 base = (t->inner != DEBUG_TYPE_NONE && t->inner <= e->d->ntypes) 542 ? &e->d->types[t->inner - 1] 543 : NULL; 544 form_uleb(&e->info_body, base ? base->byte_size : 4); 545 for (i = 0; i < t->nenums; ++i) { 546 form_uleb(&e->info_body, e->abbr_enum_val); 547 emit_strx4(e, &e->info_body, t->enum_vals[i].name); 548 form_sleb(&e->info_body, t->enum_vals[i].value); 549 } 550 form_uleb(&e->info_body, 0); 551 return; 552 } 553 } 554 } 555 556 /* ---------------------------------------------------------------- */ 557 /* Variable / scope emission. */ 558 559 static void emit_var_loc_exprloc(EmitCtx* e, Buf* b, DebugVarLoc loc) { 560 u8 expr[32]; 561 u32 n = 0; 562 u32 addr_payload_off = UINT32_MAX; 563 switch ((DebugVarLocKind)loc.kind) { 564 case DVL_REG: 565 if (loc.v.reg < 32) { 566 expr[n++] = (u8)(DW_OP_reg0 + loc.v.reg); 567 } else { 568 expr[n++] = DW_OP_regx; 569 n += form_uleb_inline(&expr[n], loc.v.reg); 570 } 571 break; 572 case DVL_FRAME: 573 expr[n++] = DW_OP_fbreg; 574 n += form_sleb_inline(&expr[n], loc.v.frame_ofs); 575 break; 576 case DVL_GLOBAL: { 577 u32 i; 578 expr[n++] = DW_OP_addr; 579 addr_payload_off = n; 580 for (i = 0; i < e->d->c->target.ptr_size; ++i) expr[n++] = 0; 581 break; 582 } 583 } 584 form_uleb(b, n); 585 { 586 u32 expr_start = buf_pos(b); 587 buf_write(b, expr, n); 588 if (loc.kind == DVL_GLOBAL && addr_payload_off != UINT32_MAX) { 589 add_addr_reloc(e, &e->info_relocs, &e->ninfo_relocs, &e->info_relocs_cap, 590 expr_start + addr_payload_off, loc.v.global); 591 } 592 } 593 } 594 595 static void emit_var_die(EmitCtx* e, DebugVarDIE* v) { 596 u32 abbrev = v->is_param ? e->abbr_param 597 : (v->external ? e->abbr_var_external : e->abbr_var); 598 v->die_offset = buf_pos(&e->info_body); 599 form_uleb(&e->info_body, abbrev); 600 /* DW_AT_external is flag_present and carries no body. */ 601 emit_strx4(e, &e->info_body, v->name); 602 form_uleb(&e->info_body, debug_file(e->d, v->decl.file_id)); 603 form_uleb(&e->info_body, v->decl.line); 604 emit_type_ref(e, v->type); 605 emit_var_loc_exprloc(e, &e->info_body, v->loc); 606 } 607 608 static void emit_scope_subtree(EmitCtx* e, DebugFunc* f, i32 scope_idx); 609 610 static void emit_vars_in_scope(EmitCtx* e, DebugFunc* f, i32 scope_idx) { 611 u32 i; 612 for (i = 0; i < f->nvars; ++i) { 613 DebugVarDIE* v = &f->vars[i]; 614 if (v->is_param) continue; 615 if (v->scope_idx == scope_idx) emit_var_die(e, v); 616 } 617 { 618 u32 s; 619 for (s = 0; s < f->nscopes; ++s) { 620 if (f->scopes[s].parent_idx == scope_idx) { 621 emit_scope_subtree(e, f, (i32)s); 622 } 623 } 624 } 625 } 626 627 static void emit_scope_subtree(EmitCtx* e, DebugFunc* f, i32 scope_idx) { 628 f->scopes[scope_idx].die_offset = buf_pos(&e->info_body); 629 form_uleb(&e->info_body, e->abbr_lexical_block); 630 emit_vars_in_scope(e, f, scope_idx); 631 form_uleb(&e->info_body, 0); 632 } 633 634 static void emit_subprogram_die(EmitCtx* e, DebugFunc* f) { 635 const ObjSym* osym = obj_symbol_get(e->ob, f->sym); 636 Sym name = osym ? osym->name : 0; 637 u32 reloc_off; 638 u32 fn_size; 639 DebugTypeId ret_type = DEBUG_TYPE_NONE; 640 if (f->fn_type != DEBUG_TYPE_NONE && f->fn_type <= e->d->ntypes) { 641 DebugType* tt = &e->d->types[f->fn_type - 1]; 642 if (tt->kind == DTK_FUNC) ret_type = tt->inner; 643 } 644 f->die_offset = buf_pos(&e->info_body); 645 form_uleb(&e->info_body, e->abbr_subprogram); 646 /* DW_AT_external (flag_present, no body) */ 647 emit_strx4(e, &e->info_body, name); 648 form_uleb(&e->info_body, debug_file(e->d, f->decl.file_id)); 649 form_uleb(&e->info_body, f->decl.line); 650 emit_type_ref(e, ret_type); 651 reloc_off = buf_pos(&e->info_body); 652 { 653 u8 zero8[8] = {0}; 654 buf_write(&e->info_body, zero8, e->d->c->target.ptr_size); 655 } 656 add_addr_reloc(e, &e->info_relocs, &e->ninfo_relocs, &e->info_relocs_cap, 657 reloc_off, f->sym); 658 fn_size = f->has_pc_range ? (f->end_ofs - f->begin_ofs) : 0; 659 form_u32(&e->info_body, fn_size); 660 { 661 u8 frame_expr[1] = {DW_OP_call_frame_cfa}; 662 form_uleb(&e->info_body, sizeof(frame_expr)); 663 buf_write(&e->info_body, frame_expr, sizeof(frame_expr)); 664 } 665 /* Children: params first, then top-level locals/scopes. */ 666 { 667 u32 i; 668 u32 emitted_params = 0; 669 for (i = 0; i < f->nvars; ++i) { 670 if (f->vars[i].is_param) { 671 emit_var_die(e, &f->vars[i]); 672 emitted_params++; 673 } 674 } 675 if (!emitted_params && f->fn_type != DEBUG_TYPE_NONE && 676 f->fn_type <= e->d->ntypes) { 677 DebugType* tt = &e->d->types[f->fn_type - 1]; 678 if (tt->kind == DTK_FUNC) { 679 for (i = 0; i < tt->nparams; ++i) { 680 form_uleb(&e->info_body, e->abbr_func_type_param); 681 emit_type_ref(e, tt->params[i]); 682 } 683 } 684 } 685 emit_vars_in_scope(e, f, -1); 686 form_uleb(&e->info_body, 0); 687 } 688 } 689 690 /* ---------------------------------------------------------------- */ 691 /* Section flushing. */ 692 693 static ObjSecId mk_section(EmitCtx* e, const char* name) { 694 Sym n = pool_intern_slice(e->pool, slice_from_cstr(name)); 695 return obj_section(e->ob, n, SEC_DEBUG, 0, 1); 696 } 697 698 /* Pre-create one SK_SECTION ObjSym pointing at `sec`. Section symbols are 699 * nameless (Sym 0); identity is the section_id they reference. SB_LOCAL 700 * because section symbols are always local in ELF/Mach-O. */ 701 static ObjSymId mk_section_sym(EmitCtx* e, ObjSecId sec) { 702 return obj_symbol(e->ob, 0, SB_LOCAL, SK_SECTION, sec, 0, 0); 703 } 704 705 static void flatten_to_section(EmitCtx* e, ObjSecId sec, const Buf* src) { 706 u32 total = buf_pos(src); 707 if (total == 0) return; 708 { 709 u8* dst = obj_reserve(e->ob, sec, total); 710 if (!dst) return; 711 buf_flatten(src, dst); 712 } 713 } 714 715 static void emit_section_str(EmitCtx* e) { 716 flatten_to_section(e, e->sec_str, &e->str.buf); 717 } 718 719 static void emit_section_line_str(EmitCtx* e) { 720 flatten_to_section(e, e->sec_line_str, &e->line_str.buf); 721 } 722 723 static void emit_section_str_offsets(EmitCtx* e) { 724 Buf b; 725 u32 i; 726 u32 unit_length; 727 u32 entries_off; /* byte offset of first entry within the section */ 728 buf_init(&b, e->heap); 729 unit_length = 4 + e->str.nsyms * 4; /* version+pad + N*4 */ 730 form_u32(&b, unit_length); 731 form_u16(&b, 5); 732 form_u16(&b, 0); 733 entries_off = buf_pos(&b); 734 for (i = 0; i < e->str.nsyms; ++i) { 735 /* Write the literal offset (so a bare-`.o` reader that doesn't apply 736 * relocs still sees the correct value), and *also* emit an R_ABS32 737 * reloc against .debug_str with addend = same literal. When the 738 * linker or JIT view-builder applies the reloc it overwrites the 739 * slot with S + addend; for a normal `.o` (debug sections not laid 740 * out) S=0 so the value is unchanged, and for the concatenated JIT 741 * view S = view-prefix into .debug_str so the slot picks up the 742 * right per-input offset. */ 743 u32* ofs = SymToU32_get(&e->str.by_sym, e->str.syms[i]); 744 form_u32(&b, ofs ? *ofs : 0); 745 } 746 flatten_to_section(e, e->sec_str_off, &b); 747 for (i = 0; i < e->str.nsyms; ++i) { 748 u32* ofs = SymToU32_get(&e->str.by_sym, e->str.syms[i]); 749 obj_reloc(e->ob, e->sec_str_off, entries_off + i * 4u, R_ABS32, e->ssym_str, 750 (i64)(ofs ? *ofs : 0)); 751 } 752 buf_fini(&b); 753 } 754 755 static void emit_section_abbrev(EmitCtx* e) { 756 Buf b; 757 buf_init(&b, e->heap); 758 abbrev_encode(&e->abbr, &b); 759 flatten_to_section(e, e->sec_abbrev, &b); 760 buf_fini(&b); 761 } 762 763 static ArchDwarfOps debug_dwarf_ops(const Debug* d) { 764 const ArchImpl* arch = arch_for_compiler(d ? d->c : NULL); 765 ArchDwarfOps ops; 766 ops.min_inst_len = 1u; 767 ops.max_ops_per_inst = 1u; 768 ops.pad[0] = 0; 769 ops.pad[1] = 0; 770 if (arch && arch->dwarf) { 771 if (arch->dwarf->min_inst_len) ops.min_inst_len = arch->dwarf->min_inst_len; 772 if (arch->dwarf->max_ops_per_inst) 773 ops.max_ops_per_inst = arch->dwarf->max_ops_per_inst; 774 } 775 return ops; 776 } 777 778 static void line_advance_pc(Buf* prog, u32 byte_delta, u32 min_inst_len) { 779 if (byte_delta == 0) return; 780 if (min_inst_len == 0) min_inst_len = 1; 781 if ((byte_delta % min_inst_len) == 0) { 782 form_u8(prog, DW_LNS_advance_pc); 783 form_uleb(prog, byte_delta / min_inst_len); 784 return; 785 } 786 787 while (byte_delta > 0xffffu) { 788 form_u8(prog, DW_LNS_fixed_advance_pc); 789 form_u16(prog, 0xffffu); 790 byte_delta -= 0xffffu; 791 } 792 form_u8(prog, DW_LNS_fixed_advance_pc); 793 form_u16(prog, (u16)byte_delta); 794 } 795 796 /* .debug_line program emission. 797 * 798 * Header layout (32-bit DWARF5): 799 * unit_length u32 800 * version u16 = 5 801 * address_size u8 802 * segment_selector_sz u8 803 * header_length u32 (excludes itself + earlier header fields) 804 * ... 805 * 806 * We emit, then track the program-start byte offset within the section so 807 * we can place address relocations. */ 808 static void emit_section_line(EmitCtx* e) { 809 Buf prog; 810 Buf hdr_body; /* header from min_inst_length onward */ 811 Buf out; 812 Pool* pool = e->pool; 813 u32 i, j; 814 u32 dir_count; 815 Sym* dirs = NULL; 816 u32 ndirs = 0, dirs_cap = 0; 817 ArchDwarfOps dwarf_ops = debug_dwarf_ops(e->d); 818 const u32 min_inst_len = dwarf_ops.min_inst_len ? dwarf_ops.min_inst_len : 1u; 819 const u32 max_ops_per_inst = 820 dwarf_ops.max_ops_per_inst ? dwarf_ops.max_ops_per_inst : 1u; 821 /* Pending line_strp relocs. Each slot is a u32 in hdr_body at 822 * `slot[k].at` with addend `slot[k].ofs` (the resolved .debug_line_str 823 * offset). Translated to section offsets and turned into R_ABS32 824 * relocs against e->ssym_line_str after we know hdr_body's location 825 * within the section. */ 826 struct LineStrpSlot { 827 u32 at; 828 u32 ofs; 829 }* lsp_slots = NULL; 830 u32 nlsp = 0, lsp_cap = 0; 831 832 buf_init(&prog, e->heap); 833 buf_init(&hdr_body, e->heap); 834 buf_init(&out, e->heap); 835 836 /* Build the program first (so we know its length). */ 837 for (i = 0; i < e->d->nfuncs; ++i) { 838 DebugFunc* f = &e->d->funcs[i]; 839 LineRow* prev = NULL; 840 u8 addr_size; 841 if (!f->has_pc_range) continue; 842 addr_size = e->d->c->target.ptr_size; 843 /* DW_LNE_set_address */ 844 form_u8(&prog, 0); 845 form_uleb(&prog, 1 + addr_size); 846 form_u8(&prog, DW_LNE_set_address); 847 { 848 u32 buf_ofs = buf_pos(&prog); 849 u8 zeros[8] = {0}; 850 buf_write(&prog, zeros, addr_size); 851 add_addr_reloc(e, &e->line_relocs, &e->nline_relocs, &e->line_relocs_cap, 852 buf_ofs, f->sym); 853 } 854 for (j = 0; j < f->nrows; ++j) { 855 LineRow* r = &f->rows[j]; 856 u32 dwfile = debug_file(e->d, r->loc.file_id); 857 i64 prev_line = prev ? prev->loc.line : 1; 858 u32 prev_offset = prev ? prev->offset : f->begin_ofs; 859 u32 pc_delta = r->offset - prev_offset; 860 i64 line_delta; 861 if (!prev || prev->loc.file_id != r->loc.file_id) { 862 form_u8(&prog, DW_LNS_set_file); 863 form_uleb(&prog, dwfile); 864 } 865 if (r->loc.col != (prev ? prev->loc.col : 0)) { 866 form_u8(&prog, DW_LNS_set_column); 867 form_uleb(&prog, r->loc.col); 868 } 869 if (pc_delta != 0) { 870 line_advance_pc(&prog, pc_delta, min_inst_len); 871 } 872 line_delta = (i64)r->loc.line - prev_line; 873 if (line_delta != 0) { 874 form_u8(&prog, DW_LNS_advance_line); 875 form_sleb(&prog, line_delta); 876 } 877 form_u8(&prog, DW_LNS_copy); 878 prev = r; 879 } 880 /* advance to function end before end_sequence */ 881 { 882 u32 last = prev ? prev->offset : f->begin_ofs; 883 u32 delta = f->end_ofs - last; 884 if (delta != 0) { 885 line_advance_pc(&prog, delta, min_inst_len); 886 } 887 } 888 form_u8(&prog, 0); 889 form_uleb(&prog, 1); 890 form_u8(&prog, DW_LNE_end_sequence); 891 } 892 893 /* Build header body (from min_inst_length onward). */ 894 form_u8(&hdr_body, (u8)min_inst_len); /* min_inst_length */ 895 form_u8(&hdr_body, (u8)max_ops_per_inst); /* max_ops_per_inst */ 896 form_u8(&hdr_body, 1); /* default_is_stmt = 1 */ 897 form_u8(&hdr_body, (u8)(i8)-5); /* line_base */ 898 form_u8(&hdr_body, 14); /* line_range */ 899 form_u8(&hdr_body, 13); /* opcode_base = #standard ops + 1 */ 900 /* DWARF 5 standard_opcode_lengths for opcodes 1..12 */ 901 { 902 u8 lens[12]; 903 lens[0] = 0; /* copy */ 904 lens[1] = 1; /* advance_pc */ 905 lens[2] = 1; /* advance_line */ 906 lens[3] = 1; /* set_file */ 907 lens[4] = 1; /* set_column */ 908 lens[5] = 0; /* negate_stmt */ 909 lens[6] = 0; /* set_basic_block */ 910 lens[7] = 0; /* const_add_pc */ 911 lens[8] = 1; /* fixed_advance_pc */ 912 lens[9] = 0; /* set_prologue_end */ 913 lens[10] = 0; /* set_epilogue_begin */ 914 lens[11] = 1; /* set_isa */ 915 buf_write(&hdr_body, lens, 12); 916 } 917 /* directories */ 918 form_u8(&hdr_body, 1); 919 form_uleb(&hdr_body, DW_LNCT_path); 920 form_uleb(&hdr_body, DW_FORM_line_strp); 921 /* dedup directories; index 0 is primary file's dir. */ 922 if (e->d->nfiles > 0) { 923 if (!VEC_GROW(e->heap, dirs, dirs_cap, ndirs + 1)) 924 dirs[ndirs++] = e->d->files[0].dir; 925 } else { 926 if (!VEC_GROW(e->heap, dirs, dirs_cap, ndirs + 1)) 927 dirs[ndirs++] = pool_intern_slice(pool, SLICE_LIT("")); 928 } 929 for (i = 1; i < e->d->nfiles; ++i) { 930 Sym dir = e->d->files[i].dir; 931 u32 di; 932 int found = 0; 933 for (di = 0; di < ndirs; ++di) { 934 if (dirs[di] == dir) { 935 found = 1; 936 break; 937 } 938 } 939 if (!found) { 940 if (!VEC_GROW(e->heap, dirs, dirs_cap, ndirs + 1)) dirs[ndirs++] = dir; 941 } 942 } 943 dir_count = ndirs; 944 form_uleb(&hdr_body, dir_count); 945 for (i = 0; i < dir_count; ++i) { 946 u32 at = buf_pos(&hdr_body); 947 u32 ofs = line_str_offset(e, dirs[i]); 948 form_u32(&hdr_body, ofs); /* literal; also bound to a reloc below */ 949 if (!VEC_GROW(e->heap, lsp_slots, lsp_cap, nlsp + 1)) { 950 lsp_slots[nlsp].at = at; 951 lsp_slots[nlsp].ofs = ofs; 952 nlsp++; 953 } 954 } 955 956 /* file_name_entry_format: 2 entries */ 957 form_u8(&hdr_body, 2); 958 form_uleb(&hdr_body, DW_LNCT_path); 959 form_uleb(&hdr_body, DW_FORM_line_strp); 960 form_uleb(&hdr_body, DW_LNCT_directory_index); 961 form_uleb(&hdr_body, DW_FORM_udata); 962 963 if (e->d->nfiles == 0) { 964 u32 at; 965 u32 ofs; 966 form_uleb(&hdr_body, 1); 967 at = buf_pos(&hdr_body); 968 ofs = line_str_offset(e, pool_intern_slice(pool, SLICE_LIT(""))); 969 form_u32(&hdr_body, ofs); 970 if (!VEC_GROW(e->heap, lsp_slots, lsp_cap, nlsp + 1)) { 971 lsp_slots[nlsp].at = at; 972 lsp_slots[nlsp].ofs = ofs; 973 nlsp++; 974 } 975 form_uleb(&hdr_body, 0); 976 } else { 977 form_uleb(&hdr_body, e->d->nfiles); 978 for (i = 0; i < e->d->nfiles; ++i) { 979 DebugFile* df = &e->d->files[i]; 980 u32 di; 981 u32 at = buf_pos(&hdr_body); 982 u32 ofs = line_str_offset(e, df->base); 983 form_u32(&hdr_body, ofs); 984 if (!VEC_GROW(e->heap, lsp_slots, lsp_cap, nlsp + 1)) { 985 lsp_slots[nlsp].at = at; 986 lsp_slots[nlsp].ofs = ofs; 987 nlsp++; 988 } 989 for (di = 0; di < ndirs; ++di) { 990 if (dirs[di] == df->dir) break; 991 } 992 form_uleb(&hdr_body, di < ndirs ? di : 0); 993 } 994 } 995 996 if (dirs) e->heap->free(e->heap, dirs, sizeof(Sym) * dirs_cap); 997 998 /* Compose final section bytes: unit-length header + hdr_body + program. */ 999 { 1000 u32 hl = buf_pos(&hdr_body); 1001 u32 plen = buf_pos(&prog); 1002 /* unit_length = (everything after the unit_length field itself) */ 1003 u32 unit_length = 2 + 1 + 1 + 4 + hl + plen; 1004 u8 addr_size = e->d->c->target.ptr_size; 1005 form_u32(&out, unit_length); 1006 form_u16(&out, 5); 1007 form_u8(&out, addr_size); 1008 form_u8(&out, 0); 1009 form_u32(&out, hl); 1010 /* Append hdr_body bytes */ 1011 { 1012 u8* tmp = (u8*)e->heap->alloc(e->heap, hl ? hl : 1, 1); 1013 if (tmp && hl) { 1014 buf_flatten(&hdr_body, tmp); 1015 buf_write(&out, tmp, hl); 1016 } 1017 if (tmp) e->heap->free(e->heap, tmp, hl ? hl : 1); 1018 } 1019 /* Append program bytes */ 1020 { 1021 u8* tmp = (u8*)e->heap->alloc(e->heap, plen ? plen : 1, 1); 1022 if (tmp && plen) { 1023 buf_flatten(&prog, tmp); 1024 buf_write(&out, tmp, plen); 1025 } 1026 if (tmp) e->heap->free(e->heap, tmp, plen ? plen : 1); 1027 } 1028 flatten_to_section(e, e->sec_line, &out); 1029 /* program-start in section bytes = 12 (unit_length+ver+addr+seg+hl) + hl. 1030 * hdr_body sits at section offset 12 (right after the unit header), 1031 * so a line_strp slot at hdr_body offset `at` is at section offset 1032 * `12 + at`. */ 1033 { 1034 u32 prog_start = 12 + hl; 1035 u32 hdr_start = 12; 1036 u32 k; 1037 for (k = 0; k < e->nline_relocs; ++k) { 1038 obj_reloc(e->ob, e->sec_line, prog_start + e->line_relocs[k].buf_offset, 1039 debug_addr_reloc_kind(e->d), e->line_relocs[k].sym, 0); 1040 } 1041 for (k = 0; k < nlsp; ++k) { 1042 obj_reloc(e->ob, e->sec_line, hdr_start + lsp_slots[k].at, R_ABS32, 1043 e->ssym_line_str, (i64)lsp_slots[k].ofs); 1044 } 1045 } 1046 } 1047 if (lsp_slots) 1048 e->heap->free(e->heap, lsp_slots, sizeof(*lsp_slots) * lsp_cap); 1049 buf_fini(&prog); 1050 buf_fini(&hdr_body); 1051 buf_fini(&out); 1052 } 1053 1054 /* .debug_aranges */ 1055 static void emit_section_aranges(EmitCtx* e) { 1056 Buf b; 1057 u32 i; 1058 u32 unit_length; 1059 u8 addr_size = e->d->c->target.ptr_size; 1060 u32 body_start; 1061 u32 padding; 1062 buf_init(&b, e->heap); 1063 form_u32(&b, 0); /* unit_length placeholder */ 1064 form_u16(&b, 2); /* aranges version */ 1065 form_u32(&b, 0); /* debug_info_offset — filled by R_ABS32 reloc below */ 1066 form_u8(&b, addr_size); 1067 form_u8(&b, 0); 1068 body_start = buf_pos(&b); 1069 /* Tuples are aligned to 2*addr_size from the section start. */ 1070 { 1071 u32 align = (u32)addr_size * 2; 1072 u32 mod = body_start % align; 1073 padding = mod ? (align - mod) : 0; 1074 while (padding--) { 1075 u8 z = 0; 1076 buf_write(&b, &z, 1); 1077 } 1078 } 1079 for (i = 0; i < e->d->nfuncs; ++i) { 1080 DebugFunc* f = &e->d->funcs[i]; 1081 if (!f->has_pc_range) continue; 1082 { 1083 u32 reloc_at = buf_pos(&b); 1084 u8 zeros[8] = {0}; 1085 buf_write(&b, zeros, addr_size); 1086 add_addr_reloc(e, &e->aranges_relocs, &e->naranges_relocs, 1087 &e->aranges_relocs_cap, reloc_at, f->sym); 1088 } 1089 { 1090 u32 fn_size = f->end_ofs - f->begin_ofs; 1091 if (addr_size == 8) 1092 form_u64(&b, fn_size); 1093 else 1094 form_u32(&b, fn_size); 1095 } 1096 } 1097 /* Terminator (zero, zero) */ 1098 { 1099 u8 zeros[16] = {0}; 1100 buf_write(&b, zeros, addr_size * 2); 1101 } 1102 unit_length = buf_pos(&b) - 4; 1103 { 1104 u8 le[4]; 1105 le[0] = (u8)(unit_length & 0xff); 1106 le[1] = (u8)((unit_length >> 8) & 0xff); 1107 le[2] = (u8)((unit_length >> 16) & 0xff); 1108 le[3] = (u8)((unit_length >> 24) & 0xff); 1109 buf_patch(&b, 0, le, 4); 1110 } 1111 flatten_to_section(e, e->sec_aranges, &b); 1112 /* debug_info_offset (header byte 6) points at this CU within 1113 * .debug_info. Emit it as a section-relative R_ABS32 against the 1114 * .debug_info section symbol (addend 0 — one CU per object at 1115 * offset 0) so that when the linker / JIT view concatenate multiple 1116 * inputs, each aranges unit is rebased to its CU's merged offset. 1117 * Without this every unit would keep offset 0 and addr2line would 1118 * map all addresses to the first input's CU. */ 1119 obj_reloc(e->ob, e->sec_aranges, 6u, R_ABS32, e->ssym_info, 0); 1120 for (i = 0; i < e->naranges_relocs; ++i) { 1121 obj_reloc(e->ob, e->sec_aranges, e->aranges_relocs[i].buf_offset, 1122 debug_addr_reloc_kind(e->d), e->aranges_relocs[i].sym, 0); 1123 } 1124 buf_fini(&b); 1125 } 1126 1127 /* .debug_rnglists */ 1128 static void emit_section_rnglists(EmitCtx* e) { 1129 Buf b; 1130 u32 unit_length; 1131 u32 i; 1132 u8 addr_size = e->d->c->target.ptr_size; 1133 buf_init(&b, e->heap); 1134 form_u32(&b, 0); /* placeholder unit_length */ 1135 form_u16(&b, 5); 1136 form_u8(&b, addr_size); 1137 form_u8(&b, 0); 1138 form_u32(&b, 0); /* offset_entry_count */ 1139 for (i = 0; i < e->d->nfuncs; ++i) { 1140 DebugFunc* f = &e->d->funcs[i]; 1141 if (!f->has_pc_range) continue; 1142 form_u8(&b, DW_RLE_start_length); 1143 { 1144 u32 reloc_at = buf_pos(&b); 1145 u8 zeros[8] = {0}; 1146 buf_write(&b, zeros, addr_size); 1147 add_addr_reloc(e, &e->rng_relocs, &e->nrng_relocs, &e->nrng_relocs_cap, 1148 reloc_at, f->sym); 1149 } 1150 form_uleb(&b, f->end_ofs - f->begin_ofs); 1151 } 1152 form_u8(&b, DW_RLE_end_of_list); 1153 unit_length = buf_pos(&b) - 4; 1154 { 1155 u8 le[4]; 1156 le[0] = (u8)(unit_length & 0xff); 1157 le[1] = (u8)((unit_length >> 8) & 0xff); 1158 le[2] = (u8)((unit_length >> 16) & 0xff); 1159 le[3] = (u8)((unit_length >> 24) & 0xff); 1160 buf_patch(&b, 0, le, 4); 1161 } 1162 flatten_to_section(e, e->sec_rnglists, &b); 1163 for (i = 0; i < e->nrng_relocs; ++i) { 1164 obj_reloc(e->ob, e->sec_rnglists, e->rng_relocs[i].buf_offset, 1165 debug_addr_reloc_kind(e->d), e->rng_relocs[i].sym, 0); 1166 } 1167 buf_fini(&b); 1168 } 1169 1170 /* .debug_info: prepend CU header, append body, apply relocs and fixups. */ 1171 static void emit_section_info(EmitCtx* e) { 1172 Buf out; 1173 u32 cu_header_size = 12; 1174 u32 body_size = buf_pos(&e->info_body); 1175 u32 unit_length = cu_header_size - 4 + body_size; 1176 buf_init(&out, e->heap); 1177 form_u32(&out, unit_length); 1178 form_u16(&out, 5); 1179 form_u8(&out, DW_UT_compile); 1180 form_u8(&out, e->d->c->target.ptr_size); 1181 form_u32(&out, 0); /* debug_abbrev_offset — filled by R_ABS32 reloc below */ 1182 /* Append body */ 1183 { 1184 u32 plen = body_size; 1185 u8* tmp = (u8*)e->heap->alloc(e->heap, plen ? plen : 1, 1); 1186 if (tmp && plen) { 1187 buf_flatten(&e->info_body, tmp); 1188 buf_write(&out, tmp, plen); 1189 } 1190 if (tmp) e->heap->free(e->heap, tmp, plen ? plen : 1); 1191 } 1192 flatten_to_section(e, e->sec_info, &out); 1193 /* CU header cross-section refs: debug_abbrev_offset at byte 8. Root 1194 * DIE cross-section refs (stmt_list / ranges / str_offsets_base) live 1195 * at body offsets captured during CU-body construction; section offset 1196 * is cu_header_size + body offset. Addend carries the in-target 1197 * offset (0 for abbrev/stmt_list, 12 for rnglists past its header, 8 1198 * for str_offsets past its header). */ 1199 obj_reloc(e->ob, e->sec_info, 8u, R_ABS32, e->ssym_abbrev, 0); 1200 obj_reloc(e->ob, e->sec_info, cu_header_size + e->root_stmt_list_at, R_ABS32, 1201 e->ssym_line, 0); 1202 obj_reloc(e->ob, e->sec_info, cu_header_size + e->root_ranges_at, R_ABS32, 1203 e->ssym_rnglists, 12); 1204 obj_reloc(e->ob, e->sec_info, cu_header_size + e->root_str_off_base_at, 1205 R_ABS32, e->ssym_str_off, 8); 1206 /* Apply forward DIE refs (DW_FORM_ref4 = CU-relative, where the CU 1207 * starts at the unit_length field. body offset 0 is at section 1208 * offset cu_header_size = 12 (post-header, post-unit_length). DW5 1209 * ref4 is unit-relative, i.e. distance from the start of the unit 1210 * (i.e. the unit_length field itself), so the on-disk u32 stored is 1211 * cu_header_size + target_body_offset. */ 1212 { 1213 u32 i; 1214 for (i = 0; i < e->nfixups; ++i) { 1215 DieFixup* fx = &e->fixups[i]; 1216 DebugType* tt = 1217 (fx->target != DEBUG_TYPE_NONE && fx->target <= e->d->ntypes) 1218 ? &e->d->types[fx->target - 1] 1219 : NULL; 1220 u32 target_body_ofs = (tt && tt->die_offset) ? tt->die_offset : 0; 1221 u32 cu_relative = 1222 target_body_ofs ? (cu_header_size + target_body_ofs) : 0; 1223 u8 le[4]; 1224 le[0] = (u8)(cu_relative & 0xff); 1225 le[1] = (u8)((cu_relative >> 8) & 0xff); 1226 le[2] = (u8)((cu_relative >> 16) & 0xff); 1227 le[3] = (u8)((cu_relative >> 24) & 0xff); 1228 obj_patch(e->ob, e->sec_info, cu_header_size + fx->buf_offset, le, 4); 1229 } 1230 for (i = 0; i < e->ninfo_relocs; ++i) { 1231 obj_reloc(e->ob, e->sec_info, 1232 cu_header_size + e->info_relocs[i].buf_offset, 1233 debug_addr_reloc_kind(e->d), e->info_relocs[i].sym, 0); 1234 } 1235 } 1236 buf_fini(&out); 1237 } 1238 1239 /* ---------------------------------------------------------------- */ 1240 1241 void debug_emit(Debug* d) { 1242 EmitCtx ec; 1243 Pool* pool = d->c->global; 1244 Sym producer_sym; 1245 Sym primary_dir = 0, primary_base = 0; 1246 u32 i; 1247 1248 /* Zero out via memset on a sized chunk. Avoid forms that clang lowers 1249 * to bzero on this size. We zero with an explicit byte-loop fallback 1250 * to match the lib_deps allowlist (which forbids _bzero). */ 1251 { 1252 u8* p = (u8*)&ec; 1253 size_t k; 1254 for (k = 0; k < sizeof(ec); ++k) p[k] = 0; 1255 } 1256 ec.d = d; 1257 ec.heap = d->heap; 1258 ec.pool = pool; 1259 ec.ob = d->ob; 1260 buf_init(&ec.info_body, d->heap); 1261 str_init(&ec.str, d->heap); 1262 str_init(&ec.line_str, d->heap); 1263 abbrev_init(&ec.abbr, d->heap); 1264 1265 resolve_abbrevs(&ec); 1266 1267 /* Pre-create every debug section + a paired SK_SECTION ObjSym, before 1268 * any DIE/program payload is emitted. Cross-section relocations 1269 * (CU-header debug_abbrev_offset, root-DIE stmt_list / ranges / 1270 * str_offsets_base, .debug_line line_strp slots, .debug_str_offsets 1271 * entries) name these symbols, so they must exist by the time the 1272 * relocs are recorded. Section order in the output `.o` is fixed by 1273 * obj_section call order and matches the previous emission. */ 1274 ec.sec_abbrev = mk_section(&ec, ".debug_abbrev"); 1275 ec.sec_line = mk_section(&ec, ".debug_line"); 1276 ec.sec_aranges = mk_section(&ec, ".debug_aranges"); 1277 ec.sec_rnglists = mk_section(&ec, ".debug_rnglists"); 1278 ec.sec_info = mk_section(&ec, ".debug_info"); 1279 ec.sec_str = mk_section(&ec, ".debug_str"); 1280 ec.sec_line_str = mk_section(&ec, ".debug_line_str"); 1281 ec.sec_str_off = mk_section(&ec, ".debug_str_offsets"); 1282 ec.ssym_abbrev = mk_section_sym(&ec, ec.sec_abbrev); 1283 ec.ssym_line = mk_section_sym(&ec, ec.sec_line); 1284 ec.ssym_rnglists = mk_section_sym(&ec, ec.sec_rnglists); 1285 ec.ssym_str = mk_section_sym(&ec, ec.sec_str); 1286 ec.ssym_line_str = mk_section_sym(&ec, ec.sec_line_str); 1287 ec.ssym_str_off = mk_section_sym(&ec, ec.sec_str_off); 1288 ec.ssym_info = mk_section_sym(&ec, ec.sec_info); 1289 1290 producer_sym = pool_intern_slice(pool, SLICE_LIT("kit 0.1")); 1291 /* Ensure the CU's primary source file occupies file-table slot 0 before 1292 * we read it for DW_AT_name/comp_dir. debug_file() is otherwise first 1293 * invoked later (child-DIE decl_file / line program), so without this the 1294 * CU name and comp_dir come out empty. Seed it from the first function's 1295 * declaration site. */ 1296 if (d->nfiles == 0) { 1297 if (d->nfuncs > 0) { 1298 (void)debug_file(d, d->funcs[0].decl.file_id); 1299 } else if (d->nglobals > 0) { 1300 (void)debug_file(d, d->globals[0].decl.file_id); 1301 } 1302 } 1303 if (d->nfiles > 0) { 1304 primary_dir = d->files[0].dir; 1305 primary_base = d->files[0].base; 1306 } else { 1307 primary_dir = pool_intern_slice(pool, SLICE_LIT("")); 1308 primary_base = pool_intern_slice(pool, SLICE_LIT("")); 1309 } 1310 1311 /* CU root DIE */ 1312 form_uleb(&ec.info_body, ec.abbr_cu); 1313 emit_strx4(&ec, &ec.info_body, producer_sym); 1314 form_u16(&ec.info_body, DW_LANG_C11); 1315 emit_strx4(&ec, &ec.info_body, primary_base); 1316 emit_strx4(&ec, &ec.info_body, primary_dir); 1317 /* DW_AT_stmt_list → offset 0 in .debug_line. Write the literal so a 1318 * bare-`.o` reader still sees the correct value; the paired R_ABS32 1319 * reloc emitted in emit_section_info() overwrites the slot in the 1320 * JIT view path where multiple inputs' .debug_line sections are 1321 * concatenated. */ 1322 ec.root_stmt_list_at = buf_pos(&ec.info_body); 1323 form_u32(&ec.info_body, 0); 1324 { 1325 u8 z[8] = {0}; 1326 buf_write(&ec.info_body, z, d->c->target.ptr_size); 1327 } 1328 /* DW_AT_ranges → 12 bytes into .debug_rnglists, post header. */ 1329 ec.root_ranges_at = buf_pos(&ec.info_body); 1330 form_u32(&ec.info_body, 12); 1331 /* DW_AT_str_offsets_base → 8 bytes into .debug_str_offsets, post header. */ 1332 ec.root_str_off_base_at = buf_pos(&ec.info_body); 1333 form_u32(&ec.info_body, 8); 1334 1335 for (i = 0; i < d->ntypes; ++i) emit_type_die(&ec, (DebugTypeId)(i + 1)); 1336 for (i = 0; i < d->nglobals; ++i) emit_var_die(&ec, &d->globals[i]); 1337 for (i = 0; i < d->nfuncs; ++i) emit_subprogram_die(&ec, &d->funcs[i]); 1338 form_uleb(&ec.info_body, 0); /* end of CU children */ 1339 1340 /* Order: build sections that don't depend on later ones first. The str 1341 * tables are populated lazily during emission, so flush them last. */ 1342 emit_section_abbrev(&ec); 1343 emit_section_line(&ec); 1344 emit_section_aranges(&ec); 1345 emit_section_rnglists(&ec); 1346 emit_section_info(&ec); 1347 emit_section_str(&ec); 1348 emit_section_line_str(&ec); 1349 emit_section_str_offsets(&ec); 1350 1351 /* Cleanup */ 1352 buf_fini(&ec.info_body); 1353 str_fini(&ec.str, ec.heap); 1354 str_fini(&ec.line_str, ec.heap); 1355 abbrev_fini_heap(&ec.abbr, ec.heap); 1356 if (ec.fixups) 1357 ec.heap->free(ec.heap, ec.fixups, sizeof(DieFixup) * ec.fixups_cap); 1358 if (ec.info_relocs) 1359 ec.heap->free(ec.heap, ec.info_relocs, 1360 sizeof(AddrReloc) * ec.info_relocs_cap); 1361 if (ec.line_relocs) 1362 ec.heap->free(ec.heap, ec.line_relocs, 1363 sizeof(AddrReloc) * ec.line_relocs_cap); 1364 if (ec.aranges_relocs) 1365 ec.heap->free(ec.heap, ec.aranges_relocs, 1366 sizeof(AddrReloc) * ec.aranges_relocs_cap); 1367 if (ec.rng_relocs) 1368 ec.heap->free(ec.heap, ec.rng_relocs, 1369 sizeof(AddrReloc) * ec.nrng_relocs_cap); 1370 }