dwarf: fix incorrect offset table parsing in cases of rnglists. extra offset field & different interpretation of table entries.

This commit is contained in:
Ryan Fleury committed 2026-10-01 16:31:18 -06:00
1 parent 0956d2fa14
commit f6b4a38134
2 files changed
+47 -17

No files matched your search

+44 -15
View File
@@ -1202,7 +1202,7 @@ dw2_read_line_table_header(Arena *arena, DW_Raw *raw, DW2_ParseCtx *ctx, String8
//~ rjf: String Offset Table Parsing (.debug_str_offsets)
internal U64
dw2_read_offset_table(String8 data, U64 off, DW2_OffsetTable *out)
dw2_read_offset_table(String8 data, U64 off, B32 offset_count_entry, DW2_OffsetTable *out)
{
U64 start_off = off;
{
@@ -1225,11 +1225,34 @@ dw2_read_offset_table(String8 data, U64 off, DW2_OffsetTable *out)
off += str8_deserial_read_struct(data, off, &addr_size);
off += str8_deserial_read_struct(data, off, &segment_selector_size);
// rjf: determine entry size
U64 entry_size = dw_addr_size_from_format(format);
if(addr_size != 0)
// rjf: 0 addr size / segment selector size -> this is an offset table (e.g. stroffs).
// this means the table immediately follows the header, and the entry size is based
// on the format.
U64 entry_size = 0;
U64 entry_count = 0;
if(addr_size == 0 && segment_selector_size == 0)
{
entry_size = dw_addr_size_from_format(format);
entry_count = (unit_data_off_opl - off) / entry_size;
}
// rjf: nonzero addr size / segment selector size -> if we have an explicitly
// stored offset count entry, we need to parse it
else if(offset_count_entry)
{
entry_size = dw_addr_size_from_format(format);
off += str8_deserial_read(data, off, &entry_count, 4, 4);
U64 entry_count_cap = (unit_data_off_opl - off) / entry_size;
entry_count = Min(entry_count, entry_count_cap);
}
// rjf: nonzero addr size / segment selector size -> no stored offset count,
// then we infer the entry count from the data remaining, as we are just
// storing address pairs.
else
{
entry_size = addr_size + segment_selector_size;
entry_count = (unit_data_off_opl - off) / entry_size;
}
// rjf: fill table info
@@ -1238,7 +1261,8 @@ dw2_read_offset_table(String8 data, U64 off, DW2_OffsetTable *out)
out->addr_size = addr_size;
out->segment_selector_size = segment_selector_size;
out->entry_size = entry_size;
out->entries_count = (unit_data_off_opl - off) / out->entry_size;
out->entries_count = entry_count;
out->entries_are_addrs = (!offset_count_entry && addr_size != 0);
out->entries = data.str + off;
// rjf: skip table
@@ -1250,14 +1274,14 @@ dw2_read_offset_table(String8 data, U64 off, DW2_OffsetTable *out)
}
internal DW2_OffsetTableList
dw2_offset_table_list_from_data(Arena *arena, String8 data)
dw2_offset_table_list_from_data(Arena *arena, String8 data, B32 offset_count_entry)
{
DW2_OffsetTableList list = {0};
for(U64 off = 0; off < data.size;)
{
U64 start_off = off;
DW2_OffsetTable table = {0};
off += dw2_read_offset_table(data, off, &table);
off += dw2_read_offset_table(data, off, offset_count_entry, &table);
if(table.entries != 0)
{
DW2_OffsetTableNode *n = push_array(arena, DW2_OffsetTableNode, 1);
@@ -1282,7 +1306,7 @@ dw2_try_offset_from_table_idx(DW2_OffsetTable *tbl, U64 idx, U64 *out)
{
U64 entry_size = tbl->entry_size;
U64 entry_off = idx * entry_size;
if(tbl->addr_size != 0)
if(tbl->entries_are_addrs)
{
U64 segment_off = entry_off;
U64 addr_off = entry_off + tbl->segment_selector_size;
@@ -1310,22 +1334,24 @@ dw2_offset_table_set_from_raw(Arena *arena, DW_Raw *raw)
struct
{
String8 data;
B32 offset_count_entry;
U64 *tables_count_out;
DW2_OffsetTable **tables_out;
Rng1U64 **tables_ranges_out;
}
tasks[] =
{
{raw->sec[DW_SectionKind_StrOffsets].data, &result.str_offsets_tables_count, &result.str_offsets_tables, &result.str_offsets_tables_ranges},
{raw->sec[DW_SectionKind_RngLists].data, &result.rnglists_tables_count, &result.rnglists_tables, &result.rnglists_tables_ranges},
{raw->sec[DW_SectionKind_Addr].data, &result.addr_tables_count, &result.addr_tables, &result.addr_tables_ranges},
{raw->sec[DW_SectionKind_LocLists].data, &result.loclists_tables_count, &result.loclists_tables, &result.loclists_tables_ranges},
{raw->sec[DW_SectionKind_StrOffsets].data, 0, &result.str_offsets_tables_count, &result.str_offsets_tables, &result.str_offsets_tables_ranges},
{raw->sec[DW_SectionKind_RngLists].data, 1, &result.rnglists_tables_count, &result.rnglists_tables, &result.rnglists_tables_ranges},
{raw->sec[DW_SectionKind_Addr].data, 0, &result.addr_tables_count, &result.addr_tables, &result.addr_tables_ranges},
{raw->sec[DW_SectionKind_LocLists].data, 1, &result.loclists_tables_count, &result.loclists_tables, &result.loclists_tables_ranges},
};
for EachElement(task_idx, tasks)
{
Temp scratch = scratch_begin(&arena, 1);
String8 data = tasks[task_idx].data;
DW2_OffsetTableList tables = dw2_offset_table_list_from_data(scratch.arena, data);
B32 offset_count_entry = tasks[task_idx].offset_count_entry;
DW2_OffsetTableList tables = dw2_offset_table_list_from_data(scratch.arena, data, offset_count_entry);
tasks[task_idx].tables_count_out[0] = tables.count;
tasks[task_idx].tables_out[0] = push_array(arena, DW2_OffsetTable, tables.count);
tasks[task_idx].tables_ranges_out[0] = push_array(arena, Rng1U64, tables.count);
@@ -1421,7 +1447,10 @@ dw2_rnglist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_Form
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);
U64 rnglist_off_from_off_array = 0;
dw2_try_offset_from_table_idx(ctx->rnglists_table, rnglist_off_idx, &rnglist_off_from_off_array);
U64 rnglist_off_array_base_off = (U64)((U8 *)ctx->rnglists_table->entries - data.str);
rnglist_off = rnglist_off_array_base_off + rnglist_off_from_off_array;
}break;
}
@@ -1624,7 +1653,7 @@ dw2_loclist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_Form
loclist_off = form_val.u128.u64[0];
}break;
case DW_FormKind_LocListx:
if(ctx->rnglists_table != 0)
if(ctx->loclists_table != 0)
{
U64 loclist_off_idx = form_val.u128.u64[0];
dw2_try_offset_from_table_idx(ctx->loclists_table, loclist_off_idx, &loclist_off);
+3 -2
View File
@@ -104,6 +104,7 @@ struct DW2_OffsetTable
U8 segment_selector_size;
U64 entry_size;
U64 entries_count;
B32 entries_are_addrs;
void *entries;
};
@@ -430,8 +431,8 @@ internal U64 dw2_read_line_table_header(Arena *arena, DW_Raw *raw, DW2_ParseCtx
////////////////////////////////
//~ rjf: Offset Table Parsing (.debug_str_offsets, .debug_rnglists)
internal U64 dw2_read_offset_table(String8 data, U64 off, DW2_OffsetTable *out);
internal DW2_OffsetTableList dw2_offset_table_list_from_data(Arena *arena, String8 data);
internal U64 dw2_read_offset_table(String8 data, U64 off, B32 offset_count_entry, DW2_OffsetTable *out);
internal DW2_OffsetTableList dw2_offset_table_list_from_data(Arena *arena, String8 data, B32 offset_count_entry);
internal B32 dw2_try_offset_from_table_idx(DW2_OffsetTable *tbl, U64 idx, U64 *out);
internal DW2_OffsetTableSet dw2_offset_table_set_from_raw(Arena *arena, DW_Raw *raw);