kit

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

dwarf_type.c (16006B)


      1 /* dwarf_type.c — type DIE → KitDwarfType resolution.
      2  *
      3  * Builds KitDwarfType records on demand from DW_TAG_base_type,
      4  * DW_TAG_pointer_type, DW_TAG_array_type, struct/union/enum, typedef,
      5  * and qualifier-types (const/volatile/restrict transparent to inner).
      6  */
      7 
      8 #include <kit/dwarf.h>
      9 #include <stddef.h>
     10 #include <stdint.h>
     11 #include <string.h>
     12 
     13 #include "core/core.h"
     14 #include "core/heap.h"
     15 #include "core/util.h"
     16 #include "debug/dwarf_internal.h"
     17 
     18 static KitDwarfType* type_cache_get(KitDebugInfo* d, u32 die_offset) {
     19   u32 i;
     20   for (i = 0; i < d->ntypes; ++i) {
     21     if (d->types_off[i] == die_offset) return d->types_by_off[i];
     22   }
     23   return NULL;
     24 }
     25 
     26 static void type_cache_put(KitDebugInfo* d, u32 die_offset, KitDwarfType* t) {
     27   if (d->ntypes == d->types_cap) {
     28     u32 ncap = d->types_cap ? d->types_cap * 2 : 16;
     29     KitDwarfType** na = (KitDwarfType**)d->h->realloc(
     30         d->h, d->types_by_off, d->types_cap * sizeof(*d->types_by_off),
     31         ncap * sizeof(*d->types_by_off), _Alignof(KitDwarfType*));
     32     u32* no =
     33         (u32*)d->h->realloc(d->h, d->types_off, d->types_cap * sizeof(u32),
     34                             ncap * sizeof(u32), _Alignof(u32));
     35     if (!na || !no) return;
     36     d->types_by_off = na;
     37     d->types_off = no;
     38     d->types_cap = ncap;
     39   }
     40   d->types_by_off[d->ntypes] = t;
     41   d->types_off[d->ntypes] = die_offset;
     42   d->ntypes++;
     43 }
     44 
     45 static KitDwarfType* type_alloc(KitDebugInfo* d) {
     46   KitDwarfType* t =
     47       (KitDwarfType*)d->h->alloc(d->h, sizeof(*t), _Alignof(KitDwarfType));
     48   if (!t) return NULL;
     49   memset(t, 0, sizeof(*t));
     50   t->name = "";
     51   return t;
     52 }
     53 
     54 KitDwarfType* dw_void_type(KitDebugInfo* d) {
     55   KitDwarfType* t = type_cache_get(d, 0);
     56   if (t) return t;
     57   t = type_alloc(d);
     58   if (!t) return NULL;
     59   t->kind = DTK_VOID;
     60   type_cache_put(d, 0, t);
     61   return t;
     62 }
     63 
     64 /* Walk struct/union children for fields, or enum children for values. */
     65 static void walk_struct_fields(KitDebugInfo* d, DwCu* cu, u32* off,
     66                                KitDwarfType* t) {
     67   DwField* fields = NULL;
     68   u32 nfields = 0, cap = 0;
     69   for (;;) {
     70     DwDie die;
     71     if (!dw_read_die(d, cu, off, &die)) break;
     72     if (die.abbrev->tag == DW_TAG_member) {
     73       DieAttrPack p;
     74       dw_die_pack(d, cu, &die, &p);
     75       /* skip past die's attrs */
     76       {
     77         u32 i;
     78         for (i = 0; i < die.abbrev->nattrs; ++i) {
     79           DwAbbrevAttr* aa = &die.abbrev->attrs[i];
     80           dw_skip_form(d, cu, aa->form, aa->implicit_const, off);
     81         }
     82       }
     83       if (nfields == cap) {
     84         u32 ncap = cap ? cap * 2 : 4;
     85         DwField* na =
     86             (DwField*)d->h->realloc(d->h, fields, cap * sizeof(*fields),
     87                                     ncap * sizeof(*fields), _Alignof(DwField));
     88         if (!na) break;
     89         fields = na;
     90         cap = ncap;
     91       }
     92       fields[nfields].name = p.name ? p.name : "";
     93       fields[nfields].byte_offset = p.has_byte_offset ? p.byte_offset : 0;
     94       fields[nfields].bit_offset = p.has_bit_offset ? p.bit_offset : 0;
     95       fields[nfields].bit_size = p.has_bit_size ? p.bit_size : 0;
     96       fields[nfields].type =
     97           p.has_type
     98               ? dw_type_from_die(d, (u32)(cu - d->cus), p.type_die_offset)
     99               : dw_void_type(d);
    100       nfields++;
    101       if (die.abbrev->has_children) {
    102         for (;;) {
    103           DwDie c;
    104           if (!dw_read_die(d, cu, off, &c)) break;
    105           dw_skip_die_subtree(d, cu, &c, off);
    106         }
    107       }
    108     } else {
    109       dw_skip_die_subtree(d, cu, &die, off);
    110     }
    111   }
    112   t->fields = fields;
    113   t->nfields = nfields;
    114 }
    115 
    116 static void walk_enum_values(KitDebugInfo* d, DwCu* cu, u32* off,
    117                              KitDwarfType* t) {
    118   DwEnumVal* evs = NULL;
    119   u32 nev = 0, cap = 0;
    120   for (;;) {
    121     DwDie die;
    122     if (!dw_read_die(d, cu, off, &die)) break;
    123     if (die.abbrev->tag == DW_TAG_enumerator) {
    124       DieAttrPack p;
    125       dw_die_pack(d, cu, &die, &p);
    126       {
    127         u32 i;
    128         for (i = 0; i < die.abbrev->nattrs; ++i) {
    129           DwAbbrevAttr* aa = &die.abbrev->attrs[i];
    130           dw_skip_form(d, cu, aa->form, aa->implicit_const, off);
    131         }
    132       }
    133       if (nev == cap) {
    134         u32 ncap = cap ? cap * 2 : 4;
    135         DwEnumVal* na =
    136             (DwEnumVal*)d->h->realloc(d->h, evs, cap * sizeof(*evs),
    137                                       ncap * sizeof(*evs), _Alignof(DwEnumVal));
    138         if (!na) break;
    139         evs = na;
    140         cap = ncap;
    141       }
    142       evs[nev].name = p.name ? p.name : "";
    143       evs[nev].value = p.has_const_value ? p.const_value : 0;
    144       nev++;
    145       if (die.abbrev->has_children) {
    146         for (;;) {
    147           DwDie c;
    148           if (!dw_read_die(d, cu, off, &c)) break;
    149           dw_skip_die_subtree(d, cu, &c, off);
    150         }
    151       }
    152     } else {
    153       dw_skip_die_subtree(d, cu, &die, off);
    154     }
    155   }
    156   t->evals = evs;
    157   t->nevals = nev;
    158 }
    159 
    160 /* For DW_TAG_array_type: child DW_TAG_subrange_type carries upper_bound /
    161  * count. */
    162 static void walk_array_subrange(KitDebugInfo* d, DwCu* cu, u32* off,
    163                                 KitDwarfType* t) {
    164   for (;;) {
    165     DwDie die;
    166     if (!dw_read_die(d, cu, off, &die)) break;
    167     if (die.abbrev->tag == DW_TAG_subrange_type) {
    168       DieAttrPack p;
    169       dw_die_pack(d, cu, &die, &p);
    170       {
    171         u32 i;
    172         for (i = 0; i < die.abbrev->nattrs; ++i) {
    173           DwAbbrevAttr* aa = &die.abbrev->attrs[i];
    174           dw_skip_form(d, cu, aa->form, aa->implicit_const, off);
    175         }
    176       }
    177       if (p.has_array_count) t->element_count = p.array_count;
    178       if (die.abbrev->has_children) {
    179         for (;;) {
    180           DwDie c;
    181           if (!dw_read_die(d, cu, off, &c)) break;
    182           dw_skip_die_subtree(d, cu, &c, off);
    183         }
    184       }
    185     } else {
    186       dw_skip_die_subtree(d, cu, &die, off);
    187     }
    188   }
    189 }
    190 
    191 KitDwarfType* dw_type_from_die(KitDebugInfo* d, u32 cu_idx, u32 die_offset) {
    192   DwCu* cu;
    193   DwDie die;
    194   u32 off;
    195   KitDwarfType* t;
    196   DieAttrPack p;
    197   if (die_offset == 0) return dw_void_type(d);
    198   t = type_cache_get(d, die_offset);
    199   if (t) return t;
    200   /* Resolve CU containing the DIE. */
    201   cu = dw_cu_at_die_offset(d, die_offset);
    202   if (!cu) {
    203     if (cu_idx < d->ncus)
    204       cu = &d->cus[cu_idx];
    205     else
    206       return dw_void_type(d);
    207   }
    208   off = die_offset;
    209   if (!dw_read_die(d, cu, &off, &die)) return dw_void_type(d);
    210   if (!die.abbrev) return dw_void_type(d);
    211   dw_die_pack(d, cu, &die, &p);
    212   /* Allocate before recursing — break cycles by interning early. */
    213   t = type_alloc(d);
    214   if (!t) return dw_void_type(d);
    215   t->die_offset = die_offset;
    216   type_cache_put(d, die_offset, t);
    217 
    218   switch (die.abbrev->tag) {
    219     case DW_TAG_base_type:
    220       t->kind = DTK_BASE;
    221       t->name = p.name ? p.name : "";
    222       t->byte_size = p.byte_size;
    223       t->base_encoding = p.base_encoding;
    224       break;
    225     case DW_TAG_pointer_type:
    226     case DW_TAG_reference_type:
    227       t->kind = DTK_PTR;
    228       t->byte_size = p.has_byte_size ? p.byte_size : 8;
    229       t->name = "";
    230       t->inner = p.has_type ? dw_type_from_die(d, (u32)(cu - d->cus),
    231                                                p.type_die_offset)
    232                             : dw_void_type(d);
    233       break;
    234     case DW_TAG_typedef:
    235       t->kind = DTK_TYPEDEF;
    236       t->name = p.name ? p.name : "";
    237       t->inner = p.has_type ? dw_type_from_die(d, (u32)(cu - d->cus),
    238                                                p.type_die_offset)
    239                             : dw_void_type(d);
    240       if (t->inner) t->byte_size = t->inner->byte_size;
    241       break;
    242     case DW_TAG_const_type:
    243     case DW_TAG_volatile_type:
    244     case DW_TAG_restrict_type:
    245       t->kind = (die.abbrev->tag == DW_TAG_const_type)      ? DTK_CONST
    246                 : (die.abbrev->tag == DW_TAG_volatile_type) ? DTK_VOLATILE
    247                                                             : DTK_RESTRICT;
    248       t->inner = p.has_type ? dw_type_from_die(d, (u32)(cu - d->cus),
    249                                                p.type_die_offset)
    250                             : dw_void_type(d);
    251       if (t->inner) {
    252         t->byte_size = t->inner->byte_size;
    253         t->name = t->inner->name;
    254       }
    255       break;
    256     case DW_TAG_array_type:
    257       t->kind = DTK_ARRAY;
    258       t->name = "";
    259       t->inner = p.has_type ? dw_type_from_die(d, (u32)(cu - d->cus),
    260                                                p.type_die_offset)
    261                             : dw_void_type(d);
    262       if (die.abbrev->has_children) {
    263         u32 cur = off;
    264         /* Skip attrs (already read into p). */
    265         u32 ii;
    266         for (ii = 0; ii < die.abbrev->nattrs; ++ii) {
    267           DwAbbrevAttr* aa = &die.abbrev->attrs[ii];
    268           dw_skip_form(d, cu, aa->form, aa->implicit_const, &cur);
    269         }
    270         walk_array_subrange(d, cu, &cur, t);
    271       }
    272       if (t->inner && t->element_count)
    273         t->byte_size = t->inner->byte_size * t->element_count;
    274       break;
    275     case DW_TAG_structure_type:
    276     case DW_TAG_class_type:
    277       t->kind = DTK_STRUCT;
    278       t->name = p.name ? p.name : "";
    279       t->byte_size = p.byte_size;
    280       if (die.abbrev->has_children) {
    281         u32 cur = off;
    282         u32 ii;
    283         for (ii = 0; ii < die.abbrev->nattrs; ++ii) {
    284           DwAbbrevAttr* aa = &die.abbrev->attrs[ii];
    285           dw_skip_form(d, cu, aa->form, aa->implicit_const, &cur);
    286         }
    287         walk_struct_fields(d, cu, &cur, t);
    288       }
    289       break;
    290     case DW_TAG_union_type:
    291       t->kind = DTK_UNION;
    292       t->name = p.name ? p.name : "";
    293       t->byte_size = p.byte_size;
    294       if (die.abbrev->has_children) {
    295         u32 cur = off;
    296         u32 ii;
    297         for (ii = 0; ii < die.abbrev->nattrs; ++ii) {
    298           DwAbbrevAttr* aa = &die.abbrev->attrs[ii];
    299           dw_skip_form(d, cu, aa->form, aa->implicit_const, &cur);
    300         }
    301         walk_struct_fields(d, cu, &cur, t);
    302       }
    303       break;
    304     case DW_TAG_enumeration_type:
    305       t->kind = DTK_ENUM;
    306       t->name = p.name ? p.name : "";
    307       t->byte_size = p.byte_size;
    308       t->inner = p.has_type ? dw_type_from_die(d, (u32)(cu - d->cus),
    309                                                p.type_die_offset)
    310                             : dw_void_type(d);
    311       if (die.abbrev->has_children) {
    312         u32 cur = off;
    313         u32 ii;
    314         for (ii = 0; ii < die.abbrev->nattrs; ++ii) {
    315           DwAbbrevAttr* aa = &die.abbrev->attrs[ii];
    316           dw_skip_form(d, cu, aa->form, aa->implicit_const, &cur);
    317         }
    318         walk_enum_values(d, cu, &cur, t);
    319       }
    320       break;
    321     case DW_TAG_subroutine_type:
    322       t->kind = DTK_FUNC;
    323       t->name = "";
    324       t->inner = p.has_type ? dw_type_from_die(d, (u32)(cu - d->cus),
    325                                                p.type_die_offset)
    326                             : dw_void_type(d);
    327       break;
    328     default:
    329       t->kind = DTK_VOID;
    330       break;
    331   }
    332   return t;
    333 }
    334 
    335 /* ---- public type-info accessors -------------------------------------- */
    336 
    337 static KitDwarfTypeKind map_kind(const KitDwarfType* t) {
    338   if (!t) return KIT_DT_VOID;
    339   switch (t->kind) {
    340     case DTK_VOID:
    341       return KIT_DT_VOID;
    342     case DTK_PTR:
    343       return KIT_DT_PTR;
    344     case DTK_ARRAY:
    345       return KIT_DT_ARRAY;
    346     case DTK_STRUCT:
    347       return KIT_DT_STRUCT;
    348     case DTK_UNION:
    349       return KIT_DT_UNION;
    350     case DTK_ENUM:
    351       return KIT_DT_ENUM;
    352     case DTK_TYPEDEF:
    353       return KIT_DT_TYPEDEF;
    354     case DTK_FUNC:
    355       return KIT_DT_FUNC;
    356     case DTK_CONST:
    357     case DTK_VOLATILE:
    358     case DTK_RESTRICT:
    359       return t->inner ? map_kind(t->inner) : KIT_DT_VOID;
    360     case DTK_BASE:
    361       switch (t->base_encoding) {
    362         case DW_ATE_boolean:
    363           return KIT_DT_BOOL;
    364         case DW_ATE_float:
    365         case DW_ATE_complex_float:
    366           return KIT_DT_FLOAT;
    367         case DW_ATE_signed_char:
    368           return KIT_DT_CHAR;
    369         case DW_ATE_unsigned_char:
    370           return KIT_DT_CHAR;
    371         case DW_ATE_unsigned:
    372         case DW_ATE_address:
    373         case DW_ATE_UTF:
    374           return KIT_DT_UINT;
    375         case DW_ATE_signed:
    376           return KIT_DT_SINT;
    377         default:
    378           return KIT_DT_UINT;
    379       }
    380   }
    381   return KIT_DT_VOID;
    382 }
    383 
    384 KitDwarfTypeInfo kit_dwarf_type_info(const KitDwarfType* t) {
    385   KitDwarfTypeInfo info;
    386   memset(&info, 0, sizeof(info));
    387   info.name = KIT_SLICE_NULL;
    388   if (!t) {
    389     info.kind = KIT_DT_VOID;
    390     return info;
    391   }
    392   info.kind = map_kind(t);
    393   info.byte_size = t->byte_size;
    394   info.name = t->name ? kit_slice_cstr(t->name) : KIT_SLICE_NULL;
    395   info.element_count = t->element_count;
    396   /* For TYPEDEF/PTR/ARRAY: expose inner. For BASE_CHAR map signedness. */
    397   switch (t->kind) {
    398     case DTK_BASE:
    399       if (t->base_encoding == DW_ATE_signed_char)
    400         info.kind = KIT_DT_SINT;
    401       else if (t->base_encoding == DW_ATE_unsigned_char)
    402         info.kind = KIT_DT_UINT;
    403       break;
    404     case DTK_PTR:
    405     case DTK_ARRAY:
    406     case DTK_TYPEDEF:
    407     case DTK_FUNC:
    408       info.inner = t->inner;
    409       break;
    410     case DTK_CONST:
    411     case DTK_VOLATILE:
    412     case DTK_RESTRICT:
    413       /* Transparent: report inner directly. */
    414       if (t->inner) {
    415         return kit_dwarf_type_info(t->inner);
    416       }
    417       break;
    418     default:
    419       break;
    420   }
    421   return info;
    422 }
    423 
    424 /* Field iterator. */
    425 struct KitDwarfFieldIter {
    426   KitDebugInfo* d;
    427   const KitDwarfType* t;
    428   u32 idx;
    429 };
    430 
    431 KitStatus kit_dwarf_field_iter_new(KitDebugInfo* d, const KitDwarfType* t,
    432                                    KitDwarfFieldIter** out) {
    433   KitDwarfFieldIter* it;
    434   if (!out) return KIT_INVALID;
    435   *out = NULL;
    436   if (!d || !t) return KIT_INVALID;
    437   it = (KitDwarfFieldIter*)d->h->alloc(d->h, sizeof(*it),
    438                                        _Alignof(KitDwarfFieldIter));
    439   if (!it) return KIT_NOMEM;
    440   it->d = d;
    441   /* Look through typedef / qualifiers to the underlying aggregate. */
    442   while (t && (t->kind == DTK_TYPEDEF || t->kind == DTK_CONST ||
    443                t->kind == DTK_VOLATILE || t->kind == DTK_RESTRICT))
    444     t = t->inner;
    445   it->t = t;
    446   it->idx = 0;
    447   *out = it;
    448   return KIT_OK;
    449 }
    450 
    451 KitIterResult kit_dwarf_field_iter_next(KitDwarfFieldIter* it,
    452                                         KitDwarfField* out) {
    453   const KitDwarfType* t;
    454   if (!it || !out) return KIT_ITER_ERROR;
    455   if (!it->t) return KIT_ITER_END;
    456   t = it->t;
    457   if (t->kind != DTK_STRUCT && t->kind != DTK_UNION) return KIT_ITER_END;
    458   if (it->idx >= t->nfields) return KIT_ITER_END;
    459   {
    460     DwField* f = &t->fields[it->idx++];
    461     out->name = f->name ? kit_slice_cstr(f->name) : KIT_SLICE_NULL;
    462     out->byte_offset = f->byte_offset;
    463     out->bit_offset = f->bit_offset;
    464     out->bit_size = f->bit_size;
    465     out->type = f->type;
    466   }
    467   return KIT_ITER_ITEM;
    468 }
    469 
    470 void kit_dwarf_field_iter_free(KitDwarfFieldIter* it) {
    471   if (!it) return;
    472   it->d->h->free(it->d->h, it, sizeof(*it));
    473 }
    474 
    475 struct KitDwarfEnumIter {
    476   KitDebugInfo* d;
    477   const KitDwarfType* t;
    478   u32 idx;
    479 };
    480 
    481 KitStatus kit_dwarf_enum_iter_new(KitDebugInfo* d, const KitDwarfType* t,
    482                                   KitDwarfEnumIter** out) {
    483   KitDwarfEnumIter* it;
    484   if (!out) return KIT_INVALID;
    485   *out = NULL;
    486   if (!d || !t) return KIT_INVALID;
    487   it = (KitDwarfEnumIter*)d->h->alloc(d->h, sizeof(*it),
    488                                       _Alignof(KitDwarfEnumIter));
    489   if (!it) return KIT_NOMEM;
    490   it->d = d;
    491   while (t && (t->kind == DTK_TYPEDEF || t->kind == DTK_CONST ||
    492                t->kind == DTK_VOLATILE || t->kind == DTK_RESTRICT))
    493     t = t->inner;
    494   it->t = t;
    495   it->idx = 0;
    496   *out = it;
    497   return KIT_OK;
    498 }
    499 
    500 KitIterResult kit_dwarf_enum_iter_next(KitDwarfEnumIter* it,
    501                                        KitDwarfEnumVal* out) {
    502   const KitDwarfType* t;
    503   if (!it || !out) return KIT_ITER_ERROR;
    504   if (!it->t) return KIT_ITER_END;
    505   t = it->t;
    506   if (t->kind != DTK_ENUM) return KIT_ITER_END;
    507   if (it->idx >= t->nevals) return KIT_ITER_END;
    508   out->name = t->evals[it->idx].name ? kit_slice_cstr(t->evals[it->idx].name)
    509                                      : KIT_SLICE_NULL;
    510   out->value = t->evals[it->idx].value;
    511   it->idx++;
    512   return KIT_ITER_ITEM;
    513 }
    514 
    515 void kit_dwarf_enum_iter_free(KitDwarfEnumIter* it) {
    516   if (!it) return;
    517   it->d->h->free(it->d->h, it, sizeof(*it));
    518 }