d2r2: dwarf 5 .debug_rnglists, .debug_addr parsing / usage

This commit is contained in:
Ryan Fleury
2026-04-28 09:37:31 -07:00
parent f5ec462438
commit 242f4e9cbd
3 changed files with 259 additions and 69 deletions
+131 -7
View File
@@ -402,12 +402,9 @@ dw2_read_form_val(DW2_ParseCtx *ctx, String8 data, U64 off, DW_FormKind form_kin
if(ctx->str_offsets_table != 0) if(ctx->str_offsets_table != 0)
{ {
U64 entry_idx = val.u128.u64[0]; U64 entry_idx = val.u128.u64[0];
if(entry_idx < ctx->str_offsets_table->entries_count)
{
U64 entry_size = ctx->str_offsets_table->entry_size;
U64 entry_off = entry_idx * entry_size;
U64 string_data_off = 0; U64 string_data_off = 0;
MemoryCopy(&string_data_off, (U8 *)ctx->str_offsets_table->entries + entry_off, entry_size); if(dw2_try_offset_from_table_idx(ctx->str_offsets_table, entry_idx, &string_data_off))
{
String8 string_section_data = ctx->raw->sec[DW_Section_Str].data; String8 string_section_data = ctx->raw->sec[DW_Section_Str].data;
val.string = str8_cstring_capped(string_section_data.str + string_data_off, val.string = str8_cstring_capped(string_section_data.str + string_data_off,
string_section_data.str + string_section_data.size); string_section_data.str + string_section_data.size);
@@ -866,7 +863,7 @@ dw2_read_line_table_header(Arena *arena, DW2_ParseCtx *ctx, String8 data, U64 of
//~ rjf: String Offset Table Parsing (.debug_str_offsets) //~ rjf: String Offset Table Parsing (.debug_str_offsets)
internal U64 internal U64
dw2_read_str_offsets_table(String8 data, U64 off, DW2_StrOffsetsTable *out) dw2_read_offset_table(String8 data, U64 off, DW2_OffsetTable *out)
{ {
U64 start_off = off; U64 start_off = off;
{ {
@@ -901,6 +898,20 @@ dw2_read_str_offsets_table(String8 data, U64 off, DW2_StrOffsetsTable *out)
return bytes_read; return bytes_read;
} }
internal B32
dw2_try_offset_from_table_idx(DW2_OffsetTable *tbl, U64 idx, U64 *out)
{
B32 result = 0;
if(idx < tbl->entries_count)
{
U64 entry_size = tbl->entry_size;
U64 entry_off = idx * entry_size;
MemoryCopy(out, (U8 *)tbl->entries + entry_off, entry_size);
result = 1;
}
return result;
}
//////////////////////////////// ////////////////////////////////
//~ rjf: Range List Parsing (.debug_rnglists) //~ rjf: Range List Parsing (.debug_rnglists)
@@ -957,7 +968,120 @@ dw2_rnglist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_Form
//- rjf: @dwarf5 //- rjf: @dwarf5
case DW_Version_5: case DW_Version_5:
{ {
// TODO(rjf) String8 data = raw->sec[DW_Section_RngLists].data;
// rjf: determine section offset - sometimes this is encoded directly,
// other times it is relative, based on the form kind - more variability
// in this awful format
U64 rnglist_off = 0;
switch(form_val.kind)
{
default:{}break;
case DW_Form_SecOffset:
{
rnglist_off = form_val.u128.u64[0];
}break;
case DW_Form_RngListx:
if(ctx->rnglists_table != 0)
{
U64 rnglist_off_idx = form_val.u128.u64[0];
dw2_try_offset_from_table_idx(ctx->rnglists_table, rnglist_off_idx, &rnglist_off);
}break;
}
// rjf: in a HIGHLY UNEXPECTED TURN OF EVENTS, we now have to decode ANOTHER
// OPCODE STREAM to unpack the actual list of ranges!!!
U64 rle_sentinel = (ctx->addr_size == 4 ? max_U32 : max_U64);
U64 base_addr = ctx->unit_base_addr;
for(U64 off = rnglist_off; off < data.size;)
{
U64 start_off = off;
// rjf: decode op kind
DW_RLE rle_kind = DW_RLE_EndOfList;
off += str8_deserial_read_struct(data, off, &rle_kind);
// rjf: obtain range from op
B32 good_range = 1;
Rng1U64 range = {0};
switch(rle_kind)
{
default:{good_range = 0;}break;
case DW_RLE_BaseAddressx:
{
good_range = 0;
U64 addr_idx = 0;
off += str8_deserial_read_uleb128(data, off, &addr_idx);
if(ctx->addr_table != 0)
{
U64 new_base_addr = 0;
if(dw2_try_offset_from_table_idx(ctx->addr_table, addr_idx, &new_base_addr))
{
base_addr = new_base_addr;
}
}
}break;
case DW_RLE_StartxLength:
{
good_range = 0;
U64 start_idx = 0;
U64 length = 0;
off += str8_deserial_read_uleb128(data, off, &start_idx);
off += str8_deserial_read_uleb128(data, off, &length);
if(ctx->addr_table != 0)
{
U64 start = 0;
if(dw2_try_offset_from_table_idx(ctx->addr_table, start_idx, &start))
{
good_range = 1;
range = r1u64(start, start+length);
}
}
}break;
case DW_RLE_OffsetPair:
{
U64 range_off_start = 0;
U64 range_off_end = 0;
off += str8_deserial_read_uleb128(data, off, &range_off_start);
off += str8_deserial_read_uleb128(data, off, &range_off_end);
range = r1u64(base_addr + range_off_start, base_addr + range_off_end);
}break;
case DW_RLE_BaseAddress:
{
U64 new_base_addr = 0;
off += str8_deserial_read(data, off, &new_base_addr, ctx->addr_size, ctx->addr_size);
base_addr = new_base_addr;
}break;
case DW_RLE_StartEnd:
{
U64 start = 0;
U64 end = 0;
off += str8_deserial_read(data, off, &start, ctx->addr_size, ctx->addr_size);
off += str8_deserial_read(data, off, &end, ctx->addr_size, ctx->addr_size);
range = r1u64(start, end);
}break;
case DW_RLE_StartLength:
{
U64 start = 0;
U64 length = 0;
off += str8_deserial_read(data, off, &start, ctx->addr_size, ctx->addr_size);
off += str8_deserial_read_uleb128(data, off, &length);
range = r1u64(start, start + length);
}break;
}
// rjf: add range
if(good_range)
{
rng1u64_list_push(arena, &result, range);
}
// rjf: end if no movement or end-of-list code
if(off == start_off || rle_kind == DW_RLE_EndOfList)
{
break;
}
}
}break; }break;
} }
return result; return result;
+9 -6
View File
@@ -37,10 +37,10 @@ struct DW2_AbbrevMap
}; };
//////////////////////////////// ////////////////////////////////
//~ rjf: String Offset Table (.debug_str_offsets) //~ rjf: Offset Tables (.debug_str_offsets, .debug_rnglists)
typedef struct DW2_StrOffsetsTable DW2_StrOffsetsTable; typedef struct DW2_OffsetTable DW2_OffsetTable;
struct DW2_StrOffsetsTable struct DW2_OffsetTable
{ {
DW_Format format; DW_Format format;
DW_Version version; DW_Version version;
@@ -64,7 +64,9 @@ struct DW2_ParseCtx
U64 addr_size; U64 addr_size;
U64 unit_base_addr; U64 unit_base_addr;
DW2_AbbrevMap *abbrev_map; DW2_AbbrevMap *abbrev_map;
DW2_StrOffsetsTable *str_offsets_table; DW2_OffsetTable *rnglists_table;
DW2_OffsetTable *str_offsets_table;
DW2_OffsetTable *addr_table;
String8 unit_dir; String8 unit_dir;
String8 unit_file; String8 unit_file;
}; };
@@ -234,9 +236,10 @@ internal U64 dw2_reference_info_off_from_form_val(DW2_ParseCtx *ctx, DW2_FormVal
internal U64 dw2_read_line_table_header(Arena *arena, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_LineTableHeader *out); internal U64 dw2_read_line_table_header(Arena *arena, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_LineTableHeader *out);
//////////////////////////////// ////////////////////////////////
//~ rjf: String Offset Table Parsing (.debug_str_offsets) //~ rjf: Offset Table Parsing (.debug_str_offsets, .debug_rnglists)
internal U64 dw2_read_str_offsets_table(String8 data, U64 off, DW2_StrOffsetsTable *out); internal U64 dw2_read_offset_table(String8 data, U64 off, DW2_OffsetTable *out);
internal B32 dw2_try_offset_from_table_idx(DW2_OffsetTable *tbl, U64 idx, U64 *out);
//////////////////////////////// ////////////////////////////////
//~ rjf: Range List Parsing (.debug_rnglists) //~ rjf: Range List Parsing (.debug_rnglists)
+83 -20
View File
@@ -416,7 +416,9 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
lane_sync(); lane_sync();
//////////////////////////// ////////////////////////////
//- rjf: parse all string offsets tables //- rjf: parse all unit offsets tables
//
// on .debug_str_offsets, as one example:
// //
// in an incredible twist of fate, DWARF decided to decouple these from // in an incredible twist of fate, DWARF decided to decouple these from
// compilation units. compilation units *do* contain a // compilation units. compilation units *do* contain a
@@ -439,28 +441,50 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
// thank you, again, DWARF. // thank you, again, DWARF.
// //
U64 str_offsets_tables_count = 0; U64 str_offsets_tables_count = 0;
DW2_StrOffsetsTable *str_offsets_tables = 0; DW2_OffsetTable *str_offsets_tables = 0;
Rng1U64 *str_offsets_tables_ranges = 0; Rng1U64 *str_offsets_tables_ranges = 0;
ProfScope("parse all string offsets tables") if(lane_idx() == 0) U64 rnglists_tables_count = 0;
DW2_OffsetTable *rnglists_tables = 0;
Rng1U64 *rnglists_tables_ranges = 0;
U64 addr_tables_count = 0;
DW2_OffsetTable *addr_tables = 0;
Rng1U64 *addr_tables_ranges = 0;
ProfScope("parse all offset tables (.debug_rnglists, .debug_str_offsets, .debug_addr)") if(lane_idx() == 0)
{
struct
{
String8 data;
U64 *tables_count_out;
DW2_OffsetTable **tables_out;
Rng1U64 **tables_ranges_out;
}
tasks[] =
{
{raw->sec[DW_Section_StrOffsets].data, &str_offsets_tables_count, &str_offsets_tables, &str_offsets_tables_ranges},
{raw->sec[DW_Section_RngLists].data, &rnglists_tables_count, &rnglists_tables, &rnglists_tables_ranges},
{raw->sec[DW_Section_Addr].data, &addr_tables_count, &addr_tables, &addr_tables_ranges},
};
for EachElement(task_idx, tasks)
{ {
Temp scratch2 = scratch_begin(&scratch.arena, 1); Temp scratch2 = scratch_begin(&scratch.arena, 1);
String8 data = tasks[task_idx].data;
//- rjf: gather all tables (loose) //- rjf: gather all tables (loose)
typedef struct TableNode TableNode; typedef struct TableNode TableNode;
struct TableNode struct TableNode
{ {
TableNode *next; TableNode *next;
DW2_StrOffsetsTable v; DW2_OffsetTable v;
Rng1U64 range; Rng1U64 range;
}; };
TableNode *first_table = 0; TableNode *first_table = 0;
TableNode *last_table = 0; TableNode *last_table = 0;
U64 table_count = 0; U64 table_count = 0;
for(U64 off = 0; off < raw->sec[DW_Section_StrOffsets].data.size;) for(U64 off = 0; off < data.size;)
{ {
U64 start_off = off; U64 start_off = off;
DW2_StrOffsetsTable table = {0}; DW2_OffsetTable table = {0};
off += dw2_read_str_offsets_table(raw->sec[DW_Section_StrOffsets].data, off, &table); off += dw2_read_offset_table(data, off, &table);
if(table.entries != 0) if(table.entries != 0)
{ {
TableNode *n = push_array(scratch2.arena, TableNode, 1); TableNode *n = push_array(scratch2.arena, TableNode, 1);
@@ -476,24 +500,31 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
} }
//- rjf: tighten //- rjf: tighten
str_offsets_tables_count = table_count; tasks[task_idx].tables_count_out[0] = table_count;
str_offsets_tables = push_array(scratch.arena, DW2_StrOffsetsTable, str_offsets_tables_count); tasks[task_idx].tables_out[0] = push_array(scratch.arena, DW2_OffsetTable, table_count);
str_offsets_tables_ranges = push_array(scratch.arena, Rng1U64, str_offsets_tables_count); tasks[task_idx].tables_ranges_out[0] = push_array(scratch.arena, Rng1U64, table_count);
{ {
U64 idx = 0; U64 idx = 0;
for EachNode(n, TableNode, first_table) for EachNode(n, TableNode, first_table)
{ {
str_offsets_tables[idx] = n->v; tasks[task_idx].tables_out[0][idx] = n->v;
str_offsets_tables_ranges[idx] = n->range; tasks[task_idx].tables_ranges_out[0][idx] = n->range;
idx += 1; idx += 1;
} }
} }
scratch_end(scratch2); scratch_end(scratch2);
} }
}
lane_sync_u64(&str_offsets_tables_count, 0); lane_sync_u64(&str_offsets_tables_count, 0);
lane_sync_u64(&str_offsets_tables, 0); lane_sync_u64(&str_offsets_tables, 0);
lane_sync_u64(&str_offsets_tables_ranges, 0); lane_sync_u64(&str_offsets_tables_ranges, 0);
lane_sync_u64(&rnglists_tables_count, 0);
lane_sync_u64(&rnglists_tables, 0);
lane_sync_u64(&rnglists_tables_ranges, 0);
lane_sync_u64(&addr_tables_count, 0);
lane_sync_u64(&addr_tables, 0);
lane_sync_u64(&addr_tables_ranges, 0);
//////////////////////////// ////////////////////////////
//- rjf: build per-unit parsing contexts //- rjf: build per-unit parsing contexts
@@ -531,17 +562,19 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
// so, in another incredible twist of fate, we actually must do this *twice*. first, // so, in another incredible twist of fate, we actually must do this *twice*. first,
// to find *just the StrOffsetsBase*, and then, to actually fully resolve everything. // to find *just the StrOffsetsBase*, and then, to actually fully resolve everything.
// //
DW2_Tag *unit_root_tags__pre_str_offsets = 0; // (all of the above is also true for RngListsBase)
//
DW2_Tag *unit_root_tags__pre_offset_tables = 0;
{ {
if(lane_idx() == 0) if(lane_idx() == 0)
{ {
unit_root_tags__pre_str_offsets = push_array(scratch.arena, DW2_Tag, unit_count); unit_root_tags__pre_offset_tables = push_array(scratch.arena, DW2_Tag, unit_count);
} }
lane_sync_u64(&unit_root_tags__pre_str_offsets, 0); lane_sync_u64(&unit_root_tags__pre_offset_tables, 0);
Rng1U64 range = lane_range(unit_count); Rng1U64 range = lane_range(unit_count);
for EachInRange(unit_idx, range) for EachInRange(unit_idx, range)
{ {
dw2_read_tag(scratch.arena, &unit_parse_ctxs[unit_idx], raw->sec[DW_Section_Info].data, unit_info_tag_ranges[unit_idx].min, &unit_root_tags__pre_str_offsets[unit_idx]); dw2_read_tag(scratch.arena, &unit_parse_ctxs[unit_idx], raw->sec[DW_Section_Info].data, unit_info_tag_ranges[unit_idx].min, &unit_root_tags__pre_offset_tables[unit_idx]);
} }
} }
lane_sync(); lane_sync();
@@ -553,7 +586,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
Rng1U64 range = lane_range(unit_count); Rng1U64 range = lane_range(unit_count);
for EachInRange(unit_idx, range) for EachInRange(unit_idx, range)
{ {
DW2_Tag *unit_root_tag = &unit_root_tags__pre_str_offsets[unit_idx]; DW2_Tag *unit_root_tag = &unit_root_tags__pre_offset_tables[unit_idx];
DW2_Attrib *low_pc_attrib = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_LowPc); DW2_Attrib *low_pc_attrib = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_LowPc);
U64 low_pc = low_pc_attrib->val.u128.u64[0]; U64 low_pc = low_pc_attrib->val.u128.u64[0];
unit_parse_ctxs[unit_idx].unit_base_addr = low_pc; unit_parse_ctxs[unit_idx].unit_base_addr = low_pc;
@@ -562,24 +595,54 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
lane_sync(); lane_sync();
//////////////////////////// ////////////////////////////
//- rjf: look up string offset tables for each unit (.debug_str_offsets); //- rjf: look up offset tables for each unit (.debug_str_offsets, .debug_rnglists, etc.);
// equip to per-unit parsing contexts // equip to per-unit parsing contexts
// //
{ {
Rng1U64Array rnglists_tables_ranges_array = {rnglists_tables_ranges, rnglists_tables_count};
Rng1U64Array str_offsets_tables_ranges_array = {str_offsets_tables_ranges, str_offsets_tables_count}; Rng1U64Array str_offsets_tables_ranges_array = {str_offsets_tables_ranges, str_offsets_tables_count};
Rng1U64Array addr_tables_ranges_array = {addr_tables_ranges, addr_tables_count};
Rng1U64 range = lane_range(unit_count); Rng1U64 range = lane_range(unit_count);
for EachInRange(unit_idx, range) for EachInRange(unit_idx, range)
{ {
DW2_Tag *unit_root_tag = &unit_root_tags__pre_str_offsets[unit_idx]; DW2_Tag *unit_root_tag = &unit_root_tags__pre_offset_tables[unit_idx];
// rjf: find rnglists table
{
DW2_Attrib *rnglists_base_off_attrib = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_RngListsBase);
U64 rnglists_base_off = rnglists_base_off_attrib->val.u128.u64[0];
U64 rnglists_table_num = rng1u64_array_num_from_value__binary_search(&rnglists_tables_ranges_array, rnglists_base_off);
if(0 < rnglists_table_num && rnglists_table_num <= rnglists_tables_ranges_array.count)
{
DW2_OffsetTable *table = &rnglists_tables[rnglists_table_num-1];
unit_parse_ctxs[unit_idx].rnglists_table = table;
}
}
// rjf: find str offsets table
{
DW2_Attrib *str_offsets_base_off_attrib = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_StrOffsetsBase); DW2_Attrib *str_offsets_base_off_attrib = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_StrOffsetsBase);
U64 str_offsets_base_off = str_offsets_base_off_attrib->val.u128.u64[0]; U64 str_offsets_base_off = str_offsets_base_off_attrib->val.u128.u64[0];
U64 str_offsets_table_num = rng1u64_array_num_from_value__binary_search(&str_offsets_tables_ranges_array, str_offsets_base_off); U64 str_offsets_table_num = rng1u64_array_num_from_value__binary_search(&str_offsets_tables_ranges_array, str_offsets_base_off);
if(0 < str_offsets_table_num && str_offsets_table_num <= str_offsets_tables_ranges_array.count) if(0 < str_offsets_table_num && str_offsets_table_num <= str_offsets_tables_ranges_array.count)
{ {
DW2_StrOffsetsTable *table = &str_offsets_tables[str_offsets_table_num-1]; DW2_OffsetTable *table = &str_offsets_tables[str_offsets_table_num-1];
unit_parse_ctxs[unit_idx].str_offsets_table = table; unit_parse_ctxs[unit_idx].str_offsets_table = table;
} }
} }
// rjf: find addr table
{
DW2_Attrib *addr_base_off_attrib = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_AddrBase);
U64 addr_base_off = addr_base_off_attrib->val.u128.u64[0];
U64 addr_table_num = rng1u64_array_num_from_value__binary_search(&addr_tables_ranges_array, addr_base_off);
if(0 < addr_table_num && addr_table_num <= addr_tables_ranges_array.count)
{
DW2_OffsetTable *table = &addr_tables[addr_table_num-1];
unit_parse_ctxs[unit_idx].addr_table = table;
}
}
}
} }
lane_sync(); lane_sync();