kit

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

debug.c (15788B)


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