kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 }