kit

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

dwarf_type.c (14764B)


      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, off); /* decodes attrs and advances off */
     75       if (nfields == cap) {
     76         u32 ncap = cap ? cap * 2 : 4;
     77         DwField* na =
     78             (DwField*)d->h->realloc(d->h, fields, cap * sizeof(*fields),
     79                                     ncap * sizeof(*fields), _Alignof(DwField));
     80         if (!na) break;
     81         fields = na;
     82         cap = ncap;
     83       }
     84       fields[nfields].name = p.name ? p.name : "";
     85       fields[nfields].byte_offset = p.has_byte_offset ? p.byte_offset : 0;
     86       fields[nfields].bit_offset = p.has_bit_offset ? p.bit_offset : 0;
     87       fields[nfields].bit_size = p.has_bit_size ? p.bit_size : 0;
     88       fields[nfields].type =
     89           p.has_type
     90               ? dw_type_from_die(d, (u32)(cu - d->cus), p.type_die_offset)
     91               : dw_void_type(d);
     92       nfields++;
     93       if (die.abbrev->has_children) {
     94         for (;;) {
     95           DwDie c;
     96           if (!dw_read_die(d, cu, off, &c)) break;
     97           dw_skip_die_subtree(d, cu, &c, off);
     98         }
     99       }
    100     } else {
    101       dw_skip_die_subtree(d, cu, &die, off);
    102     }
    103   }
    104   t->fields = fields;
    105   t->nfields = nfields;
    106 }
    107 
    108 static void walk_enum_values(KitDebugInfo* d, DwCu* cu, u32* off,
    109                              KitDwarfType* t) {
    110   DwEnumVal* evs = NULL;
    111   u32 nev = 0, cap = 0;
    112   for (;;) {
    113     DwDie die;
    114     if (!dw_read_die(d, cu, off, &die)) break;
    115     if (die.abbrev->tag == DW_TAG_enumerator) {
    116       DieAttrPack p;
    117       dw_die_pack(d, cu, &die, &p, off); /* decodes attrs and advances off */
    118       if (nev == cap) {
    119         u32 ncap = cap ? cap * 2 : 4;
    120         DwEnumVal* na =
    121             (DwEnumVal*)d->h->realloc(d->h, evs, cap * sizeof(*evs),
    122                                       ncap * sizeof(*evs), _Alignof(DwEnumVal));
    123         if (!na) break;
    124         evs = na;
    125         cap = ncap;
    126       }
    127       evs[nev].name = p.name ? p.name : "";
    128       evs[nev].value = p.has_const_value ? p.const_value : 0;
    129       nev++;
    130       if (die.abbrev->has_children) {
    131         for (;;) {
    132           DwDie c;
    133           if (!dw_read_die(d, cu, off, &c)) break;
    134           dw_skip_die_subtree(d, cu, &c, off);
    135         }
    136       }
    137     } else {
    138       dw_skip_die_subtree(d, cu, &die, off);
    139     }
    140   }
    141   t->evals = evs;
    142   t->nevals = nev;
    143 }
    144 
    145 /* For DW_TAG_array_type: child DW_TAG_subrange_type carries upper_bound /
    146  * count. */
    147 static void walk_array_subrange(KitDebugInfo* d, DwCu* cu, u32* off,
    148                                 KitDwarfType* t) {
    149   for (;;) {
    150     DwDie die;
    151     if (!dw_read_die(d, cu, off, &die)) break;
    152     if (die.abbrev->tag == DW_TAG_subrange_type) {
    153       DieAttrPack p;
    154       dw_die_pack(d, cu, &die, &p, off); /* decodes attrs and advances off */
    155       if (p.has_array_count) t->element_count = p.array_count;
    156       if (die.abbrev->has_children) {
    157         for (;;) {
    158           DwDie c;
    159           if (!dw_read_die(d, cu, off, &c)) break;
    160           dw_skip_die_subtree(d, cu, &c, off);
    161         }
    162       }
    163     } else {
    164       dw_skip_die_subtree(d, cu, &die, off);
    165     }
    166   }
    167 }
    168 
    169 KitDwarfType* dw_type_from_die(KitDebugInfo* d, u32 cu_idx, u32 die_offset) {
    170   DwCu* cu;
    171   DwDie die;
    172   u32 off;
    173   KitDwarfType* t;
    174   DieAttrPack p;
    175   if (die_offset == 0) return dw_void_type(d);
    176   t = type_cache_get(d, die_offset);
    177   if (t) return t;
    178   /* Resolve CU containing the DIE. */
    179   cu = dw_cu_at_die_offset(d, die_offset);
    180   if (!cu) {
    181     if (cu_idx < d->ncus)
    182       cu = &d->cus[cu_idx];
    183     else
    184       return dw_void_type(d);
    185   }
    186   off = die_offset;
    187   if (!dw_read_die(d, cu, &off, &die)) return dw_void_type(d);
    188   if (!die.abbrev) return dw_void_type(d);
    189   /* Decode attrs and advance `off` to the first child DIE. */
    190   dw_die_pack(d, cu, &die, &p, &off);
    191   /* Allocate before recursing — break cycles by interning early. */
    192   t = type_alloc(d);
    193   if (!t) return dw_void_type(d);
    194   t->die_offset = die_offset;
    195   type_cache_put(d, die_offset, t);
    196 
    197   switch (die.abbrev->tag) {
    198     case DW_TAG_base_type:
    199       t->kind = DTK_BASE;
    200       t->name = p.name ? p.name : "";
    201       t->byte_size = p.byte_size;
    202       t->base_encoding = p.base_encoding;
    203       break;
    204     case DW_TAG_pointer_type:
    205     case DW_TAG_reference_type:
    206       t->kind = DTK_PTR;
    207       t->byte_size = p.has_byte_size ? p.byte_size : 8;
    208       t->name = "";
    209       t->inner = p.has_type ? dw_type_from_die(d, (u32)(cu - d->cus),
    210                                                p.type_die_offset)
    211                             : dw_void_type(d);
    212       break;
    213     case DW_TAG_typedef:
    214       t->kind = DTK_TYPEDEF;
    215       t->name = p.name ? p.name : "";
    216       t->inner = p.has_type ? dw_type_from_die(d, (u32)(cu - d->cus),
    217                                                p.type_die_offset)
    218                             : dw_void_type(d);
    219       if (t->inner) t->byte_size = t->inner->byte_size;
    220       break;
    221     case DW_TAG_const_type:
    222     case DW_TAG_volatile_type:
    223     case DW_TAG_restrict_type:
    224       t->kind = (die.abbrev->tag == DW_TAG_const_type)      ? DTK_CONST
    225                 : (die.abbrev->tag == DW_TAG_volatile_type) ? DTK_VOLATILE
    226                                                             : DTK_RESTRICT;
    227       t->inner = p.has_type ? dw_type_from_die(d, (u32)(cu - d->cus),
    228                                                p.type_die_offset)
    229                             : dw_void_type(d);
    230       if (t->inner) {
    231         t->byte_size = t->inner->byte_size;
    232         t->name = t->inner->name;
    233       }
    234       break;
    235     case DW_TAG_array_type:
    236       t->kind = DTK_ARRAY;
    237       t->name = "";
    238       t->inner = p.has_type ? dw_type_from_die(d, (u32)(cu - d->cus),
    239                                                p.type_die_offset)
    240                             : dw_void_type(d);
    241       if (die.abbrev->has_children) {
    242         /* `off` already sits at the first child (attrs decoded above). */
    243         u32 cur = off;
    244         walk_array_subrange(d, cu, &cur, t);
    245       }
    246       if (t->inner && t->element_count)
    247         t->byte_size = t->inner->byte_size * t->element_count;
    248       break;
    249     case DW_TAG_structure_type:
    250     case DW_TAG_class_type:
    251       t->kind = DTK_STRUCT;
    252       t->name = p.name ? p.name : "";
    253       t->byte_size = p.byte_size;
    254       if (die.abbrev->has_children) {
    255         u32 cur = off;
    256         walk_struct_fields(d, cu, &cur, t);
    257       }
    258       break;
    259     case DW_TAG_union_type:
    260       t->kind = DTK_UNION;
    261       t->name = p.name ? p.name : "";
    262       t->byte_size = p.byte_size;
    263       if (die.abbrev->has_children) {
    264         u32 cur = off;
    265         walk_struct_fields(d, cu, &cur, t);
    266       }
    267       break;
    268     case DW_TAG_enumeration_type:
    269       t->kind = DTK_ENUM;
    270       t->name = p.name ? p.name : "";
    271       t->byte_size = p.byte_size;
    272       t->inner = p.has_type ? dw_type_from_die(d, (u32)(cu - d->cus),
    273                                                p.type_die_offset)
    274                             : dw_void_type(d);
    275       if (die.abbrev->has_children) {
    276         u32 cur = off;
    277         walk_enum_values(d, cu, &cur, t);
    278       }
    279       break;
    280     case DW_TAG_subroutine_type:
    281       t->kind = DTK_FUNC;
    282       t->name = "";
    283       t->inner = p.has_type ? dw_type_from_die(d, (u32)(cu - d->cus),
    284                                                p.type_die_offset)
    285                             : dw_void_type(d);
    286       break;
    287     default:
    288       t->kind = DTK_VOID;
    289       break;
    290   }
    291   return t;
    292 }
    293 
    294 /* ---- public type-info accessors -------------------------------------- */
    295 
    296 static KitDwarfTypeKind map_kind(const KitDwarfType* t) {
    297   if (!t) return KIT_DT_VOID;
    298   switch (t->kind) {
    299     case DTK_VOID:
    300       return KIT_DT_VOID;
    301     case DTK_PTR:
    302       return KIT_DT_PTR;
    303     case DTK_ARRAY:
    304       return KIT_DT_ARRAY;
    305     case DTK_STRUCT:
    306       return KIT_DT_STRUCT;
    307     case DTK_UNION:
    308       return KIT_DT_UNION;
    309     case DTK_ENUM:
    310       return KIT_DT_ENUM;
    311     case DTK_TYPEDEF:
    312       return KIT_DT_TYPEDEF;
    313     case DTK_FUNC:
    314       return KIT_DT_FUNC;
    315     case DTK_CONST:
    316     case DTK_VOLATILE:
    317     case DTK_RESTRICT:
    318       return t->inner ? map_kind(t->inner) : KIT_DT_VOID;
    319     case DTK_BASE:
    320       switch (t->base_encoding) {
    321         case DW_ATE_boolean:
    322           return KIT_DT_BOOL;
    323         case DW_ATE_float:
    324         case DW_ATE_complex_float:
    325           return KIT_DT_FLOAT;
    326         case DW_ATE_signed_char:
    327           return KIT_DT_CHAR;
    328         case DW_ATE_unsigned_char:
    329           return KIT_DT_CHAR;
    330         case DW_ATE_unsigned:
    331         case DW_ATE_address:
    332         case DW_ATE_UTF:
    333           return KIT_DT_UINT;
    334         case DW_ATE_signed:
    335           return KIT_DT_SINT;
    336         default:
    337           return KIT_DT_UINT;
    338       }
    339   }
    340   return KIT_DT_VOID;
    341 }
    342 
    343 KitDwarfTypeInfo kit_dwarf_type_info(const KitDwarfType* t) {
    344   KitDwarfTypeInfo info;
    345   memset(&info, 0, sizeof(info));
    346   info.name = KIT_SLICE_NULL;
    347   if (!t) {
    348     info.kind = KIT_DT_VOID;
    349     return info;
    350   }
    351   info.kind = map_kind(t);
    352   info.byte_size = t->byte_size;
    353   info.name = t->name ? kit_slice_cstr(t->name) : KIT_SLICE_NULL;
    354   info.element_count = t->element_count;
    355   /* For TYPEDEF/PTR/ARRAY: expose inner. For BASE_CHAR map signedness. */
    356   switch (t->kind) {
    357     case DTK_BASE:
    358       if (t->base_encoding == DW_ATE_signed_char)
    359         info.kind = KIT_DT_SINT;
    360       else if (t->base_encoding == DW_ATE_unsigned_char)
    361         info.kind = KIT_DT_UINT;
    362       break;
    363     case DTK_PTR:
    364     case DTK_ARRAY:
    365     case DTK_TYPEDEF:
    366     case DTK_FUNC:
    367       info.inner = t->inner;
    368       break;
    369     case DTK_CONST:
    370     case DTK_VOLATILE:
    371     case DTK_RESTRICT:
    372       /* Transparent: report inner directly. */
    373       if (t->inner) {
    374         return kit_dwarf_type_info(t->inner);
    375       }
    376       break;
    377     default:
    378       break;
    379   }
    380   return info;
    381 }
    382 
    383 /* Field iterator. */
    384 struct KitDwarfFieldIter {
    385   KitDebugInfo* d;
    386   const KitDwarfType* t;
    387   u32 idx;
    388 };
    389 
    390 KitStatus kit_dwarf_field_iter_new(KitDebugInfo* d, const KitDwarfType* t,
    391                                    KitDwarfFieldIter** out) {
    392   KitDwarfFieldIter* it;
    393   if (!out) return KIT_INVALID;
    394   *out = NULL;
    395   if (!d || !t) return KIT_INVALID;
    396   it = (KitDwarfFieldIter*)d->h->alloc(d->h, sizeof(*it),
    397                                        _Alignof(KitDwarfFieldIter));
    398   if (!it) return KIT_NOMEM;
    399   it->d = d;
    400   /* Look through typedef / qualifiers to the underlying aggregate. */
    401   while (t && (t->kind == DTK_TYPEDEF || t->kind == DTK_CONST ||
    402                t->kind == DTK_VOLATILE || t->kind == DTK_RESTRICT))
    403     t = t->inner;
    404   it->t = t;
    405   it->idx = 0;
    406   *out = it;
    407   return KIT_OK;
    408 }
    409 
    410 KitIterResult kit_dwarf_field_iter_next(KitDwarfFieldIter* it,
    411                                         KitDwarfField* out) {
    412   const KitDwarfType* t;
    413   if (!it || !out) return KIT_ITER_ERROR;
    414   if (!it->t) return KIT_ITER_END;
    415   t = it->t;
    416   if (t->kind != DTK_STRUCT && t->kind != DTK_UNION) return KIT_ITER_END;
    417   if (it->idx >= t->nfields) return KIT_ITER_END;
    418   {
    419     DwField* f = &t->fields[it->idx++];
    420     out->name = f->name ? kit_slice_cstr(f->name) : KIT_SLICE_NULL;
    421     out->byte_offset = f->byte_offset;
    422     out->bit_offset = f->bit_offset;
    423     out->bit_size = f->bit_size;
    424     out->type = f->type;
    425   }
    426   return KIT_ITER_ITEM;
    427 }
    428 
    429 void kit_dwarf_field_iter_free(KitDwarfFieldIter* it) {
    430   if (!it) return;
    431   it->d->h->free(it->d->h, it, sizeof(*it));
    432 }
    433 
    434 struct KitDwarfEnumIter {
    435   KitDebugInfo* d;
    436   const KitDwarfType* t;
    437   u32 idx;
    438 };
    439 
    440 KitStatus kit_dwarf_enum_iter_new(KitDebugInfo* d, const KitDwarfType* t,
    441                                   KitDwarfEnumIter** out) {
    442   KitDwarfEnumIter* it;
    443   if (!out) return KIT_INVALID;
    444   *out = NULL;
    445   if (!d || !t) return KIT_INVALID;
    446   it = (KitDwarfEnumIter*)d->h->alloc(d->h, sizeof(*it),
    447                                       _Alignof(KitDwarfEnumIter));
    448   if (!it) return KIT_NOMEM;
    449   it->d = d;
    450   while (t && (t->kind == DTK_TYPEDEF || t->kind == DTK_CONST ||
    451                t->kind == DTK_VOLATILE || t->kind == DTK_RESTRICT))
    452     t = t->inner;
    453   it->t = t;
    454   it->idx = 0;
    455   *out = it;
    456   return KIT_OK;
    457 }
    458 
    459 KitIterResult kit_dwarf_enum_iter_next(KitDwarfEnumIter* it,
    460                                        KitDwarfEnumVal* out) {
    461   const KitDwarfType* t;
    462   if (!it || !out) return KIT_ITER_ERROR;
    463   if (!it->t) return KIT_ITER_END;
    464   t = it->t;
    465   if (t->kind != DTK_ENUM) return KIT_ITER_END;
    466   if (it->idx >= t->nevals) return KIT_ITER_END;
    467   out->name = t->evals[it->idx].name ? kit_slice_cstr(t->evals[it->idx].name)
    468                                      : KIT_SLICE_NULL;
    469   out->value = t->evals[it->idx].value;
    470   it->idx++;
    471   return KIT_ITER_ITEM;
    472 }
    473 
    474 void kit_dwarf_enum_iter_free(KitDwarfEnumIter* it) {
    475   if (!it) return;
    476   it->d->h->free(it->d->h, it, sizeof(*it));
    477 }