kit

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

debug.c (15497B)


      1 /* Debug producer: state, type DIE pool, function/scope/var lifecycle, and
      2  * line-row accumulator. Emit-side serialization lives in debug_emit.c. */
      3 
      4 #include <string.h>
      5 
      6 #include "core/core.h"
      7 #include "core/heap.h"
      8 #include "core/pool.h"
      9 #include "core/slice.h"
     10 #include "core/vec.h"
     11 #include "debug/debug_internal.h"
     12 
     13 /* ---- internal helpers ---- */
     14 
     15 static _Noreturn void debug_oom(Debug* d, const char* what) {
     16   SrcLoc nl = {0, 0, 0};
     17   compiler_panic(d->c, nl, "debug: oom (%.*s)",
     18                  SLICE_ARG(slice_from_cstr(what)));
     19 }
     20 
     21 static DebugTypeId type_alloc(Debug* d) {
     22   DebugType* slot;
     23   if (VEC_GROW(d->heap, d->types, d->types_cap, d->ntypes + 1))
     24     debug_oom(d, "type pool");
     25   slot = &d->types[d->ntypes++];
     26   memset(slot, 0, sizeof(*slot));
     27   return (DebugTypeId)d->ntypes;
     28 }
     29 
     30 DebugType* debug_type_at(Debug* d, DebugTypeId id);
     31 DebugType* debug_type_at(Debug* d, DebugTypeId id) {
     32   if (id == DEBUG_TYPE_NONE || id > d->ntypes) return NULL;
     33   return &d->types[id - 1];
     34 }
     35 
     36 /* ---- public API: lifecycle ---- */
     37 
     38 Debug* debug_new(Compiler* c, ObjBuilder* ob) {
     39   Heap* h = (Heap*)c->ctx->heap;
     40   Debug* d = (Debug*)h->alloc(h, sizeof(*d), _Alignof(Debug));
     41   SrcLoc no_loc = {0, 0, 0};
     42   if (!d) return NULL;
     43   memset(d, 0, sizeof(*d));
     44   d->c = c;
     45   d->ob = ob;
     46   d->heap = h;
     47   d->cur_func = -1;
     48   d->pending_loc = no_loc;
     49   U32ToU32_init(&d->src_to_file, h);
     50   return d;
     51 }
     52 
     53 static void func_free(Debug* d, DebugFunc* f) {
     54   if (f->vars) d->heap->free(d->heap, f->vars, sizeof(*f->vars) * f->vars_cap);
     55   if (f->scopes)
     56     d->heap->free(d->heap, f->scopes, sizeof(*f->scopes) * f->scopes_cap);
     57   if (f->scope_stack)
     58     d->heap->free(d->heap, f->scope_stack,
     59                   sizeof(*f->scope_stack) * f->scope_stack_cap);
     60   if (f->rows) d->heap->free(d->heap, f->rows, sizeof(*f->rows) * f->rows_cap);
     61 }
     62 
     63 static void type_free(Debug* d, DebugType* t) {
     64   if (t->params)
     65     d->heap->free(d->heap, t->params, sizeof(*t->params) * t->nparams);
     66   if (t->fields)
     67     d->heap->free(d->heap, t->fields, sizeof(*t->fields) * t->nfields);
     68   if (t->enum_vals)
     69     d->heap->free(d->heap, t->enum_vals, sizeof(*t->enum_vals) * t->nenums);
     70 }
     71 
     72 void debug_free(Debug* d) {
     73   u32 i;
     74   if (!d) return;
     75   for (i = 0; i < d->nfuncs; ++i) func_free(d, &d->funcs[i]);
     76   if (d->funcs)
     77     d->heap->free(d->heap, d->funcs, sizeof(*d->funcs) * d->funcs_cap);
     78   for (i = 0; i < d->ntypes; ++i) type_free(d, &d->types[i]);
     79   if (d->types)
     80     d->heap->free(d->heap, d->types, sizeof(*d->types) * d->types_cap);
     81   if (d->files)
     82     d->heap->free(d->heap, d->files, sizeof(*d->files) * d->files_cap);
     83   if (d->loclists) {
     84     for (i = 0; i < d->nloclists; ++i) {
     85       DebugLocList* l = &d->loclists[i];
     86       if (l->entries)
     87         d->heap->free(d->heap, l->entries, sizeof(*l->entries) * l->cap);
     88     }
     89     d->heap->free(d->heap, d->loclists, sizeof(*d->loclists) * d->loclists_cap);
     90   }
     91   U32ToU32_fini(&d->src_to_file);
     92   d->heap->free(d->heap, d, sizeof(*d));
     93 }
     94 
     95 /* ---- file table ---- */
     96 
     97 static void split_path(Pool* p, Sym path, Sym* dir_out, Sym* base_out) {
     98   Slice sl = pool_slice(p, path);
     99   const char* s = sl.s;
    100   size_t len = sl.len;
    101   size_t i;
    102   size_t slash = (size_t)-1;
    103   if (!s || len == 0) {
    104     *dir_out = pool_intern_slice(p, SLICE_LIT(""));
    105     *base_out = path ? path : pool_intern_slice(p, SLICE_LIT(""));
    106     return;
    107   }
    108   for (i = 0; i < len; ++i) {
    109     if (s[i] == '/') slash = i;
    110   }
    111   if (slash == (size_t)-1) {
    112     *dir_out = pool_intern_slice(p, SLICE_LIT(""));
    113     *base_out = path;
    114     return;
    115   }
    116   *dir_out = pool_intern_slice(p, (Slice){.s = s, .len = slash});
    117   *base_out =
    118       pool_intern_slice(p, (Slice){.s = s + slash + 1, .len = len - slash - 1});
    119 }
    120 
    121 u32 debug_file(Debug* d, u32 source_file_id) {
    122   u32* found = U32ToU32_get(&d->src_to_file, source_file_id + 1);
    123   if (found) return *found;
    124   {
    125     const SourceFile* sf = source_file(d->c->sources, source_file_id);
    126     DebugFile* slot;
    127     Sym path = 0, dir, base;
    128     if (sf) path = sf->path ? sf->path : sf->name;
    129     if (!path) path = pool_intern_slice(d->c->global, SLICE_LIT(""));
    130     split_path(d->c->global, path, &dir, &base);
    131     if (VEC_GROW(d->heap, d->files, d->files_cap, d->nfiles + 1))
    132       debug_oom(d, "file table");
    133     slot = &d->files[d->nfiles];
    134     slot->src_file_id = source_file_id;
    135     slot->dir = dir;
    136     slot->base = base;
    137     {
    138       u32 idx = d->nfiles;
    139       d->nfiles++;
    140       U32ToU32_set(&d->src_to_file, source_file_id + 1, idx);
    141       return idx;
    142     }
    143   }
    144 }
    145 
    146 /* ---- type DIEs ---- */
    147 
    148 DebugTypeId debug_type_base(Debug* d, Sym name, DebugBaseEncoding enc,
    149                             u32 byte_size) {
    150   DebugTypeId id = type_alloc(d);
    151   DebugType* t = debug_type_at(d, id);
    152   t->kind = DTK_BASE;
    153   t->name = name;
    154   t->byte_size = byte_size;
    155   t->base_encoding = (u8)enc;
    156   return id;
    157 }
    158 
    159 DebugTypeId debug_type_void(Debug* d) {
    160   if (d->void_type) return d->void_type;
    161   {
    162     DebugTypeId id = type_alloc(d);
    163     DebugType* t = debug_type_at(d, id);
    164     t->kind = DTK_VOID;
    165     d->void_type = id;
    166     return id;
    167   }
    168 }
    169 
    170 DebugTypeId debug_type_ptr(Debug* d, DebugTypeId pointee) {
    171   DebugTypeId id = type_alloc(d);
    172   DebugType* t = debug_type_at(d, id);
    173   t->kind = DTK_PTR;
    174   t->inner = pointee;
    175   t->byte_size = d->c->target.ptr_size;
    176   return id;
    177 }
    178 
    179 DebugTypeId debug_type_array(Debug* d, DebugTypeId elem, u32 count) {
    180   DebugTypeId id = type_alloc(d);
    181   DebugType* t = debug_type_at(d, id);
    182   t->kind = DTK_ARRAY;
    183   t->inner = elem;
    184   t->array_count = count;
    185   return id;
    186 }
    187 
    188 DebugTypeId debug_type_const(Debug* d, DebugTypeId base) {
    189   DebugTypeId id = type_alloc(d);
    190   DebugType* t = debug_type_at(d, id);
    191   t->kind = DTK_CONST;
    192   t->inner = base;
    193   return id;
    194 }
    195 
    196 DebugTypeId debug_type_volatile(Debug* d, DebugTypeId base) {
    197   DebugTypeId id = type_alloc(d);
    198   DebugType* t = debug_type_at(d, id);
    199   t->kind = DTK_VOLATILE;
    200   t->inner = base;
    201   return id;
    202 }
    203 
    204 DebugTypeId debug_type_restrict(Debug* d, DebugTypeId base) {
    205   DebugTypeId id = type_alloc(d);
    206   DebugType* t = debug_type_at(d, id);
    207   t->kind = DTK_RESTRICT;
    208   t->inner = base;
    209   return id;
    210 }
    211 
    212 DebugTypeId debug_type_typedef(Debug* d, Sym name, DebugTypeId base) {
    213   DebugTypeId id = type_alloc(d);
    214   DebugType* t = debug_type_at(d, id);
    215   t->kind = DTK_TYPEDEF;
    216   t->name = name;
    217   t->inner = base;
    218   return id;
    219 }
    220 
    221 DebugTypeId debug_type_func(Debug* d, DebugTypeId ret,
    222                             const DebugTypeId* params, u32 nparams,
    223                             int variadic) {
    224   DebugTypeId id = type_alloc(d);
    225   DebugType* t = debug_type_at(d, id);
    226   t->kind = DTK_FUNC;
    227   t->inner = ret;
    228   t->variadic = (u8)(variadic ? 1 : 0);
    229   if (nparams) {
    230     t->params = (DebugTypeId*)d->heap->alloc(
    231         d->heap, sizeof(DebugTypeId) * nparams, _Alignof(DebugTypeId));
    232     if (!t->params) debug_oom(d, "func params");
    233     memcpy(t->params, params, sizeof(DebugTypeId) * nparams);
    234     t->nparams = nparams;
    235   }
    236   return id;
    237 }
    238 
    239 /* ---- record builders ---- */
    240 
    241 DebugTypeBuilder* debug_type_record_begin(Debug* d, Sym tag, int is_union,
    242                                           u32 byte_size, u32 align) {
    243   DebugTypeBuilder* b = (DebugTypeBuilder*)d->heap->alloc(
    244       d->heap, sizeof(*b), _Alignof(DebugTypeBuilder));
    245   if (!b) debug_oom(d, "rec builder");
    246   memset(b, 0, sizeof(*b));
    247   b->d = d;
    248   b->is_union = (u8)(is_union ? 1 : 0);
    249   b->tag = tag;
    250   b->byte_size = byte_size;
    251   b->align = align;
    252   return b;
    253 }
    254 
    255 void debug_type_record_field(DebugTypeBuilder* b, Sym name, DebugTypeId type,
    256                              u32 byte_offset) {
    257   DebugRecField* f;
    258   if (VEC_GROW(b->d->heap, b->fields, b->fields_cap, b->nfields + 1))
    259     debug_oom(b->d, "rec field");
    260   f = &b->fields[b->nfields++];
    261   f->name = name;
    262   f->type = type;
    263   f->byte_offset = byte_offset;
    264   f->bit_offset = 0;
    265   f->bit_width = 0;
    266 }
    267 
    268 void debug_type_record_bitfield(DebugTypeBuilder* b, Sym name, DebugTypeId type,
    269                                 u32 byte_offset, u16 bit_offset,
    270                                 u16 bit_width) {
    271   DebugRecField* f;
    272   if (VEC_GROW(b->d->heap, b->fields, b->fields_cap, b->nfields + 1))
    273     debug_oom(b->d, "rec field");
    274   f = &b->fields[b->nfields++];
    275   f->name = name;
    276   f->type = type;
    277   f->byte_offset = byte_offset;
    278   f->bit_offset = bit_offset;
    279   f->bit_width = bit_width;
    280 }
    281 
    282 DebugTypeId debug_type_record_end(DebugTypeBuilder* b) {
    283   Debug* d = b->d;
    284   DebugTypeId id = type_alloc(d);
    285   DebugType* t = debug_type_at(d, id);
    286   t->kind = DTK_RECORD;
    287   t->is_union = b->is_union;
    288   t->name = b->tag;
    289   t->byte_size = b->byte_size;
    290   t->align = b->align;
    291   if (b->nfields) {
    292     t->fields = (DebugRecField*)d->heap->alloc(
    293         d->heap, sizeof(DebugRecField) * b->nfields, _Alignof(DebugRecField));
    294     if (!t->fields) debug_oom(d, "rec fields");
    295     memcpy(t->fields, b->fields, sizeof(DebugRecField) * b->nfields);
    296     t->nfields = b->nfields;
    297   }
    298   if (b->fields)
    299     d->heap->free(d->heap, b->fields, sizeof(*b->fields) * b->fields_cap);
    300   d->heap->free(d->heap, b, sizeof(*b));
    301   return id;
    302 }
    303 
    304 DebugEnumBuilder* debug_type_enum_begin(Debug* d, Sym tag, DebugTypeId base) {
    305   DebugEnumBuilder* b = (DebugEnumBuilder*)d->heap->alloc(
    306       d->heap, sizeof(*b), _Alignof(DebugEnumBuilder));
    307   if (!b) debug_oom(d, "enum builder");
    308   memset(b, 0, sizeof(*b));
    309   b->d = d;
    310   b->tag = tag;
    311   b->base = base;
    312   return b;
    313 }
    314 
    315 void debug_type_enum_value(DebugEnumBuilder* b, Sym name, i64 value) {
    316   DebugEnumVal* v;
    317   if (VEC_GROW(b->d->heap, b->vals, b->vals_cap, b->nvals + 1))
    318     debug_oom(b->d, "enum val");
    319   v = &b->vals[b->nvals++];
    320   v->name = name;
    321   v->value = value;
    322 }
    323 
    324 DebugTypeId debug_type_enum_end(DebugEnumBuilder* b) {
    325   Debug* d = b->d;
    326   DebugTypeId id = type_alloc(d);
    327   DebugType* t = debug_type_at(d, id);
    328   t->kind = DTK_ENUM;
    329   t->name = b->tag;
    330   t->inner = b->base;
    331   if (b->nvals) {
    332     t->enum_vals = (DebugEnumVal*)d->heap->alloc(
    333         d->heap, sizeof(DebugEnumVal) * b->nvals, _Alignof(DebugEnumVal));
    334     if (!t->enum_vals) debug_oom(d, "enum vals");
    335     memcpy(t->enum_vals, b->vals, sizeof(DebugEnumVal) * b->nvals);
    336     t->nenums = b->nvals;
    337   }
    338   if (b->vals) d->heap->free(d->heap, b->vals, sizeof(*b->vals) * b->vals_cap);
    339   d->heap->free(d->heap, b, sizeof(*b));
    340   return id;
    341 }
    342 
    343 /* ---- function lifecycle ---- */
    344 
    345 void debug_func_begin(Debug* d, ObjSymId sym, DebugTypeId fn_type,
    346                       SrcLoc decl) {
    347   DebugFunc* f;
    348   if (VEC_GROW(d->heap, d->funcs, d->funcs_cap, d->nfuncs + 1))
    349     debug_oom(d, "func table");
    350   f = &d->funcs[d->nfuncs];
    351   memset(f, 0, sizeof(*f));
    352   f->sym = sym;
    353   f->fn_type = fn_type;
    354   f->decl = decl;
    355   f->text_section = OBJ_SEC_NONE;
    356   d->cur_func = (i32)d->nfuncs;
    357   d->nfuncs++;
    358 }
    359 
    360 void debug_func_select(Debug* d, ObjSymId sym) {
    361   if (!d || sym == OBJ_SYM_NONE) return;
    362   for (u32 i = 0; i < d->nfuncs; ++i) {
    363     if (d->funcs[i].sym == sym) {
    364       d->cur_func = (i32)i;
    365       return;
    366     }
    367   }
    368 }
    369 
    370 void debug_func_pc_range(Debug* d, ObjSecId text_section, u32 begin_ofs,
    371                          u32 end_ofs) {
    372   if (d->cur_func < 0) return;
    373   {
    374     DebugFunc* f = &d->funcs[d->cur_func];
    375     f->text_section = text_section;
    376     f->begin_ofs = begin_ofs;
    377     f->end_ofs = end_ofs;
    378     f->has_pc_range = 1;
    379   }
    380 }
    381 
    382 void debug_func_end(Debug* d) {
    383   if (d->cur_func < 0) return;
    384   d->cur_func = -1;
    385 }
    386 
    387 void debug_prune_removed_funcs(Debug* d) {
    388   u32 w = 0;
    389   if (!d) return;
    390   for (u32 r = 0; r < d->nfuncs; ++r) {
    391     DebugFunc* f = &d->funcs[r];
    392     const ObjSym* sym = obj_symbol_get(d->ob, f->sym);
    393     if (!sym || sym->removed) {
    394       func_free(d, f);
    395       continue;
    396     }
    397     if (w != r) d->funcs[w] = *f;
    398     ++w;
    399   }
    400   d->nfuncs = w;
    401   d->cur_func = -1;
    402 }
    403 
    404 /* ---- scopes ---- */
    405 
    406 void debug_scope_begin(Debug* d, SrcLoc loc) {
    407   DebugFunc* f;
    408   i32 scope_idx;
    409   if (d->cur_func < 0) return;
    410   f = &d->funcs[d->cur_func];
    411   if (VEC_GROW(d->heap, f->scopes, f->scopes_cap, f->nscopes + 1))
    412     debug_oom(d, "scopes");
    413   if (VEC_GROW(d->heap, f->scope_stack, f->scope_stack_cap,
    414                f->scope_stack_n + 1))
    415     debug_oom(d, "scope stack");
    416   scope_idx = (i32)f->nscopes;
    417   f->scopes[scope_idx].parent_idx =
    418       f->scope_stack_n ? f->scope_stack[f->scope_stack_n - 1] : -1;
    419   f->scopes[scope_idx].begin = loc;
    420   f->scopes[scope_idx].end = loc;
    421   f->scopes[scope_idx].die_offset = 0;
    422   f->nscopes++;
    423   f->scope_stack[f->scope_stack_n++] = scope_idx;
    424 }
    425 
    426 void debug_scope_end(Debug* d, SrcLoc loc) {
    427   DebugFunc* f;
    428   if (d->cur_func < 0) return;
    429   f = &d->funcs[d->cur_func];
    430   if (f->scope_stack_n == 0) return;
    431   {
    432     i32 top = f->scope_stack[--f->scope_stack_n];
    433     f->scopes[top].end = loc;
    434   }
    435 }
    436 
    437 /* ---- variables ---- */
    438 
    439 static i32 cur_scope_idx(DebugFunc* f) {
    440   if (f->scope_stack_n == 0) return -1;
    441   return f->scope_stack[f->scope_stack_n - 1];
    442 }
    443 
    444 void debug_param(Debug* d, Sym name, DebugTypeId type, SrcLoc loc, u32 idx,
    445                  DebugVarLoc vloc) {
    446   DebugFunc* f;
    447   DebugVarDIE* v;
    448   if (d->cur_func < 0) return;
    449   f = &d->funcs[d->cur_func];
    450   if (VEC_GROW(d->heap, f->vars, f->vars_cap, f->nvars + 1))
    451     debug_oom(d, "vars");
    452   v = &f->vars[f->nvars++];
    453   v->is_param = 1;
    454   v->param_idx = idx;
    455   v->name = name;
    456   v->type = type;
    457   v->decl = loc;
    458   v->loc = vloc;
    459   v->scope_idx = -1;
    460   v->die_offset = 0;
    461 }
    462 
    463 void debug_local(Debug* d, Sym name, DebugTypeId type, SrcLoc loc,
    464                  DebugVarLoc vloc) {
    465   DebugFunc* f;
    466   DebugVarDIE* v;
    467   if (d->cur_func < 0) return;
    468   f = &d->funcs[d->cur_func];
    469   if (VEC_GROW(d->heap, f->vars, f->vars_cap, f->nvars + 1))
    470     debug_oom(d, "vars");
    471   v = &f->vars[f->nvars++];
    472   v->is_param = 0;
    473   v->name = name;
    474   v->type = type;
    475   v->decl = loc;
    476   v->loc = vloc;
    477   v->scope_idx = cur_scope_idx(f);
    478   v->die_offset = 0;
    479 }
    480 
    481 /* ---- line program input ---- */
    482 
    483 void debug_set_pending_loc(Debug* d, SrcLoc loc) {
    484   if (!d) return;
    485   d->pending_loc = loc;
    486 }
    487 
    488 void debug_emit_row(Debug* d, ObjSecId text_section_id, u32 text_offset,
    489                     SrcLoc loc) {
    490   debug_line(d, text_section_id, text_offset, loc, 1);
    491 }
    492 
    493 void debug_line(Debug* d, ObjSecId text_section_id, u32 text_offset, SrcLoc loc,
    494                 int is_stmt) {
    495   DebugFunc* f;
    496   LineRow* prev;
    497   LineRow* row;
    498   if (d->cur_func < 0) return;
    499   f = &d->funcs[d->cur_func];
    500   if (f->nrows) {
    501     prev = &f->rows[f->nrows - 1];
    502     if (prev->section_id == text_section_id && prev->offset == text_offset &&
    503         prev->loc.file_id == loc.file_id && prev->loc.line == loc.line &&
    504         prev->loc.col == loc.col) {
    505       return;
    506     }
    507   }
    508   if (VEC_GROW(d->heap, f->rows, f->rows_cap, f->nrows + 1))
    509     debug_oom(d, "rows");
    510   row = &f->rows[f->nrows++];
    511   row->section_id = text_section_id;
    512   row->offset = text_offset;
    513   row->loc = loc;
    514   row->is_stmt = (u8)(is_stmt ? 1 : 0);
    515 }
    516 
    517 /* ---- loclists (Phase 5 placeholder) ---- */
    518 
    519 u32 debug_loclist_new(Debug* d) {
    520   DebugLocList* l;
    521   if (VEC_GROW(d->heap, d->loclists, d->loclists_cap, d->nloclists + 1))
    522     debug_oom(d, "loclists");
    523   l = &d->loclists[d->nloclists];
    524   memset(l, 0, sizeof(*l));
    525   d->nloclists++;
    526   return d->nloclists;
    527 }
    528 
    529 void debug_loclist_add(Debug* d, u32 id, u32 begin_pc, u32 end_pc,
    530                        DebugVarLoc vloc) {
    531   DebugLocList* l;
    532   DebugLocListEntry* e;
    533   if (id == 0 || id > d->nloclists) return;
    534   l = &d->loclists[id - 1];
    535   if (VEC_GROW(d->heap, l->entries, l->cap, l->nentries + 1))
    536     debug_oom(d, "loclist entries");
    537   e = &l->entries[l->nentries++];
    538   e->begin_pc = begin_pc;
    539   e->end_pc = end_pc;
    540   e->loc = vloc;
    541 }