kit

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

dwarf_dump.c (13361B)


      1 /* dwarf_dump.c — structural enumeration of DWARF sections.
      2  *
      3  * Implements the kit_dwarf_*_iter API used by `objdump --dwarf` and
      4  * similar dumpers. Unlike the PC/name-keyed query API, these walk the raw
      5  * .debug_info / .debug_abbrev / .debug_line / .debug_str structure and
      6  * hand back numeric DWARF codes; symbolic rendering is the caller's job.
      7  *
      8  * The iterators are thin cursors over the consumer state already built by
      9  * dwarf_open.c (CUs, abbrev tables) and dwarf_line.c (decoded line rows).
     10  */
     11 
     12 #include <kit/dwarf.h>
     13 #include <stddef.h>
     14 #include <stdint.h>
     15 
     16 #include "core/core.h"
     17 #include "core/heap.h"
     18 #include "debug/dwarf_defs.h"
     19 #include "debug/dwarf_internal.h"
     20 
     21 /* ---- shared helpers --------------------------------------------------- */
     22 
     23 #define DW_ITER_ALLOC(d, T) ((T*)(d)->h->alloc((d)->h, sizeof(T), _Alignof(T)))
     24 
     25 static void dw_iter_free(KitDebugInfo* d, void* p, size_t n) {
     26   if (p) d->h->free(d->h, p, n);
     27 }
     28 
     29 /* Find the CU index whose header sits at `cu_offset`, or UINT32_MAX. */
     30 static u32 dw_cu_index_at(KitDebugInfo* d, u32 cu_offset) {
     31   u32 i;
     32   for (i = 0; i < d->ncus; ++i) {
     33     if (d->cus[i].hdr_offset == cu_offset) return i;
     34   }
     35   return UINT32_MAX;
     36 }
     37 
     38 /* ---- CU iterator ------------------------------------------------------ */
     39 
     40 struct KitDwarfCuIter {
     41   KitDebugInfo* d;
     42   u32 idx;
     43 };
     44 
     45 KitStatus kit_dwarf_cu_iter_new(KitDebugInfo* d, KitDwarfCuIter** out) {
     46   KitDwarfCuIter* it;
     47   if (!out) return KIT_INVALID;
     48   *out = NULL;
     49   if (!d) return KIT_INVALID;
     50   dw_parse_all_cus(d);
     51   it = DW_ITER_ALLOC(d, KitDwarfCuIter);
     52   if (!it) return KIT_NOMEM;
     53   it->d = d;
     54   it->idx = 0;
     55   *out = it;
     56   return KIT_OK;
     57 }
     58 
     59 KitIterResult kit_dwarf_cu_iter_next(KitDwarfCuIter* it, KitDwarfCu* out) {
     60   DwCu* cu;
     61   if (!it || !out) return KIT_ITER_ERROR;
     62   if (it->idx >= it->d->ncus) return KIT_ITER_END;
     63   cu = &it->d->cus[it->idx++];
     64   out->offset = cu->hdr_offset;
     65   out->length = cu->hdr_length;
     66   out->version = cu->version;
     67   out->address_size = cu->address_size;
     68   out->unit_type = cu->unit_type;
     69   out->abbrev_offset = cu->abbrev_offset;
     70   out->is_64bit = cu->is_64bit != 0;
     71   return KIT_ITER_ITEM;
     72 }
     73 
     74 void kit_dwarf_cu_iter_free(KitDwarfCuIter* it) {
     75   if (it) dw_iter_free(it->d, it, sizeof(*it));
     76 }
     77 
     78 /* ---- DIE iterator (depth-first across all CUs) ------------------------ */
     79 
     80 struct KitDwarfDieIter {
     81   KitDebugInfo* d;
     82   u32 cu_idx; /* current CU */
     83   u32 off;    /* cursor into .debug_info */
     84   u32 depth;  /* current nesting level */
     85 };
     86 
     87 KitStatus kit_dwarf_die_iter_new(KitDebugInfo* d, KitDwarfDieIter** out) {
     88   KitDwarfDieIter* it;
     89   if (!out) return KIT_INVALID;
     90   *out = NULL;
     91   if (!d) return KIT_INVALID;
     92   dw_parse_all_cus(d);
     93   it = DW_ITER_ALLOC(d, KitDwarfDieIter);
     94   if (!it) return KIT_NOMEM;
     95   it->d = d;
     96   it->cu_idx = 0;
     97   it->depth = 0;
     98   it->off = d->ncus ? d->cus[0].die_start_off : 0;
     99   *out = it;
    100   return KIT_OK;
    101 }
    102 
    103 KitIterResult kit_dwarf_die_iter_next(KitDwarfDieIter* it, KitDwarfDie* out) {
    104   KitDebugInfo* d;
    105   if (!it || !out) return KIT_ITER_ERROR;
    106   d = it->d;
    107   for (;;) {
    108     DwCu* cu;
    109     DwDie die;
    110     if (it->cu_idx >= d->ncus) return KIT_ITER_END;
    111     cu = &d->cus[it->cu_idx];
    112     if (!dw_read_die(d, cu, &it->off, &die)) {
    113       /* Null entry or end-of-CU: close one level, or advance to the next
    114        * CU when we have unwound back past the root. */
    115       if (it->depth > 0) {
    116         it->depth--;
    117         continue;
    118       }
    119       it->cu_idx++;
    120       it->depth = 0;
    121       if (it->cu_idx < d->ncus) it->off = d->cus[it->cu_idx].die_start_off;
    122       continue;
    123     }
    124     out->offset = die.die_off;
    125     out->cu_offset = cu->hdr_offset;
    126     out->tag = die.abbrev ? die.abbrev->tag : 0;
    127     out->depth = it->depth;
    128     out->has_children = die.abbrev && die.abbrev->has_children;
    129     dw_skip_die_attrs(d, cu, &die, &it->off);
    130     if (die.abbrev && die.abbrev->has_children) it->depth++;
    131     return KIT_ITER_ITEM;
    132   }
    133 }
    134 
    135 void kit_dwarf_die_iter_free(KitDwarfDieIter* it) {
    136   if (it) dw_iter_free(it->d, it, sizeof(*it));
    137 }
    138 
    139 /* ---- DIE attribute iterator ------------------------------------------- */
    140 
    141 struct KitDwarfAttrIter {
    142   KitDebugInfo* d;
    143   const DwCu* cu;
    144   DwAbbrev* abbrev;
    145   u32 attr_idx; /* index into abbrev->attrs */
    146   u32 off;      /* running cursor in .debug_info */
    147 };
    148 
    149 static KitDwarfFormClass dw_form_class(u32 form) {
    150   switch (form) {
    151     case DW_FORM_string:
    152     case DW_FORM_strp:
    153     case DW_FORM_line_strp:
    154     case DW_FORM_strx:
    155     case DW_FORM_strx1:
    156     case DW_FORM_strx2:
    157     case DW_FORM_strx3:
    158     case DW_FORM_strx4:
    159       return KIT_DWARF_FC_STRING;
    160     case DW_FORM_addr:
    161     case DW_FORM_addrx:
    162     case DW_FORM_addrx1:
    163     case DW_FORM_addrx2:
    164     case DW_FORM_addrx3:
    165     case DW_FORM_addrx4:
    166       return KIT_DWARF_FC_ADDR;
    167     case DW_FORM_ref1:
    168     case DW_FORM_ref2:
    169     case DW_FORM_ref4:
    170     case DW_FORM_ref8:
    171     case DW_FORM_ref_udata:
    172     case DW_FORM_ref_addr:
    173     case DW_FORM_ref_sig8:
    174     case DW_FORM_ref_sup4:
    175     case DW_FORM_ref_sup8:
    176       return KIT_DWARF_FC_REF;
    177     case DW_FORM_sdata:
    178       return KIT_DWARF_FC_SDATA;
    179     case DW_FORM_flag:
    180     case DW_FORM_flag_present:
    181       return KIT_DWARF_FC_FLAG;
    182     case DW_FORM_block:
    183     case DW_FORM_block1:
    184     case DW_FORM_block2:
    185     case DW_FORM_block4:
    186     case DW_FORM_exprloc:
    187     case DW_FORM_data16:
    188       return KIT_DWARF_FC_BLOCK;
    189     case DW_FORM_data1:
    190     case DW_FORM_data2:
    191     case DW_FORM_data4:
    192     case DW_FORM_data8:
    193     case DW_FORM_udata:
    194     case DW_FORM_sec_offset:
    195     case DW_FORM_loclistx:
    196     case DW_FORM_rnglistx:
    197     case DW_FORM_implicit_const:
    198       return KIT_DWARF_FC_UDATA;
    199     default:
    200       return KIT_DWARF_FC_UNKNOWN;
    201   }
    202 }
    203 
    204 KitStatus kit_dwarf_attr_iter_new(KitDebugInfo* d, uint32_t die_offset,
    205                                   KitDwarfAttrIter** out) {
    206   KitDwarfAttrIter* it;
    207   DwCu* cu;
    208   DwDie die;
    209   u32 off;
    210   if (!out) return KIT_INVALID;
    211   *out = NULL;
    212   if (!d) return KIT_INVALID;
    213   dw_parse_all_cus(d);
    214   cu = dw_cu_at_die_offset(d, die_offset);
    215   if (!cu) return KIT_NOT_FOUND;
    216   off = die_offset;
    217   if (!dw_read_die(d, cu, &off, &die) || !die.abbrev) return KIT_NOT_FOUND;
    218   it = DW_ITER_ALLOC(d, KitDwarfAttrIter);
    219   if (!it) return KIT_NOMEM;
    220   it->d = d;
    221   it->cu = cu;
    222   it->abbrev = die.abbrev;
    223   it->attr_idx = 0;
    224   it->off = die.attrs_off;
    225   *out = it;
    226   return KIT_OK;
    227 }
    228 
    229 KitIterResult kit_dwarf_attr_iter_next(KitDwarfAttrIter* it,
    230                                        KitDwarfAttr* out) {
    231   DwAbbrevAttr* spec;
    232   DwAttrValue v;
    233   if (!it || !out) return KIT_ITER_ERROR;
    234   if (it->attr_idx >= it->abbrev->nattrs) return KIT_ITER_END;
    235   spec = &it->abbrev->attrs[it->attr_idx++];
    236   dw_read_form(it->d, it->cu, spec->form, spec->implicit_const, &it->off, &v);
    237   out->attr = spec->attr;
    238   out->form = spec->form;
    239   out->form_class = dw_form_class(spec->form);
    240   out->u = v.u;
    241   out->s = v.s;
    242   out->str = v.str ? kit_slice_cstr(v.str) : KIT_SLICE_NULL;
    243   out->block = v.block;
    244   out->block_len = v.block_len;
    245   return KIT_ITER_ITEM;
    246 }
    247 
    248 void kit_dwarf_attr_iter_free(KitDwarfAttrIter* it) {
    249   if (it) dw_iter_free(it->d, it, sizeof(*it));
    250 }
    251 
    252 /* ---- abbrev iterators ------------------------------------------------- */
    253 
    254 struct KitDwarfAbbrevIter {
    255   KitDebugInfo* d;
    256   u32 tbl;  /* index into d->abbrevs */
    257   u32 slot; /* index into table->abbrevs */
    258 };
    259 
    260 /* Ensure every CU's abbrev table is materialized before walking them. */
    261 static void dw_ensure_abbrevs(KitDebugInfo* d) {
    262   u32 i;
    263   dw_parse_all_cus(d);
    264   for (i = 0; i < d->ncus; ++i) dw_abbrev_get(d, d->cus[i].abbrev_offset);
    265 }
    266 
    267 KitStatus kit_dwarf_abbrev_iter_new(KitDebugInfo* d, KitDwarfAbbrevIter** out) {
    268   KitDwarfAbbrevIter* it;
    269   if (!out) return KIT_INVALID;
    270   *out = NULL;
    271   if (!d) return KIT_INVALID;
    272   dw_ensure_abbrevs(d);
    273   it = DW_ITER_ALLOC(d, KitDwarfAbbrevIter);
    274   if (!it) return KIT_NOMEM;
    275   it->d = d;
    276   it->tbl = 0;
    277   it->slot = 0;
    278   *out = it;
    279   return KIT_OK;
    280 }
    281 
    282 KitIterResult kit_dwarf_abbrev_iter_next(KitDwarfAbbrevIter* it,
    283                                          KitDwarfAbbrev* out) {
    284   KitDebugInfo* d;
    285   if (!it || !out) return KIT_ITER_ERROR;
    286   d = it->d;
    287   while (it->tbl < d->nabbrevs) {
    288     DwAbbrevTable* t = &d->abbrevs[it->tbl];
    289     if (it->slot >= t->nabbrevs) {
    290       it->tbl++;
    291       it->slot = 0;
    292       continue;
    293     }
    294     {
    295       DwAbbrev* a = &t->abbrevs[it->slot++];
    296       if (a->code == 0) continue; /* unused slot */
    297       out->table_offset = t->cu_abbrev_offset;
    298       out->code = a->code;
    299       out->tag = a->tag;
    300       out->has_children = a->has_children != 0;
    301       return KIT_ITER_ITEM;
    302     }
    303   }
    304   return KIT_ITER_END;
    305 }
    306 
    307 void kit_dwarf_abbrev_iter_free(KitDwarfAbbrevIter* it) {
    308   if (it) dw_iter_free(it->d, it, sizeof(*it));
    309 }
    310 
    311 struct KitDwarfAbbrevAttrIter {
    312   KitDebugInfo* d;
    313   DwAbbrev* abbrev;
    314   u32 idx;
    315 };
    316 
    317 KitStatus kit_dwarf_abbrev_attr_iter_new(KitDebugInfo* d, uint32_t table_offset,
    318                                          uint64_t code,
    319                                          KitDwarfAbbrevAttrIter** out) {
    320   KitDwarfAbbrevAttrIter* it;
    321   DwAbbrevTable* t;
    322   DwAbbrev* a;
    323   if (!out) return KIT_INVALID;
    324   *out = NULL;
    325   if (!d) return KIT_INVALID;
    326   dw_ensure_abbrevs(d);
    327   t = dw_abbrev_get(d, table_offset);
    328   if (!t) return KIT_NOT_FOUND;
    329   a = dw_abbrev_lookup(t, code);
    330   if (!a) return KIT_NOT_FOUND;
    331   it = DW_ITER_ALLOC(d, KitDwarfAbbrevAttrIter);
    332   if (!it) return KIT_NOMEM;
    333   it->d = d;
    334   it->abbrev = a;
    335   it->idx = 0;
    336   *out = it;
    337   return KIT_OK;
    338 }
    339 
    340 KitIterResult kit_dwarf_abbrev_attr_iter_next(KitDwarfAbbrevAttrIter* it,
    341                                               KitDwarfAbbrevAttr* out) {
    342   DwAbbrevAttr* aa;
    343   if (!it || !out) return KIT_ITER_ERROR;
    344   if (it->idx >= it->abbrev->nattrs) return KIT_ITER_END;
    345   aa = &it->abbrev->attrs[it->idx++];
    346   out->attr = aa->attr;
    347   out->form = aa->form;
    348   out->implicit_const = aa->implicit_const;
    349   return KIT_ITER_ITEM;
    350 }
    351 
    352 void kit_dwarf_abbrev_attr_iter_free(KitDwarfAbbrevAttrIter* it) {
    353   if (it) dw_iter_free(it->d, it, sizeof(*it));
    354 }
    355 
    356 /* ---- line row iterator ------------------------------------------------ */
    357 
    358 struct KitDwarfLineIter {
    359   KitDebugInfo* d;
    360   u32 cu_idx;
    361   u32 row;
    362 };
    363 
    364 KitStatus kit_dwarf_line_iter_new(KitDebugInfo* d, uint32_t cu_offset,
    365                                   KitDwarfLineIter** out) {
    366   KitDwarfLineIter* it;
    367   u32 cu_idx;
    368   if (!out) return KIT_INVALID;
    369   *out = NULL;
    370   if (!d) return KIT_INVALID;
    371   dw_parse_all_cus(d);
    372   cu_idx = dw_cu_index_at(d, cu_offset);
    373   if (cu_idx == UINT32_MAX) return KIT_NOT_FOUND;
    374   if (!d->cus[cu_idx].has_stmt_list) return KIT_NOT_FOUND;
    375   if (!d->lines_built[cu_idx]) dw_build_line(d, cu_idx);
    376   it = DW_ITER_ALLOC(d, KitDwarfLineIter);
    377   if (!it) return KIT_NOMEM;
    378   it->d = d;
    379   it->cu_idx = cu_idx;
    380   it->row = 0;
    381   *out = it;
    382   return KIT_OK;
    383 }
    384 
    385 KitIterResult kit_dwarf_line_iter_next(KitDwarfLineIter* it,
    386                                        KitDwarfLineRow* out) {
    387   DwLineProgram* lp;
    388   DwLineRow* r;
    389   if (!it || !out) return KIT_ITER_ERROR;
    390   lp = &it->d->lines_by_cu[it->cu_idx];
    391   if (it->row >= lp->nrows) return KIT_ITER_END;
    392   r = &lp->rows[it->row++];
    393   out->address = r->address;
    394   out->file_index = r->file_index;
    395   out->line = r->line;
    396   out->column = r->column;
    397   out->is_stmt = r->is_stmt != 0;
    398   out->end_sequence = r->end_sequence != 0;
    399   return KIT_ITER_ITEM;
    400 }
    401 
    402 void kit_dwarf_line_iter_free(KitDwarfLineIter* it) {
    403   if (it) dw_iter_free(it->d, it, sizeof(*it));
    404 }
    405 
    406 KitStatus kit_dwarf_line_file(KitDebugInfo* d, uint32_t cu_offset,
    407                               uint32_t file_index, KitSlice* out) {
    408   u32 cu_idx;
    409   DwLineProgram* lp;
    410   const char* path = NULL;
    411   if (!out) return KIT_INVALID;
    412   *out = KIT_SLICE_NULL;
    413   if (!d) return KIT_INVALID;
    414   dw_parse_all_cus(d);
    415   cu_idx = dw_cu_index_at(d, cu_offset);
    416   if (cu_idx == UINT32_MAX) return KIT_NOT_FOUND;
    417   if (!d->cus[cu_idx].has_stmt_list) return KIT_NOT_FOUND;
    418   if (!d->lines_built[cu_idx]) dw_build_line(d, cu_idx);
    419   lp = &d->lines_by_cu[cu_idx];
    420   if (file_index < lp->nfile_norm && lp->file_norm[file_index])
    421     path = lp->file_norm[file_index];
    422   else if (file_index < lp->nfiles)
    423     path = lp->files[file_index].path;
    424   if (!path) return KIT_NOT_FOUND;
    425   *out = kit_slice_cstr(path);
    426   return KIT_OK;
    427 }
    428 
    429 /* ---- .debug_str iterator ---------------------------------------------- */
    430 
    431 struct KitDwarfStrIter {
    432   KitDebugInfo* d;
    433   u32 off;
    434 };
    435 
    436 KitStatus kit_dwarf_str_iter_new(KitDebugInfo* d, KitDwarfStrIter** out) {
    437   KitDwarfStrIter* it;
    438   if (!out) return KIT_INVALID;
    439   *out = NULL;
    440   if (!d) return KIT_INVALID;
    441   it = DW_ITER_ALLOC(d, KitDwarfStrIter);
    442   if (!it) return KIT_NOMEM;
    443   it->d = d;
    444   it->off = 0;
    445   *out = it;
    446   return KIT_OK;
    447 }
    448 
    449 KitIterResult kit_dwarf_str_iter_next(KitDwarfStrIter* it, KitDwarfStr* out) {
    450   KitDebugInfo* d;
    451   const u8* base;
    452   u32 size, start, n;
    453   if (!it || !out) return KIT_ITER_ERROR;
    454   d = it->d;
    455   base = d->str.data;
    456   size = d->str.size;
    457   if (!base || it->off >= size) return KIT_ITER_END;
    458   start = it->off;
    459   n = 0;
    460   while (it->off < size && base[it->off] != 0) {
    461     it->off++;
    462     n++;
    463   }
    464   if (it->off < size) it->off++; /* step over the NUL */
    465   out->offset = start;
    466   out->str.s = (const char*)(base + start);
    467   out->str.len = n;
    468   return KIT_ITER_ITEM;
    469 }
    470 
    471 void kit_dwarf_str_iter_free(KitDwarfStrIter* it) {
    472   if (it) dw_iter_free(it->d, it, sizeof(*it));
    473 }