mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-14 17:28:07 +00:00
d2r2: dwarf 5 .debug_rnglists, .debug_addr parsing / usage
This commit is contained in:
+131
-7
@@ -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)
|
||||
{
|
||||
U64 entry_idx = val.u128.u64[0];
|
||||
if(entry_idx < ctx->str_offsets_table->entries_count)
|
||||
U64 string_data_off = 0;
|
||||
if(dw2_try_offset_from_table_idx(ctx->str_offsets_table, entry_idx, &string_data_off))
|
||||
{
|
||||
U64 entry_size = ctx->str_offsets_table->entry_size;
|
||||
U64 entry_off = entry_idx * entry_size;
|
||||
U64 string_data_off = 0;
|
||||
MemoryCopy(&string_data_off, (U8 *)ctx->str_offsets_table->entries + entry_off, entry_size);
|
||||
String8 string_section_data = ctx->raw->sec[DW_Section_Str].data;
|
||||
val.string = str8_cstring_capped(string_section_data.str + string_data_off,
|
||||
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)
|
||||
|
||||
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;
|
||||
{
|
||||
@@ -901,6 +898,20 @@ dw2_read_str_offsets_table(String8 data, U64 off, DW2_StrOffsetsTable *out)
|
||||
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)
|
||||
|
||||
@@ -957,7 +968,120 @@ dw2_rnglist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_Form
|
||||
//- rjf: @dwarf5
|
||||
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;
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -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;
|
||||
struct DW2_StrOffsetsTable
|
||||
typedef struct DW2_OffsetTable DW2_OffsetTable;
|
||||
struct DW2_OffsetTable
|
||||
{
|
||||
DW_Format format;
|
||||
DW_Version version;
|
||||
@@ -64,7 +64,9 @@ struct DW2_ParseCtx
|
||||
U64 addr_size;
|
||||
U64 unit_base_addr;
|
||||
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_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);
|
||||
|
||||
////////////////////////////////
|
||||
//~ 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)
|
||||
|
||||
@@ -416,7 +416,9 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
||||
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
|
||||
// compilation units. compilation units *do* contain a
|
||||
@@ -439,61 +441,90 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
||||
// thank you, again, DWARF.
|
||||
//
|
||||
U64 str_offsets_tables_count = 0;
|
||||
DW2_StrOffsetsTable *str_offsets_tables = 0;
|
||||
DW2_OffsetTable *str_offsets_tables = 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)
|
||||
{
|
||||
Temp scratch2 = scratch_begin(&scratch.arena, 1);
|
||||
|
||||
//- rjf: gather all tables (loose)
|
||||
typedef struct TableNode TableNode;
|
||||
struct TableNode
|
||||
struct
|
||||
{
|
||||
TableNode *next;
|
||||
DW2_StrOffsetsTable v;
|
||||
Rng1U64 range;
|
||||
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},
|
||||
};
|
||||
TableNode *first_table = 0;
|
||||
TableNode *last_table = 0;
|
||||
U64 table_count = 0;
|
||||
for(U64 off = 0; off < raw->sec[DW_Section_StrOffsets].data.size;)
|
||||
for EachElement(task_idx, tasks)
|
||||
{
|
||||
U64 start_off = off;
|
||||
DW2_StrOffsetsTable table = {0};
|
||||
off += dw2_read_str_offsets_table(raw->sec[DW_Section_StrOffsets].data, off, &table);
|
||||
if(table.entries != 0)
|
||||
{
|
||||
TableNode *n = push_array(scratch2.arena, TableNode, 1);
|
||||
SLLQueuePush(first_table, last_table, n);
|
||||
n->v = table;
|
||||
n->range = r1u64(start_off, off);
|
||||
table_count += 1;
|
||||
}
|
||||
if(off == start_off)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
Temp scratch2 = scratch_begin(&scratch.arena, 1);
|
||||
String8 data = tasks[task_idx].data;
|
||||
|
||||
//- rjf: tighten
|
||||
str_offsets_tables_count = table_count;
|
||||
str_offsets_tables = push_array(scratch.arena, DW2_StrOffsetsTable, str_offsets_tables_count);
|
||||
str_offsets_tables_ranges = push_array(scratch.arena, Rng1U64, str_offsets_tables_count);
|
||||
{
|
||||
U64 idx = 0;
|
||||
for EachNode(n, TableNode, first_table)
|
||||
//- rjf: gather all tables (loose)
|
||||
typedef struct TableNode TableNode;
|
||||
struct TableNode
|
||||
{
|
||||
str_offsets_tables[idx] = n->v;
|
||||
str_offsets_tables_ranges[idx] = n->range;
|
||||
idx += 1;
|
||||
TableNode *next;
|
||||
DW2_OffsetTable v;
|
||||
Rng1U64 range;
|
||||
};
|
||||
TableNode *first_table = 0;
|
||||
TableNode *last_table = 0;
|
||||
U64 table_count = 0;
|
||||
for(U64 off = 0; off < data.size;)
|
||||
{
|
||||
U64 start_off = off;
|
||||
DW2_OffsetTable table = {0};
|
||||
off += dw2_read_offset_table(data, off, &table);
|
||||
if(table.entries != 0)
|
||||
{
|
||||
TableNode *n = push_array(scratch2.arena, TableNode, 1);
|
||||
SLLQueuePush(first_table, last_table, n);
|
||||
n->v = table;
|
||||
n->range = r1u64(start_off, off);
|
||||
table_count += 1;
|
||||
}
|
||||
if(off == start_off)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch2);
|
||||
//- rjf: tighten
|
||||
tasks[task_idx].tables_count_out[0] = table_count;
|
||||
tasks[task_idx].tables_out[0] = push_array(scratch.arena, DW2_OffsetTable, table_count);
|
||||
tasks[task_idx].tables_ranges_out[0] = push_array(scratch.arena, Rng1U64, table_count);
|
||||
{
|
||||
U64 idx = 0;
|
||||
for EachNode(n, TableNode, first_table)
|
||||
{
|
||||
tasks[task_idx].tables_out[0][idx] = n->v;
|
||||
tasks[task_idx].tables_ranges_out[0][idx] = n->range;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch2);
|
||||
}
|
||||
}
|
||||
lane_sync_u64(&str_offsets_tables_count, 0);
|
||||
lane_sync_u64(&str_offsets_tables, 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
|
||||
@@ -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,
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
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();
|
||||
@@ -553,7 +586,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
||||
Rng1U64 range = lane_range(unit_count);
|
||||
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);
|
||||
U64 low_pc = low_pc_attrib->val.u128.u64[0];
|
||||
unit_parse_ctxs[unit_idx].unit_base_addr = low_pc;
|
||||
@@ -562,22 +595,52 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
||||
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
|
||||
//
|
||||
{
|
||||
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 addr_tables_ranges_array = {addr_tables_ranges, addr_tables_count};
|
||||
Rng1U64 range = lane_range(unit_count);
|
||||
for EachInRange(unit_idx, range)
|
||||
{
|
||||
DW2_Tag *unit_root_tag = &unit_root_tags__pre_str_offsets[unit_idx];
|
||||
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_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)
|
||||
DW2_Tag *unit_root_tag = &unit_root_tags__pre_offset_tables[unit_idx];
|
||||
|
||||
// rjf: find rnglists table
|
||||
{
|
||||
DW2_StrOffsetsTable *table = &str_offsets_tables[str_offsets_table_num-1];
|
||||
unit_parse_ctxs[unit_idx].str_offsets_table = 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);
|
||||
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);
|
||||
if(0 < str_offsets_table_num && str_offsets_table_num <= str_offsets_tables_ranges_array.count)
|
||||
{
|
||||
DW2_OffsetTable *table = &str_offsets_tables[str_offsets_table_num-1];
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user