mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-10-14 04:49:41 -07:00
major clean-up pass over unwinding/module-info abstraction, + usage in the debug engine. simplified / cleaned up DWARF helpers for unwind info & expressions. decoupling unwinding / DWARF evaluation from memory read callbacks. light module info now prepared by demon layer - debug engine no longer duplicates per-backend parsing. unwind abstraction layer now does thin abstraction over unwinding backends, debug engine only calls abstraction. clean up demon to have fewer ad-hoc 'queries' on handles, and prefer sending info over debug events when possible / when it fits the usage pattern. move DWARF enum specifications to metacode, generate enums/xlists/tables/etc. decouple raddbg/radbin completely from old parsing helpers. replace portion of DWARF dumping; pull out some new parsing helpers from converter / dumper.
This commit is contained in:
1 parent
541d3afefa
commit
d73ce364b9
88 files changed
+9899
-4723
No files matched your search
+448
-764
File diff suppressed because it is too large.
Load diff
+54
-1798
File diff suppressed because it is too large.
Load diff
+1338
-16
File diff suppressed because it is too large.
Load diff
@@ -1,62 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal B32
|
||||
dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table)
|
||||
{
|
||||
B32 is_dwarf_present = 0;
|
||||
for EachIndex(idx, section_count)
|
||||
{
|
||||
COFF_SectionHeader *header = §ion_table[idx];
|
||||
String8 name = coff_name_from_section_header(string_table, header);
|
||||
DW_SectionKind s = dw_section_kind_from_string(name);
|
||||
if(s == DW_Section_Null)
|
||||
{
|
||||
s = dw_section_dwo_kind_from_string(name);
|
||||
}
|
||||
is_dwarf_present = s != DW_Section_Null;
|
||||
if(is_dwarf_present)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return is_dwarf_present;
|
||||
}
|
||||
|
||||
internal DW_Raw
|
||||
dw_input_from_coff_section_table(Arena *arena,
|
||||
String8 raw_image,
|
||||
String8 string_table,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *section_table)
|
||||
{
|
||||
DW_Raw input = {0};
|
||||
B32 sect_status[ArrayCount(input.sec)] = {0};
|
||||
|
||||
for (U64 i = 0; i < section_count; ++i) {
|
||||
COFF_SectionHeader *header = §ion_table[i];
|
||||
Rng1U64 raw_data_range = rng_1u64(header->foff, header->vsize ? header->foff + header->vsize : header->foff + header->fsize);
|
||||
String8 name = coff_name_from_section_header(string_table, header);
|
||||
|
||||
DW_SectionKind s = dw_section_kind_from_string(name);
|
||||
B32 is_dwo = 0;
|
||||
if (s == DW_Section_Null) {
|
||||
s = dw_section_dwo_kind_from_string(name);
|
||||
is_dwo = 1;
|
||||
}
|
||||
|
||||
if (s != DW_Section_Null) {
|
||||
if (sect_status[s]) {
|
||||
Assert(!"too many debug sections with identical name, picking first");
|
||||
} else {
|
||||
sect_status[s] = 1;
|
||||
DW_Section *d = &input.sec[s];
|
||||
d->name = push_str8_copy(arena, name);
|
||||
d->data = str8_substr(raw_image, raw_data_range);
|
||||
d->is_dwo = is_dwo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
@@ -1185,7 +1185,7 @@ DW_PRINTER(dw_print_frame)
|
||||
for (U64 cursor = 0, desc_size; cursor < debug_frame.size; cursor += desc_size) {
|
||||
DW_DescriptorEntry desc = {0};
|
||||
desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc);
|
||||
if (desc.type == DW_DescriptorEntryType_CIE) {
|
||||
if (desc.type == DW_DescriptorEntryKind_CIE) {
|
||||
String8 raw_cie = str8_substr(debug_frame, desc.entry_range);
|
||||
U64 restore_pos = arena_pos(scratch.arena);
|
||||
DW_CIE *cie = push_array(scratch.arena, DW_CIE, 1);
|
||||
@@ -1202,8 +1202,8 @@ DW_PRINTER(dw_print_frame)
|
||||
desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc);
|
||||
String8 raw_desc = str8_substr(debug_frame, desc.entry_range);
|
||||
switch (desc.type) {
|
||||
case DW_DescriptorEntryType_Null: {} break;
|
||||
case DW_DescriptorEntryType_CIE: {
|
||||
case DW_DescriptorEntryKind_Null: {} break;
|
||||
case DW_DescriptorEntryKind_CIE: {
|
||||
DW_CIE cie = {0};
|
||||
if (dw_parse_cie(raw_desc, desc.format, arch, &cie)) {
|
||||
String8List init_insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, DW_Ext_All, cie.format, 0, &cie, dw_decode_ptr_debug_frame, &cie, cie.insts);
|
||||
@@ -1229,7 +1229,7 @@ DW_PRINTER(dw_print_frame)
|
||||
dw_printf("ERROR: unable to parse CIE @ %I64x\n", desc.entry_range.min);
|
||||
}
|
||||
} break;
|
||||
case DW_DescriptorEntryType_FDE: {
|
||||
case DW_DescriptorEntryKind_FDE: {
|
||||
DW_DescriptorEntry cie_desc = {0};
|
||||
U64 cie_desc_size = dw_parse_descriptor_entry_header(debug_frame, desc.cie_pointer, &cie_desc);
|
||||
String8 cie_data = str8_substr(debug_frame, cie_desc.entry_range);
|
||||
|
||||
@@ -0,0 +1,718 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal String8List
|
||||
dw_dump_list_from_expr(Arena *arena, String8 data, Arch arch, DW2_ParseCtx *ctx)
|
||||
{
|
||||
String8List result = {0};
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
||||
for(U64 off = 0; off < data.size;)
|
||||
{
|
||||
U64 start_off = 0;
|
||||
|
||||
// rjf: read next op
|
||||
U8 op = 0;
|
||||
off += str8_deserial_read_struct(data, off, &op);
|
||||
|
||||
// rjf: unpack op / operands
|
||||
String8 operand_string = {0};
|
||||
U64 size_param = 0;
|
||||
B32 is_signed = 0;
|
||||
switch(op)
|
||||
{
|
||||
case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2:
|
||||
case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5:
|
||||
case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8:
|
||||
case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11:
|
||||
case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14:
|
||||
case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17:
|
||||
case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20:
|
||||
case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23:
|
||||
case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26:
|
||||
case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29:
|
||||
case DW_ExprOp_Lit30: case DW_ExprOp_Lit31:
|
||||
{
|
||||
U64 x = op - DW_ExprOp_Lit0;
|
||||
operand_string = str8f(scratch.arena, "%I64u", x);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_Const1U:size_param = 1; goto const_n;
|
||||
case DW_ExprOp_Const2U:size_param = 2; goto const_n;
|
||||
case DW_ExprOp_Const4U:size_param = 4; goto const_n;
|
||||
case DW_ExprOp_Const8U:size_param = 8; goto const_n;
|
||||
case DW_ExprOp_Const1S:size_param = 1; is_signed = 1; goto const_n;
|
||||
case DW_ExprOp_Const2S:size_param = 2; is_signed = 1; goto const_n;
|
||||
case DW_ExprOp_Const4S:size_param = 4; is_signed = 1; goto const_n;
|
||||
case DW_ExprOp_Const8S:size_param = 8; is_signed = 1; goto const_n;
|
||||
const_n:
|
||||
{
|
||||
if(is_signed)
|
||||
{
|
||||
S64 x = 0;
|
||||
off += str8_deserial_read(data, off, &x, size_param, 1);
|
||||
x = extend_sign64(x, size_param);
|
||||
operand_string = str8f(scratch.arena, "%I64d", x);
|
||||
}
|
||||
else
|
||||
{
|
||||
U64 x = 0;
|
||||
off += str8_deserial_read(data, off, &x, size_param, 1);
|
||||
operand_string = str8f(scratch.arena, "%I64u", x);
|
||||
}
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_Addr:
|
||||
{
|
||||
U64 addr = 0;
|
||||
off += str8_deserial_read(data, off, &addr, ctx->addr_size, 1);
|
||||
operand_string = str8f(scratch.arena, "0x%I64x", addr);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_ConstU:
|
||||
{
|
||||
U64 x = 0;
|
||||
off += str8_deserial_read_uleb128(data, off, &x);
|
||||
operand_string = str8f(scratch.arena, "%I64u", x);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_ConstS:
|
||||
{
|
||||
S64 x = 0;
|
||||
off += str8_deserial_read_sleb128(data, off, &x);
|
||||
operand_string = str8f(scratch.arena, "%I64d", x);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2:
|
||||
case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5:
|
||||
case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8:
|
||||
case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11:
|
||||
case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14:
|
||||
case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17:
|
||||
case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20:
|
||||
case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23:
|
||||
case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26:
|
||||
case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29:
|
||||
case DW_ExprOp_Reg30: case DW_ExprOp_Reg31:
|
||||
{
|
||||
U64 reg_idx = op - DW_ExprOp_Reg0;
|
||||
ARCH_RegCode regcode = arch_reg_code_from_dw(arch, (DW_RegCode)reg_idx);
|
||||
operand_string = arch_info->reg_code_name_table[regcode];
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_RegX:
|
||||
{
|
||||
U64 reg_idx = 0;
|
||||
off += str8_deserial_read_uleb128(data, off, ®_idx);
|
||||
ARCH_RegCode regcode = arch_reg_code_from_dw(arch, (DW_RegCode)reg_idx);
|
||||
operand_string = arch_info->reg_code_name_table[regcode];
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_ImplicitValue:
|
||||
{
|
||||
U64 value_size = 0;
|
||||
off += str8_deserial_read_uleb128(data, off, &value_size);
|
||||
Rng1U64 value_range = rng_1u64(off, off + value_size);
|
||||
String8 value_data = str8_substr(data, value_range);
|
||||
off += value_size;
|
||||
String8List value_strings = numeric_str8_list_from_data(scratch.arena, 16, value_data, 1);
|
||||
operand_string = str8_list_join(scratch.arena, &value_strings, &(StringJoin){.pre = str8_lit("{ "), .sep = str8_lit(", "), .post = str8_lit(" }")});
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_Piece:
|
||||
{
|
||||
U64 size = 0;
|
||||
off += str8_deserial_read_uleb128(data, off, &size);
|
||||
operand_string = str8f(scratch.arena, "%u", size);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_BitPiece:
|
||||
{
|
||||
U64 bit_size = 0, bit_off = 0;
|
||||
off += str8_deserial_read_uleb128(data, off, &bit_size);
|
||||
off += str8_deserial_read_uleb128(data, off, &bit_off);
|
||||
operand_string = str8f(scratch.arena, "bit size %I64u, bit offset %I64u", bit_size, bit_off);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_Pick:
|
||||
{
|
||||
U8 stack_idx = 0;
|
||||
off += str8_deserial_read_struct(data, off, &stack_idx);
|
||||
operand_string = str8f(scratch.arena, "stack index %u", stack_idx);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_PlusUConst:
|
||||
{
|
||||
U64 addend = 0;
|
||||
off += str8_deserial_read_uleb128(data, off, &addend);
|
||||
operand_string = str8f(arena, "addend %I64u", addend);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_Skip:
|
||||
{
|
||||
S16 x = 0;
|
||||
off += str8_deserial_read_struct(data, off, &x);
|
||||
operand_string = str8f(scratch.arena, "%+d bytes", x);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_Bra:
|
||||
{
|
||||
S16 x = 0;
|
||||
off += str8_deserial_read_struct(data, off, &x);
|
||||
operand_string = str8f(scratch.arena, "%+d", x);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2:
|
||||
case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5:
|
||||
case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8:
|
||||
case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11:
|
||||
case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14:
|
||||
case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17:
|
||||
case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20:
|
||||
case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23:
|
||||
case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26:
|
||||
case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29:
|
||||
case DW_ExprOp_BReg30: case DW_ExprOp_BReg31:
|
||||
{
|
||||
U64 reg_idx = op - DW_ExprOp_BReg0;
|
||||
S64 reg_off = 0;
|
||||
off += str8_deserial_read_sleb128(data, off, ®_off);
|
||||
ARCH_RegCode regcode = arch_reg_code_from_dw(arch, (DW_RegCode)reg_idx);
|
||||
operand_string = str8f(scratch.arena, "%S+%I64d", arch_info->reg_code_name_table[regcode], reg_off);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_FBReg:
|
||||
{
|
||||
S64 reg_off = 0;
|
||||
off += str8_deserial_read_sleb128(data, off, ®_off);
|
||||
operand_string = str8f(scratch.arena, "frame base offset %I64d", reg_off);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_BRegX:
|
||||
{
|
||||
U64 reg_idx = 0;
|
||||
S64 reg_off = 0;
|
||||
off += str8_deserial_read_uleb128(data, off, ®_idx);
|
||||
off += str8_deserial_read_sleb128(data, off, ®_off);
|
||||
ARCH_RegCode regcode = arch_reg_code_from_dw(arch, (DW_RegCode)reg_idx);
|
||||
operand_string = str8f(scratch.arena, "%S+%I64d", arch_info->reg_code_name_table[regcode], reg_off);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_XDerefSize:
|
||||
case DW_ExprOp_DerefSize:
|
||||
{
|
||||
U8 x = 0;
|
||||
off += str8_deserial_read_struct(data, off, &x);
|
||||
operand_string = str8f(scratch.arena, "%u", x);
|
||||
}break;
|
||||
|
||||
case DW_ExprOp_Call2:
|
||||
{
|
||||
U16 x = 0;
|
||||
off += str8_deserial_read_struct(data, off, &x);
|
||||
operand_string = str8f(scratch.arena, "%u", x);
|
||||
}break;
|
||||
case DW_ExprOp_Call4:
|
||||
{
|
||||
U32 x = 0;
|
||||
off += str8_deserial_read_struct(data, off, &x);
|
||||
operand_string = str8f(arena, "%u", x);
|
||||
}break;
|
||||
case DW_ExprOp_CallRef:
|
||||
{
|
||||
U64 x = 0;
|
||||
off += dw2_read_fmt_u64(data, off, ctx->format, &x);
|
||||
operand_string = str8f(scratch.arena, "%I64u", x);
|
||||
}break;
|
||||
case DW_ExprOp_ImplicitPointer:
|
||||
case DW_GNU_ExprOp_ImplicitPointer:
|
||||
{
|
||||
U64 info_off = 0;
|
||||
off += dw2_read_fmt_u64(data, off, ctx->format, &info_off);
|
||||
S64 ptr = 0;
|
||||
off += str8_deserial_read_sleb128(data, off, &ptr);
|
||||
operand_string = str8f(scratch.arena, ".debug_info@0x%I64x, ptr %I64x", info_off, ptr);
|
||||
} break;
|
||||
case DW_ExprOp_Convert:
|
||||
case DW_GNU_ExprOp_Convert:
|
||||
{
|
||||
U64 type_cu_off = 0;
|
||||
off += str8_deserial_read_uleb128(data, off, &type_cu_off);
|
||||
operand_string = str8f(scratch.arena, "TypeCuOff %#I64x", ctx->unit_base_info_off + type_cu_off);
|
||||
}break;
|
||||
case DW_GNU_ExprOp_ParameterRef:
|
||||
{
|
||||
// TODO: always 4 bytes?
|
||||
U32 cu_off = 0;
|
||||
off += str8_deserial_read_struct(data, off, &cu_off);
|
||||
operand_string = str8f(scratch.arena, "CuOff %#x", ctx->unit_base_info_off + cu_off);
|
||||
}break;
|
||||
case DW_ExprOp_DerefType:
|
||||
case DW_GNU_ExprOp_DerefType:
|
||||
{
|
||||
U8 deref_size = 0;
|
||||
U64 type_cu_off = 0;
|
||||
off += str8_deserial_read_struct(data, off, &deref_size);
|
||||
off += str8_deserial_read_uleb128(data, off, &type_cu_off);
|
||||
operand_string = str8f(scratch.arena, "%#x, TypeCuOff %#I64x", deref_size, ctx->unit_base_info_off + type_cu_off);
|
||||
}break;
|
||||
case DW_ExprOp_ConstType:
|
||||
case DW_GNU_ExprOp_ConstType:
|
||||
{
|
||||
U64 type_cu_off = 0;
|
||||
U8 const_value_size = 0;
|
||||
off += str8_deserial_read_uleb128(data, off, &type_cu_off);
|
||||
off += str8_deserial_read_struct(data, off, &const_value_size);
|
||||
Rng1U64 const_value_range = rng_1u64(off, off + const_value_size);
|
||||
String8 const_value_data = str8_substr(data, const_value_range);
|
||||
String8List const_value_strings = numeric_str8_list_from_data(scratch.arena, 16, const_value_data, 1);
|
||||
String8 const_value_str = str8_list_join(scratch.arena, &const_value_strings, &(StringJoin){.sep = str8_lit(", ")});
|
||||
operand_string = str8f(scratch.arena, "TypeCuOff %#I64x, Const Value { %S }", ctx->unit_base_info_off + type_cu_off, const_value_str);
|
||||
off += const_value_size;
|
||||
}break;
|
||||
case DW_ExprOp_RegvalType:
|
||||
case DW_GNU_ExprOp_RegvalType:
|
||||
{
|
||||
U64 reg_idx = 0, type_cu_off = 0;
|
||||
off += str8_deserial_read_uleb128(data, off, ®_idx);
|
||||
off += str8_deserial_read_uleb128(data, off, &type_cu_off);
|
||||
ARCH_RegCode regcode = arch_reg_code_from_dw(arch, (DW_RegCode)reg_idx);
|
||||
operand_string = str8f(scratch.arena, "%S, TypeCuOff %#I64x", arch_info->reg_code_name_table[regcode], ctx->unit_base_info_off + type_cu_off);
|
||||
}break;
|
||||
case DW_ExprOp_EntryValue:
|
||||
case DW_GNU_ExprOp_EntryValue:
|
||||
{
|
||||
U64 block_size = 0;
|
||||
off += str8_deserial_read_uleb128(data, off, &block_size);
|
||||
Rng1U64 block_range = rng_1u64(off, off + block_size);
|
||||
String8 block_data = str8_substr(data, block_range);
|
||||
// TODO(rjf): WTF, recursive? let's not... - if we want this, let's just do the stack inside of this function
|
||||
// String8List block_expr = dw_string_list_from_expression(scratch.arena, block_data, cu_base, addr_size, arch, ver, ext, format);
|
||||
// operand_string = str8_list_join(scratch.arena, &block_expr, &(StringJoin){.pre = str8_lit("{ "), .sep = str8_lit(","), .post = str8_lit(" }")});
|
||||
operand_string = s("{...}");
|
||||
off += block_size;
|
||||
} break;
|
||||
case DW_ExprOp_Addrx:
|
||||
{
|
||||
U64 addr = 0;
|
||||
off += str8_deserial_read_uleb128(data, off, &addr);
|
||||
operand_string = str8f(scratch.arena, "%#I64x", addr);
|
||||
}break;
|
||||
}
|
||||
|
||||
// rjf: push opcode info
|
||||
String8 opcode_string = dw_string_from_expr_op(ctx->version, ctx->exts, op);
|
||||
if(operand_string.size == 0)
|
||||
{
|
||||
str8_list_pushf(arena, &result, "%S", opcode_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_pushf(arena, &result, "%S(%S)", opcode_string, operand_string);
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Dump Entry Point
|
||||
|
||||
internal String8List
|
||||
dw_dump_list_from_raw(Arena *arena, DW_Raw *raw, Arch arch, DW_SectionFlags subset_flags)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8 indent = str8_lit(" ");
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: set up
|
||||
//
|
||||
typedef struct DumpSubsetOutputNode DumpSubsetOutputNode;
|
||||
struct DumpSubsetOutputNode
|
||||
{
|
||||
DumpSubsetOutputNode *next;
|
||||
DW_SectionKind section_kind;
|
||||
String8List *lane_strings;
|
||||
};
|
||||
DumpSubsetOutputNode *first_output_node = 0;
|
||||
DumpSubsetOutputNode *last_output_node = 0;
|
||||
String8List *strings = 0;
|
||||
#define dump(str) str8_list_push(arena, strings, (str))
|
||||
#define dumpf(...) str8_list_pushf(arena, strings, __VA_ARGS__)
|
||||
#define DumpSubsetKind(kind) \
|
||||
if(lane_idx() == 0)\
|
||||
{\
|
||||
DumpSubsetOutputNode *n = push_array(scratch.arena, DumpSubsetOutputNode, 1);\
|
||||
SLLQueuePush(first_output_node, last_output_node, n);\
|
||||
n->section_kind = (kind);\
|
||||
n->lane_strings = push_array(scratch.arena, String8List, lane_count());\
|
||||
}\
|
||||
lane_sync_u64(&first_output_node, 0);\
|
||||
lane_sync_u64(&last_output_node, 0);\
|
||||
strings = &last_output_node->lane_strings[lane_idx()];\
|
||||
lane_sync(); if(subset_flags & (1ull<<(kind))) ProfScope((char *)dw_regular_name_from_section_kind(kind).str)
|
||||
#define DumpSubset(name) DumpSubsetKind(DW_SectionKind_##name)
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: .debug_abbrev
|
||||
//
|
||||
DumpSubset(Abbrev)
|
||||
{
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
String8 data = raw->sec[DW_SectionKind_Abbrev].data;
|
||||
U64 idx = 0;
|
||||
dumpf("\nabbrevs:\n{\n");
|
||||
for(U64 off = 0; off < data.size; idx += 1)
|
||||
{
|
||||
Temp scratch2 = scratch_begin(&scratch.arena, 1);
|
||||
U64 start_off = off;
|
||||
|
||||
// rjf: read abbrev info
|
||||
DW2_AbbrevHeader abbrev_header = {0};
|
||||
DW2_AbbrevAttribList abbrev_attribs = {0};
|
||||
off += dw2_read_abbrev(scratch2.arena, data, off, &abbrev_header, &abbrev_attribs);
|
||||
|
||||
// rjf: log
|
||||
dumpf(" abbrev: // abbrev[%I64u], .debug_abbrev@0x%I64x\n", idx, start_off);
|
||||
dumpf(" {\n");
|
||||
dumpf(" id: %I64u\n", abbrev_header.id);
|
||||
dumpf(" tag_kind: %S (0x%I64x)\n", dw_string_from_tag_kind(DW_Version_Last, DW_ExtFlag_All, abbrev_header.tag_kind), abbrev_header.tag_kind);
|
||||
dumpf(" has_children: %s\n", abbrev_header.has_children ? "yes" : "no");
|
||||
if(abbrev_attribs.count != 0)
|
||||
{
|
||||
dumpf(" attribs:\n {\n");
|
||||
for EachNode(n, DW2_AbbrevAttribNode, abbrev_attribs.first)
|
||||
{
|
||||
DW2_AbbrevAttrib *attrib = &n->v;
|
||||
dumpf(" {%-24S %-16S%S}\n",
|
||||
dw_string_from_attrib_kind(DW_Version_Last, DW_ExtFlag_All, attrib->attrib_kind),
|
||||
dw_string_from_form_kind(DW_Version_Last, DW_ExtFlag_All, attrib->form_kind),
|
||||
attrib->form_kind == DW_FormKind_ImplicitConst ? str8f(scratch2.arena, " (0x%I64x, %I64u)", attrib->implicit_const, attrib->implicit_const) : s(""));
|
||||
}
|
||||
dumpf(" }\n");
|
||||
}
|
||||
dumpf(" }\n");
|
||||
|
||||
if(off == start_off)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
dumpf("}\n");
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: .debug_info
|
||||
//
|
||||
DumpSubset(Info)
|
||||
{
|
||||
//- rjf: gather unit ranges from .debug_info
|
||||
Rng1U64Array *unit_info_ranges = 0;
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
unit_info_ranges = push_array(scratch.arena, Rng1U64Array, 1);
|
||||
*unit_info_ranges = dw2_unit_ranges_from_data(scratch.arena, raw->sec[DW_SectionKind_Info].data);
|
||||
}
|
||||
lane_sync_u64(&unit_info_ranges, 0);
|
||||
U64 unit_count = unit_info_ranges->count;
|
||||
|
||||
//- rjf: parse all .debug_info unit headers
|
||||
DW2_UnitHeader *unit_headers = 0;
|
||||
Rng1U64 *unit_info_tag_ranges = 0;
|
||||
{
|
||||
// rjf: set up
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
unit_headers = push_array(scratch.arena, DW2_UnitHeader, unit_count);
|
||||
unit_info_tag_ranges = push_array(scratch.arena, Rng1U64, unit_count);
|
||||
}
|
||||
lane_sync_u64(&unit_headers, 0);
|
||||
lane_sync_u64(&unit_info_tag_ranges, 0);
|
||||
|
||||
// rjf: parse all unit headers
|
||||
String8 data = raw->sec[DW_SectionKind_Info].data;
|
||||
Rng1U64 range = lane_range(unit_count);
|
||||
for EachInRange(idx, range)
|
||||
{
|
||||
Rng1U64 unit_info_range = unit_info_ranges->v[idx];
|
||||
U64 bytes_read = dw2_read_unit_header(str8_substr(data, unit_info_range), 0, &unit_headers[idx]);
|
||||
unit_info_tag_ranges[idx] = r1u64(unit_info_range.min + bytes_read, unit_info_range.max);
|
||||
}
|
||||
}
|
||||
lane_sync();
|
||||
Rng1U64Array unit_info_tag_ranges_array = {unit_info_tag_ranges, unit_count};
|
||||
|
||||
//- rjf: build all abbreviation maps, build (unit -> abbrev map)
|
||||
DW2_UnitAbbrevMapMap unit_abbrev_map_map = dw2_unit_abbrev_map_map_from_data(scratch.arena, raw->sec[DW_SectionKind_Abbrev].data, unit_headers, unit_count);
|
||||
|
||||
//- rjf: parse all unit offsets tables
|
||||
DW2_OffsetTableSet *offset_tables = 0;
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
offset_tables = push_array(scratch.arena, DW2_OffsetTableSet, 1);
|
||||
offset_tables[0] = dw2_offset_table_set_from_raw(scratch.arena, raw);
|
||||
}
|
||||
lane_sync_u64(&offset_tables, 0);
|
||||
|
||||
//- rjf: build per-unit parsing contexts
|
||||
DW2_ParseCtx *unit_parse_ctxs = 0;
|
||||
{
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
unit_parse_ctxs = push_array(scratch.arena, DW2_ParseCtx, unit_count);
|
||||
}
|
||||
lane_sync_u64(&unit_parse_ctxs, 0);
|
||||
Rng1U64 range = lane_range(unit_count);
|
||||
for EachInRange(unit_idx, range)
|
||||
{
|
||||
DW2_UnitHeader *hdr = &unit_headers[unit_idx];
|
||||
DW2_ParseCtx *ctx = &unit_parse_ctxs[unit_idx];
|
||||
|
||||
// rjf: equip initial bootstrapping info
|
||||
dw2_parse_ctx_equip_unit_header(ctx, hdr, unit_info_ranges->v[unit_idx].min);
|
||||
dw2_parse_ctx_equip_unit_abbrev_map(ctx, &unit_abbrev_map_map, unit_idx);
|
||||
|
||||
// rjf: do bootstrapping parse of root tag
|
||||
DW2_Tag root_tag_bootstrap = {0};
|
||||
dw2_read_tag(scratch.arena, raw, ctx, raw->sec[DW_SectionKind_Info].data, unit_info_tag_ranges[unit_idx].min, &root_tag_bootstrap);
|
||||
|
||||
// rjf: equip info extracted from bootstrapping parse
|
||||
dw2_parse_ctx_equip_unit_root_tag(ctx, &root_tag_bootstrap, offset_tables);
|
||||
|
||||
// rjf: do non-bootstrapping parse
|
||||
DW2_Tag root_tag = {0};
|
||||
dw2_read_tag(scratch.arena, raw, ctx, raw->sec[DW_SectionKind_Info].data, unit_info_tag_ranges[unit_idx].min, &root_tag);
|
||||
|
||||
// rjf: equip info extracted from non-bootstrapping parse
|
||||
dw2_parse_ctx_equip_unit_root_tag(ctx, &root_tag, offset_tables);
|
||||
}
|
||||
}
|
||||
lane_sync();
|
||||
|
||||
//- rjf: dump all unit tag trees
|
||||
String8List *unit_dumps = 0;
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
unit_dumps = push_array(scratch.arena, String8List, unit_count);
|
||||
}
|
||||
lane_sync_u64(&unit_dumps, 0);
|
||||
U64 unit_take_idx_ = 0;
|
||||
U64 *unit_take_idx_ptr = &unit_take_idx_;
|
||||
lane_sync_u64(&unit_take_idx_ptr, 0);
|
||||
String8List *strings_restore = strings;
|
||||
for(;;)
|
||||
{
|
||||
//- rjf: take unit
|
||||
U64 unit_idx = ins_atomic_u64_inc_eval(unit_take_idx_ptr)-1;
|
||||
if(unit_idx >= unit_count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//- rjf: unpack unit
|
||||
strings = &unit_dumps[unit_idx];
|
||||
DW2_ParseCtx *ctx = &unit_parse_ctxs[unit_idx];
|
||||
|
||||
//- rjf: dump
|
||||
dumpf(" unit: // unit[%I64u], .debug_info@0x%I64x\n", unit_idx, ctx->unit_base_info_off);
|
||||
dumpf(" {\n");
|
||||
dumpf(" version: %u\n", ctx->version);
|
||||
dumpf(" format: %S\n", dw_string_from_format(ctx->format));
|
||||
dumpf(" abbrev_off: 0x%I64x\n", unit_headers[unit_idx].abbrev_off);
|
||||
dumpf(" addr_size: %I64u\n", ctx->addr_size);
|
||||
dumpf(" kind: %S\n", dw_string_from_comp_unit_kind(unit_headers[unit_idx].kind));
|
||||
dumpf(" dwo_id: 0x%I64x\n", unit_headers[unit_idx].dwo_id);
|
||||
dumpf(" tags:\n {\n");
|
||||
{
|
||||
U64 depth = 0;
|
||||
for(U64 off = unit_info_tag_ranges[unit_idx].min; off < unit_info_tag_ranges[unit_idx].max;)
|
||||
{
|
||||
U64 start_off = off;
|
||||
Temp tag_scratch = scratch_begin(&scratch.arena, 1);
|
||||
|
||||
// rjf: parse next tag
|
||||
DW2_Tag tag = {0};
|
||||
off += dw2_read_tag(tag_scratch.arena, raw, ctx, raw->sec[DW_SectionKind_Info].data, off, &tag);
|
||||
|
||||
// rjf: non-zero tag -> dump
|
||||
if(tag.kind != DW_TagKind_Null)
|
||||
{
|
||||
dumpf(" %.*s%S: // .debug_info@0x%I64x\n", depth, indent.str, dw_string_from_tag_kind(ctx->version, ctx->exts, tag.kind), start_off);
|
||||
dumpf(" %.*s{\n", depth, indent.str);
|
||||
for EachNode(n, DW2_AttribNode, tag.attribs.first)
|
||||
{
|
||||
DW2_Attrib *attrib = &n->v;
|
||||
String8 kind_string = dw_string_from_attrib_kind(ctx->version, ctx->exts, attrib->attrib_kind);
|
||||
String8 form_kind_string = dw_string_from_form_kind(ctx->version, ctx->exts, attrib->val.kind);
|
||||
String8 value_string = {0};
|
||||
DW_AttribClass value_class = dw_attrib_class_from_form_kind(ctx->version, ctx->exts, attrib->val.kind);
|
||||
switch(value_class)
|
||||
{
|
||||
default:
|
||||
{
|
||||
value_string = str8f(tag_scratch.arena, "0x%I64x", attrib->val.u128.u64[0]);
|
||||
}break;
|
||||
case DW_AttribClass_Address:
|
||||
{
|
||||
value_string = str8f(tag_scratch.arena, "0x%I64x", attrib->val.addr);
|
||||
}break;
|
||||
case DW_AttribClass_String:
|
||||
{
|
||||
value_string = str8f(tag_scratch.arena, "\"%S\"", attrib->val.string);
|
||||
}break;
|
||||
case DW_AttribClass_Flag:
|
||||
{
|
||||
value_string = attrib->val.u128.u64[0] ? s("true") : s("false");
|
||||
}break;
|
||||
case DW_AttribClass_Block:
|
||||
{
|
||||
String8 block = attrib->val.string;
|
||||
String8List block_strs = numeric_str8_list_from_data(tag_scratch.arena, 16, block, 1);
|
||||
value_string = str8_list_join(tag_scratch.arena, &block_strs, &(StringJoin){.pre = s("{ "), .sep = s(", "), .post = s(" }")});
|
||||
}break;
|
||||
case DW_AttribClass_ExprLoc:
|
||||
{
|
||||
String8 expr = attrib->val.string;
|
||||
String8List expr_strs = dw_dump_list_from_expr(tag_scratch.arena, expr, arch, ctx);
|
||||
value_string = str8_list_join(tag_scratch.arena, &expr_strs, &(StringJoin){.pre = s("{ "), .sep = s(", "), .post = s(" }")});
|
||||
}break;
|
||||
}
|
||||
dumpf(" %.*s %S: %S // %S\n", depth, indent.str, kind_string, value_string, form_kind_string);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: push/pop
|
||||
if(tag.has_children)
|
||||
{
|
||||
depth += 1;
|
||||
}
|
||||
else if(tag.kind == DW_TagKind_Null)
|
||||
{
|
||||
depth -= 1;
|
||||
}
|
||||
|
||||
// rjf: if tag does not have children -> end info
|
||||
if(!tag.has_children)
|
||||
{
|
||||
dumpf(" %.*s}\n", depth, indent.str);
|
||||
}
|
||||
|
||||
scratch_end(tag_scratch);
|
||||
if(off == start_off)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dumpf(" }\n");
|
||||
dumpf(" }\n");
|
||||
}
|
||||
strings = strings_restore;
|
||||
|
||||
//- rjf: join unit dumps in order
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
dumpf("\nunits:\n{\n");
|
||||
for EachIndex(unit_idx, unit_count)
|
||||
{
|
||||
str8_list_concat_in_place(strings, &unit_dumps[unit_idx]);
|
||||
}
|
||||
dumpf("}\n");
|
||||
}
|
||||
lane_sync();
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: .debug_line
|
||||
//
|
||||
DumpSubset(Line)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: .debug_str
|
||||
//
|
||||
DumpSubset(Str)
|
||||
{
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
dumpf("\nstrings:\n{\n");
|
||||
String8 data = raw->sec[DW_SectionKind_Str].data;
|
||||
U64 idx = 0;
|
||||
for(U64 off = 0; off < data.size; idx += 1)
|
||||
{
|
||||
U64 start_off = off;
|
||||
String8 string = {0};
|
||||
off += str8_deserial_read_cstr(data, off, &string);
|
||||
dumpf(" {\"%S\"} // string[%I64u], .debug_str@0x%I64x\n", string, idx, start_off);
|
||||
if(off == start_off)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
dumpf("}\n");
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: .debug_frame
|
||||
//
|
||||
#if 0
|
||||
DumpSubset(Frame)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: .debug_loc
|
||||
//
|
||||
#if 0
|
||||
DumpSubset(Loc)
|
||||
{
|
||||
// TODO(rjf)
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: join results
|
||||
//
|
||||
String8List *result_strings_ptr = push_array(scratch.arena, String8List, 1);
|
||||
lane_sync();
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
for EachNode(n, DumpSubsetOutputNode, first_output_node)
|
||||
{
|
||||
String8List subset_strings = {0};
|
||||
for EachIndex(idx, lane_count())
|
||||
{
|
||||
str8_list_concat_in_place(&subset_strings, &n->lane_strings[idx]);
|
||||
}
|
||||
if(subset_strings.total_size != 0)
|
||||
{
|
||||
str8_list_pushf(arena, result_strings_ptr, "////////////////////////////////\n//~ %S\n", dw_regular_name_from_section_kind(n->section_kind));
|
||||
str8_list_concat_in_place(result_strings_ptr, &subset_strings);
|
||||
str8_list_pushf(arena, result_strings_ptr, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
lane_sync();
|
||||
lane_sync_u64(&result_strings_ptr, 0);
|
||||
String8List result_strings = *result_strings_ptr;
|
||||
lane_sync();
|
||||
|
||||
#undef DumpSubsetKind
|
||||
#undef DumpSubset
|
||||
#undef dump
|
||||
#undef dumpf
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return result_strings;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DWARF_DUMP_2_H
|
||||
#define DWARF_DUMP_2_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal String8List dw_dump_list_from_expr(Arena *arena, String8 data, Arch arch, DW2_ParseCtx *ctx);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Dump Entry Point
|
||||
|
||||
internal String8List dw_dump_list_from_raw(Arena *arena, DW_Raw *raw, Arch arch, DW_SectionFlags subset_flags);
|
||||
|
||||
#endif //DWARF_DUMP_2_H
|
||||
@@ -1578,111 +1578,3 @@ dw_eval_expr(Arena *arena, Arch arch, DW_Format format, U64 frame_base, U64 cfa,
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_encode_expr(Arena *arena, Arch arch, DW_Format format, DW_ExprEnc *encs, U64 encs_count)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8List *srl = push_array(scratch.arena, String8List, 1);
|
||||
str8_serial_begin(scratch.arena, srl);
|
||||
|
||||
HashTable *label_map = hash_table_init(scratch.arena, 128);
|
||||
|
||||
struct Fixup { U64 offset; String8 label; struct Fixup *next; };
|
||||
struct Fixup *first_fixup = 0, *last_fixup = 0;
|
||||
|
||||
for EachIndex(i, encs_count) {
|
||||
DW_ExprEnc *e = &encs[i];
|
||||
|
||||
switch (e->type) {
|
||||
case DW_ExprEncType_Null: {} break;
|
||||
case DW_ExprEncType_Op: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->op);
|
||||
} break;
|
||||
case DW_ExprEncType_U8: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->u8);
|
||||
} break;
|
||||
case DW_ExprEncType_U16: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->u16);
|
||||
} break;
|
||||
case DW_ExprEncType_U32: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->u32);
|
||||
} break;
|
||||
case DW_ExprEncType_U64: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->u64);
|
||||
} break;
|
||||
case DW_ExprEncType_S8: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->s8);
|
||||
} break;
|
||||
case DW_ExprEncType_S16: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->s16);
|
||||
} break;
|
||||
case DW_ExprEncType_S32: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->s32);
|
||||
} break;
|
||||
case DW_ExprEncType_S64: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->s64);
|
||||
} break;
|
||||
case DW_ExprEncType_ULEB128: {
|
||||
str8_serial_push_string(scratch.arena, srl, dw_write_uleb128(scratch.arena, e->u64));
|
||||
} break;
|
||||
case DW_ExprEncType_SLEB128: {
|
||||
str8_serial_push_string(scratch.arena, srl, dw_write_sleb128(scratch.arena, e->s64));
|
||||
} break;
|
||||
case DW_ExprEncType_Addr: {
|
||||
U64 addr_size = byte_size_from_arch(arch);
|
||||
Assert(addr_size <= sizeof(e->addr));
|
||||
str8_serial_push_string(scratch.arena, srl, str8((U8 *)&e->addr, addr_size));
|
||||
} break;
|
||||
case DW_ExprEncType_Block: {
|
||||
Assert(e->block.size <= max_U8);
|
||||
str8_serial_push_u8(scratch.arena, srl, (U8)e->block.size);
|
||||
str8_serial_push_string(scratch.arena, srl, e->block);
|
||||
} break;
|
||||
case DW_ExprEncType_DwarfUInt: {
|
||||
switch (format) {
|
||||
case DW_Format_Null: {} break;
|
||||
case DW_Format_32Bit: { str8_serial_push_u32(scratch.arena, srl, e->u32); } break;
|
||||
case DW_Format_64Bit: { str8_serial_push_u64(scratch.arena, srl, e->u64); } break;
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
} break;
|
||||
case DW_ExprEncType_Label: {
|
||||
struct Fixup *fixup = push_array(scratch.arena, struct Fixup, 1);
|
||||
fixup->offset = srl->total_size;
|
||||
fixup->label = e->label;
|
||||
SLLQueuePush(first_fixup, last_fixup, fixup);
|
||||
|
||||
S16 delta_placeholder = 0;
|
||||
str8_serial_push_struct(scratch.arena, srl, &delta_placeholder);
|
||||
} break;
|
||||
case DW_ExprEncType_DeclLabel: {
|
||||
hash_table_push_string_u64(scratch.arena, label_map, e->label, srl->total_size);
|
||||
} break;
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
}
|
||||
|
||||
// finalize expression
|
||||
String8 expr = str8_serial_end(arena, srl);
|
||||
|
||||
// apply fixups
|
||||
for EachNode(fixup, struct Fixup, first_fixup) {
|
||||
U64 label_offset;
|
||||
if (!hash_table_search_string_u64(label_map, fixup->label, &label_offset)) {
|
||||
Assert(0 && "undefined label");
|
||||
continue;
|
||||
}
|
||||
|
||||
S64 delta = (S64)label_offset - (S64)fixup->offset;
|
||||
AssertAlways(min_S16 <= delta && delta <= max_S16);
|
||||
|
||||
S16 *delta_ptr = (S16 *)(expr.str + fixup->offset);
|
||||
*delta_ptr = delta;
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return expr;
|
||||
}
|
||||
|
||||
@@ -229,8 +229,5 @@ internal String8 dw_string_from_expr_value(Arena *arena, U64 addr_size, DW_ExprV
|
||||
// evaluator
|
||||
internal DW_ExprEvalResult dw_eval_expr(Arena *arena, Arch arch, DW_Format format, U64 frame_base, U64 cfa, U64 tls_base, U64 op_limit, DW_Expr expr, void *reg_block, MachineOp_MemRead *mem_read, void *mem_read_ud, DW_ExprValue *value_out);
|
||||
|
||||
// encoder
|
||||
internal String8 dw_encode_expr(Arena *arena, Arch arch, DW_Format format, DW_ExprEnc *encs, U64 encs_count);
|
||||
|
||||
#endif //DWARF_EXPR_H
|
||||
|
||||
@@ -0,0 +1,393 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Expression Evaluation Functions
|
||||
|
||||
internal DW_Eval
|
||||
dw_eval(Arena *arena, DW_Format fmt, Arch arch, MemoryMap *memory_map, void *regs, U64 frame_base, U64 cfa, U64 tls, DW_EvalState *state, String8 expr, U64 op_idx_cap)
|
||||
{
|
||||
DW_Eval result = {0};
|
||||
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
||||
B32 need_a_break = 0;
|
||||
B32 done = 0;
|
||||
for(;state->off < expr.size && !need_a_break && !done;)
|
||||
{
|
||||
U64 start_off = state->off;
|
||||
U64 off = state->off;
|
||||
|
||||
//- rjf: too many ops? -> error
|
||||
if(state->op_idx >= op_idx_cap)
|
||||
{
|
||||
result.status = DW_EvalStatus_ExecOpLimitReached;
|
||||
break;
|
||||
}
|
||||
|
||||
//- rjf: read next opcode
|
||||
DW_ExprOp opcode = 0;
|
||||
off += str8_deserial_read_struct(expr, off, &opcode);
|
||||
|
||||
//- rjf: unpack opcode
|
||||
U8 push_count = 0;
|
||||
U8 pop_count = 0;
|
||||
U8 operand_count = 0;
|
||||
DW_ExprOperandKind operand_kinds[2] = {DW_ExprOperandKind_Null};
|
||||
{
|
||||
DW_ExprOpInfo *op_info = dw_info_from_expr_op(DW_Version_5, DW_ExtFlag_All, opcode);
|
||||
push_count = op_info->push_count;
|
||||
pop_count = op_info->pop_count;
|
||||
operand_count = op_info->operand_count;
|
||||
MemoryCopy(operand_kinds, op_info->operand_kinds, sizeof(operand_kinds));
|
||||
}
|
||||
|
||||
//- rjf: read operands
|
||||
DW_EvalVal operands[2] = {0};
|
||||
for(U8 operand_idx = 0; operand_idx < operand_count; operand_idx += 1)
|
||||
{
|
||||
U64 fixed_bytes_to_read = 0;
|
||||
switch(operand_kinds[operand_idx])
|
||||
{
|
||||
default:{}break;
|
||||
case DW_ExprOperandKind_U8: {fixed_bytes_to_read = 1;}goto fixed_read;
|
||||
case DW_ExprOperandKind_U16: {fixed_bytes_to_read = 2;}goto fixed_read;
|
||||
case DW_ExprOperandKind_U32: {fixed_bytes_to_read = 4;}goto fixed_read;
|
||||
case DW_ExprOperandKind_U64: {fixed_bytes_to_read = 8;}goto fixed_read;
|
||||
case DW_ExprOperandKind_S8: {fixed_bytes_to_read = 1;}goto fixed_read;
|
||||
case DW_ExprOperandKind_S16: {fixed_bytes_to_read = 2;}goto fixed_read;
|
||||
case DW_ExprOperandKind_S32: {fixed_bytes_to_read = 4;}goto fixed_read;
|
||||
case DW_ExprOperandKind_S64: {fixed_bytes_to_read = 8;}goto fixed_read;
|
||||
case DW_ExprOperandKind_Addr: {fixed_bytes_to_read = byte_size_from_arch(arch);}goto fixed_read;
|
||||
case DW_ExprOperandKind_DwarfUInt:{fixed_bytes_to_read = dw_addr_size_from_format(fmt);}goto fixed_read;
|
||||
fixed_read:;
|
||||
{
|
||||
off += str8_deserial_read(expr, off, &operands[operand_idx].u512.u64[0], fixed_bytes_to_read, fixed_bytes_to_read);
|
||||
}break;
|
||||
case DW_ExprOperandKind_ULEB128:
|
||||
{
|
||||
off += str8_deserial_read_uleb128(expr, off, &operands[operand_idx].u512.u64[0]);
|
||||
}break;
|
||||
case DW_ExprOperandKind_SLEB128:
|
||||
{
|
||||
off += str8_deserial_read_sleb128(expr, off, &operands[operand_idx].s64);
|
||||
}break;
|
||||
case DW_ExprOperandKind_Block:
|
||||
{
|
||||
U8 block_size = 0;
|
||||
off += str8_deserial_read_struct(expr, off, &block_size);
|
||||
operands[operand_idx].data = str8_prefix(str8_skip(expr, off), block_size);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: do pops
|
||||
DW_EvalVal popped_vals[3] = {0};
|
||||
{
|
||||
pop_count = Min(pop_count, ArrayCount(popped_vals));
|
||||
for(U8 pop_idx = 0; pop_idx < pop_count; pop_idx += 1)
|
||||
{
|
||||
if(state->top_val != 0)
|
||||
{
|
||||
DW_EvalValNode *popped = state->top_val;
|
||||
SLLStackPop(state->top_val);
|
||||
popped_vals[pop_idx] = popped->v;
|
||||
SLLStackPush(state->free_val, popped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: apply opcode
|
||||
DW_EvalVal push_vals[3] = {0};
|
||||
U64 pick_target_idx = 0;
|
||||
U64 deref_read_size = 0;
|
||||
DW_RegCode reg_code_dw = 0;
|
||||
switch(opcode)
|
||||
{
|
||||
//- rjf: unsuported ops
|
||||
case DW_ExprOp_Call2: // DWARF function calls
|
||||
case DW_ExprOp_Call4: // DWARF function calls
|
||||
case DW_ExprOp_CallRef: // DWARF function calls
|
||||
case DW_ExprOp_Addrx: // address in .debug_addr; not currently present for us, need to find how to preserve if we care
|
||||
case DW_ExprOp_Constx: // address in .debug_addr; not currently present for us, need to find how to preserve if we care
|
||||
case DW_ExprOp_EntryValue: // encodes a sub-expression as a data block - need to recursively evaluate, lol
|
||||
case DW_ExprOp_ConstType: // pushes a constant - but refers into DWARF debug info to specify the type. we don't have that, need to figure out how to preserve mapping from DW type ID -> RDI type, if we care
|
||||
case DW_ExprOp_DerefType: // same as above - refers to DWARF debug info
|
||||
case DW_ExprOp_RegvalType: // same as above - refers to DWARF debug info
|
||||
case DW_ExprOp_Piece: // pieces - used to stitch multiple sub-values together
|
||||
case DW_ExprOp_BitPiece: // pieces - used to stitch multiple sub-values together
|
||||
case DW_ExprOp_XDeref: // two entries popped from stack - second one is 'address space identifier'. not possible in this layer right now
|
||||
case DW_ExprOp_XDerefSize: // does multiple address spaces
|
||||
case DW_ExprOp_XDerefType: // refers to DWARF debug info, *and* does multiple address spaces
|
||||
case DW_ExprOp_PushObjectAddress: // pushes "the address of the object currently being evaluated" ???
|
||||
case DW_ExprOp_ImplicitPointer: // refers to DWARF debug info
|
||||
default:
|
||||
{
|
||||
done = 1;
|
||||
result.status = DW_EvalStatus_UnsupportedOp;
|
||||
}break;
|
||||
|
||||
//- rjf: address ops
|
||||
case DW_ExprOp_Deref:{deref_read_size = byte_size_from_arch(arch);}goto deref;
|
||||
case DW_ExprOp_DerefSize:{deref_read_size = operands[0].u512.u64[0];}goto deref;
|
||||
deref:;
|
||||
{
|
||||
U64 vaddr = popped_vals[0].u512.u64[0];
|
||||
U64 read_size = Min(deref_read_size, sizeof(push_vals[0].u512));
|
||||
Rng1U64 read_vaddr_range = r1u64(vaddr, vaddr+read_size);
|
||||
if(!memory_map_read(memory_map, read_vaddr_range, &push_vals[0].u512))
|
||||
{
|
||||
need_a_break = 1;
|
||||
result.status = DW_EvalStatus_FailedMemoryRead;
|
||||
result.missed_read_vaddr_range = read_vaddr_range;
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: generic constants
|
||||
case DW_ExprOp_Const1U: case DW_ExprOp_Const1S:
|
||||
case DW_ExprOp_Const2U: case DW_ExprOp_Const2S:
|
||||
case DW_ExprOp_Const4U: case DW_ExprOp_Const4S:
|
||||
case DW_ExprOp_Const8U: case DW_ExprOp_Const8S:
|
||||
case DW_ExprOp_ConstU: case DW_ExprOp_ConstS:
|
||||
case DW_ExprOp_Addr:
|
||||
{
|
||||
push_vals[0] = operands[0];
|
||||
}break;
|
||||
|
||||
//- rjf: stack ops
|
||||
case DW_ExprOp_Dup:{push_vals[0] = popped_vals[0];}break;
|
||||
case DW_ExprOp_Drop:{/* NOTE(rjf): nothing to do here - just pops */}break;
|
||||
case DW_ExprOp_Swap:{push_vals[0] = popped_vals[1]; push_vals[1] = popped_vals[0];}break;
|
||||
case DW_ExprOp_Rot: {push_vals[0] = popped_vals[0]; push_vals[1] = popped_vals[1]; push_vals[2] = popped_vals[2];}break;
|
||||
case DW_ExprOp_Over:{pick_target_idx = 1;}break;
|
||||
case DW_ExprOp_Pick:{pick_target_idx = operands[0].u512.u64[0];}goto pick_stack_val;
|
||||
pick_stack_val:;
|
||||
{
|
||||
U64 idx = 0;
|
||||
for(DW_EvalValNode *n = state->top_val; n != 0; n = n->next, idx += 1)
|
||||
{
|
||||
if(idx == pick_target_idx)
|
||||
{
|
||||
push_vals[0] = n->v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: arithmetic ops
|
||||
#define UniOpU(k, op) case k:{push_vals[0].u512.u64[0] = op(popped_vals[0].u512.u64[0]);}break
|
||||
#define UniOpS(k, op) case k:{push_vals[0].s64 = op(popped_vals[0].s64);}break
|
||||
#define BinOpS(k, op) case k:{push_vals[0].s64 = popped_vals[1].s64 op popped_vals[0].s64;}break
|
||||
#define BinOpU(k, op) case k:{push_vals[0].u512.u64[0] = popped_vals[1].u512.u64[0] op popped_vals[0].u512.u64[0];}break
|
||||
#define BinOpDiv(k, op) case k:if(popped_vals[0].u512.u64[0] != 0){push_vals[0].u512.u64[0] = popped_vals[1].u512.u64[0] op popped_vals[0].u512.u64[0];}break
|
||||
UniOpS(DW_ExprOp_Abs, abs_s64);
|
||||
UniOpS(DW_ExprOp_Neg, -);
|
||||
UniOpU(DW_ExprOp_Not, !);
|
||||
BinOpU(DW_ExprOp_Minus, -);
|
||||
BinOpU(DW_ExprOp_Mul, *);
|
||||
BinOpU(DW_ExprOp_Plus, +);
|
||||
BinOpU(DW_ExprOp_Shl, <<);
|
||||
BinOpU(DW_ExprOp_Shr, >>);
|
||||
BinOpU(DW_ExprOp_And, &);
|
||||
BinOpU(DW_ExprOp_Or, |);
|
||||
BinOpU(DW_ExprOp_Xor, ^);
|
||||
BinOpS(DW_ExprOp_Shra, >>);
|
||||
BinOpDiv(DW_ExprOp_Div, /);
|
||||
BinOpDiv(DW_ExprOp_Mod, %);
|
||||
BinOpU(DW_ExprOp_Eq, ==);
|
||||
BinOpU(DW_ExprOp_Ne, !=);
|
||||
BinOpS(DW_ExprOp_Ge, >=);
|
||||
BinOpS(DW_ExprOp_Gt, >);
|
||||
BinOpS(DW_ExprOp_Le, <=);
|
||||
BinOpS(DW_ExprOp_Lt, <);
|
||||
#undef UniOpU
|
||||
#undef UniOpS
|
||||
#undef BinOpS
|
||||
#undef BinOpU
|
||||
#undef BinOpDiv
|
||||
case DW_ExprOp_PlusUConst:
|
||||
{
|
||||
push_vals[0].u512.u64[0] = popped_vals[0].u512.u64[0] + operands[0].u512.u64[0];
|
||||
}break;
|
||||
|
||||
//- rjf: jumps/branches
|
||||
case DW_ExprOp_Bra:
|
||||
{
|
||||
if(popped_vals[0].u512.u64[0] == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} // fallthrough
|
||||
case DW_ExprOp_Skip:
|
||||
{
|
||||
S64 jump_delta = operands[0].s64;
|
||||
if((jump_delta < 0 && -jump_delta > off) || (off + jump_delta >= expr.size))
|
||||
{
|
||||
done = 1;
|
||||
result.status = DW_EvalStatus_Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
off += jump_delta;
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: literals
|
||||
case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: case DW_ExprOp_Lit3:
|
||||
case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: case DW_ExprOp_Lit6: case DW_ExprOp_Lit7:
|
||||
case DW_ExprOp_Lit8: case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11:
|
||||
case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: case DW_ExprOp_Lit15:
|
||||
case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: case DW_ExprOp_Lit18: case DW_ExprOp_Lit19:
|
||||
case DW_ExprOp_Lit20: case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23:
|
||||
case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: case DW_ExprOp_Lit27:
|
||||
case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: case DW_ExprOp_Lit30: case DW_ExprOp_Lit31:
|
||||
{
|
||||
U8 val = (opcode - DW_ExprOp_Lit0);
|
||||
push_vals[0].u512.u8[0] = val;
|
||||
}break;
|
||||
|
||||
//- rjf: register reads (opcode-encoded reg)
|
||||
case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: case DW_ExprOp_Reg3:
|
||||
case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: case DW_ExprOp_Reg6: case DW_ExprOp_Reg7:
|
||||
case DW_ExprOp_Reg8: case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11:
|
||||
case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: case DW_ExprOp_Reg15:
|
||||
case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: case DW_ExprOp_Reg18: case DW_ExprOp_Reg19:
|
||||
case DW_ExprOp_Reg20: case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23:
|
||||
case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: case DW_ExprOp_Reg27:
|
||||
case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: case DW_ExprOp_Reg30: case DW_ExprOp_Reg31:
|
||||
{reg_code_dw = (opcode - DW_ExprOp_Reg0);}goto reg_read;
|
||||
case DW_ExprOp_RegX:
|
||||
{reg_code_dw = operands[0].u512.u64[0];}goto reg_read;
|
||||
reg_read:;
|
||||
{
|
||||
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_code_dw);
|
||||
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
|
||||
U64 read_size = dim_1u16(reg_rng);
|
||||
read_size = Min(read_size, sizeof(push_vals[0].u512));
|
||||
reg_rng.max = reg_rng.min + read_size;
|
||||
arch_reg_block_read_range(arch_info, regs, reg_rng, &push_vals[0].u512);
|
||||
}break;
|
||||
|
||||
//- rjf: register reads (opcode-encoded reg + offset)
|
||||
case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: case DW_ExprOp_BReg3:
|
||||
case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: case DW_ExprOp_BReg6: case DW_ExprOp_BReg7:
|
||||
case DW_ExprOp_BReg8: case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11:
|
||||
case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: case DW_ExprOp_BReg15:
|
||||
case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: case DW_ExprOp_BReg18: case DW_ExprOp_BReg19:
|
||||
case DW_ExprOp_BReg20: case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23:
|
||||
case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: case DW_ExprOp_BReg27:
|
||||
case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: case DW_ExprOp_BReg30: case DW_ExprOp_BReg31:
|
||||
{reg_code_dw = (opcode - DW_ExprOp_BReg0);}goto based_reg_read;
|
||||
case DW_ExprOp_BRegX:
|
||||
{reg_code_dw = operands[0].u512.u64[0];}goto based_reg_read;
|
||||
based_reg_read:;
|
||||
{
|
||||
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_code_dw);
|
||||
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
|
||||
U64 read_size = dim_1u16(reg_rng);
|
||||
read_size = Min(read_size, sizeof(push_vals[0].u512));
|
||||
reg_rng.max = reg_rng.min + read_size;
|
||||
arch_reg_block_read_range(arch_info, regs, reg_rng, &push_vals[0].u512);
|
||||
push_vals[0].u512.u64[0] += operands[0].s64;
|
||||
}break;
|
||||
|
||||
//- rjf: frame base register read
|
||||
case DW_ExprOp_FBReg:
|
||||
{
|
||||
push_vals[0].u512.u64[0] = (U64)(frame_base + operands[0].s64);
|
||||
}break;
|
||||
|
||||
//- rjf: TLS
|
||||
case DW_ExprOp_FormTlsAddress:
|
||||
{
|
||||
U64 tls_off = popped_vals[0].u512.u64[0];
|
||||
U64 tls_addr = tls + tls_off;
|
||||
push_vals[0].u512.u64[0] = tls_addr;
|
||||
}break;
|
||||
|
||||
//- rjf: call frame CFA
|
||||
case DW_ExprOp_CallFrameCfa:
|
||||
{
|
||||
push_vals[0].u512.u64[0] = cfa;
|
||||
}break;
|
||||
|
||||
//- rjf: implicit location descriptions (value is known, location is not)
|
||||
case DW_ExprOp_ImplicitValue:
|
||||
{
|
||||
push_vals[0] = operands[0];
|
||||
}break;
|
||||
case DW_ExprOp_StackValue:
|
||||
{
|
||||
// NOTE(rjf): nothing to do here - program is over, value (but not location) has
|
||||
// been evaluated and exists as the top entry on the stack.
|
||||
}break;
|
||||
|
||||
//- rjf: conversions
|
||||
case DW_ExprOp_Convert:
|
||||
case DW_ExprOp_Reinterpret:
|
||||
{
|
||||
if(operands[0].u512.u64[0] == 0)
|
||||
{
|
||||
push_vals[0] = popped_vals[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE(rjf): with a nonzero operand, it is expecting us to read into the
|
||||
// DWARF debug info and push as that base type. we do not have access to that
|
||||
// in the general case here, and we need to figure out how to preserve that info
|
||||
// if we care.
|
||||
done = 1;
|
||||
result.status = DW_EvalStatus_UnsupportedOp;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
|
||||
//- rjf: do pushes
|
||||
if(!done && !need_a_break)
|
||||
{
|
||||
push_count = Min(push_count, ArrayCount(push_vals));
|
||||
for(U8 push_idx = 0; push_idx < push_count; push_idx += 1)
|
||||
{
|
||||
DW_EvalValNode *n = state->free_val;
|
||||
if(n != 0)
|
||||
{
|
||||
SLLStackPop(state->free_val);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = push_array(arena, DW_EvalValNode, 1);
|
||||
}
|
||||
n->v = push_vals[push_idx];
|
||||
SLLStackPush(state->top_val, n);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: do not need a break? advance state.
|
||||
//
|
||||
// (if we *do* need a break, this means we need to ask the caller for
|
||||
// more info, like memory reads, and so we want to resume from the
|
||||
// offset just before this opcode)
|
||||
//
|
||||
if(!need_a_break)
|
||||
{
|
||||
state->op_idx += 1;
|
||||
state->off = off;
|
||||
}
|
||||
|
||||
//- rjf: at the end of the expression? -> set success, fill result
|
||||
if(off == expr.size)
|
||||
{
|
||||
result.status = DW_EvalStatus_Good;
|
||||
if(state->top_val != 0)
|
||||
{
|
||||
result.val = state->top_val->v;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: did not advance? -> error
|
||||
if(off == start_off)
|
||||
{
|
||||
result.status = DW_EvalStatus_Error;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DWARF_EXPR_2_H
|
||||
#define DWARF_EXPR_2_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evaluation Values
|
||||
|
||||
typedef struct DW_EvalVal DW_EvalVal;
|
||||
struct DW_EvalVal
|
||||
{
|
||||
union
|
||||
{
|
||||
U512 u512;
|
||||
S64 s64;
|
||||
};
|
||||
String8 data;
|
||||
};
|
||||
|
||||
typedef struct DW_EvalValNode DW_EvalValNode;
|
||||
struct DW_EvalValNode
|
||||
{
|
||||
DW_EvalValNode *next;
|
||||
DW_EvalVal v;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evaluation Results
|
||||
|
||||
typedef enum DW_EvalStatus
|
||||
{
|
||||
DW_EvalStatus_Error,
|
||||
DW_EvalStatus_FailedMemoryRead,
|
||||
DW_EvalStatus_ExecOpLimitReached,
|
||||
DW_EvalStatus_UnsupportedOp,
|
||||
DW_EvalStatus_Good,
|
||||
}
|
||||
DW_EvalStatus;
|
||||
|
||||
typedef struct DW_Eval DW_Eval;
|
||||
struct DW_Eval
|
||||
{
|
||||
DW_EvalVal val;
|
||||
DW_EvalStatus status;
|
||||
Rng1U64 missed_read_vaddr_range;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evaluation State Machine
|
||||
|
||||
typedef struct DW_EvalState DW_EvalState;
|
||||
struct DW_EvalState
|
||||
{
|
||||
U64 off;
|
||||
U64 op_idx;
|
||||
DW_EvalValNode *top_val;
|
||||
DW_EvalValNode *free_val;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Expression Evaluation Functions
|
||||
|
||||
internal DW_Eval dw_eval(Arena *arena, DW_Format fmt, Arch arch, MemoryMap *memory_map, void *regs, U64 frame_base, U64 cfa, U64 tls, DW_EvalState *state, String8 expr, U64 op_idx_cap);
|
||||
|
||||
#endif // DWARF_EXPR_2_H
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal DW_CallFrameInfo
|
||||
dw_call_frame_info_from_data(Arena *arena, Arch arch, U64 rebase, String8 debug_frame)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
// count CIE and FDE entries
|
||||
U64 cie_count = 0, fde_count = 0;
|
||||
for (U64 cursor = 0, desc_size; cursor < debug_frame.size; cursor += desc_size) {
|
||||
DW_DescriptorEntry desc = {0};
|
||||
desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc);
|
||||
if (desc_size == 0) { break; }
|
||||
if (desc.type == DW_DescriptorEntryType_CIE) {
|
||||
cie_count += 1;
|
||||
} else if (desc.type == DW_DescriptorEntryType_FDE) {
|
||||
fde_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// parse CIEs and build (offset -> CIE) hash table
|
||||
HashTable *cie_ht = hash_table_init(scratch.arena, (U64)(cie_count * 1.3));
|
||||
DW_CIE *cie = push_array(arena, DW_CIE, cie_count);
|
||||
U64 parse_cie_count = 0;
|
||||
for (U64 cursor = 0, desc_size; cursor < debug_frame.size; cursor += desc_size) {
|
||||
DW_DescriptorEntry desc = {0};
|
||||
desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc);
|
||||
if (desc_size == 0) { break; }
|
||||
if (desc.type == DW_DescriptorEntryType_CIE) {
|
||||
if (dw_parse_cie(str8_skip(debug_frame, cursor), desc.format, arch, &cie[parse_cie_count])) {
|
||||
hash_table_push_u64_raw(scratch.arena, cie_ht, cursor, &cie[parse_cie_count]);
|
||||
parse_cie_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse FDEs
|
||||
DW_FDE *fde = push_array(arena, DW_FDE, fde_count);
|
||||
U64 parse_fde_count = 0;
|
||||
for (U64 cursor = 0, desc_size; cursor < debug_frame.size; cursor += desc_size) {
|
||||
DW_DescriptorEntry desc = {0};
|
||||
desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc);
|
||||
if (desc_size == 0) { break; }
|
||||
if (desc.type == DW_DescriptorEntryType_FDE) {
|
||||
DW_CIE *cie = hash_table_search_u64_raw(cie_ht, desc.cie_pointer);
|
||||
if (dw_parse_fde(str8_skip(debug_frame, cursor), desc.format, cie, &fde[parse_fde_count])) {
|
||||
fde[parse_fde_count].pc_range.min += rebase;
|
||||
fde[parse_fde_count].pc_range.max += rebase;
|
||||
parse_fde_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fill out result
|
||||
DW_CallFrameInfo cfi = {0};
|
||||
cfi.cie_count = parse_cie_count;
|
||||
cfi.fde_count = parse_fde_count;
|
||||
cfi.cie = cie;
|
||||
cfi.fde = fde;
|
||||
|
||||
scratch_end(scratch);
|
||||
return cfi;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DWARF_HELP_H
|
||||
#define DWARF_HELP_H
|
||||
|
||||
typedef struct DW_CallFrameInfo
|
||||
{
|
||||
U64 cie_count;
|
||||
U64 fde_count;
|
||||
DW_CIE *cie;
|
||||
DW_FDE *fde;
|
||||
} DW_CallFrameInfo;
|
||||
|
||||
internal DW_CallFrameInfo dw_call_frame_info_from_data(Arena *arena, Arch arch, U64 rebase, String8 debug_frame);
|
||||
|
||||
#endif // DWARF_HELP_H
|
||||
|
||||
+16
-12
@@ -2,17 +2,21 @@
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "dwarf/dwarf.c"
|
||||
#include "dwarf/dwarf_parse.c"
|
||||
#include "dwarf/dwarf_expr.c"
|
||||
#include "dwarf/dwarf_coff.c"
|
||||
#include "dwarf/dwarf_elf.c"
|
||||
#include "dwarf/dwarf_unwind.c"
|
||||
#include "dwarf/dwarf_dump.c"
|
||||
#include "dwarf/dwarf_help.c"
|
||||
#include "dwarf/dwarf_writer.c"
|
||||
// #include "dwarf/dwarf_parse.c"
|
||||
// #include "dwarf/dwarf_expr.c"
|
||||
#include "dwarf/dwarf_expr_2.c"
|
||||
// #include "dwarf/dwarf_unwind.c"
|
||||
// #include "dwarf/dwarf_dump.c"
|
||||
#include "dwarf/dwarf_parse_2.c"
|
||||
#include "dwarf/eh_frame.c"
|
||||
#include "dwarf/eh_dump.c"
|
||||
#if defined(X64_H)
|
||||
# include "dwarf/x64/dwarf_x64.c"
|
||||
#include "dwarf/dwarf_unwind_2.c"
|
||||
#include "dwarf/dwarf_dump_2.c"
|
||||
#if defined(COFF_H)
|
||||
# include "dwarf/dwarf_parse_coff.c"
|
||||
#endif
|
||||
#if defined(ELF_H)
|
||||
# include "dwarf/dwarf_parse_elf.c"
|
||||
#endif
|
||||
|
||||
#if 0 // TODO(rjf): this uses concepts from the old parser
|
||||
# include "dwarf/dwarf_writer.c"
|
||||
#endif
|
||||
+16
-12
@@ -5,19 +5,23 @@
|
||||
#define DWARF_INC_H
|
||||
|
||||
#include "dwarf/dwarf.h"
|
||||
#include "dwarf/dwarf_parse.h"
|
||||
#include "dwarf/dwarf_expr.h"
|
||||
#include "dwarf/dwarf_coff.h"
|
||||
#include "dwarf/dwarf_elf.h"
|
||||
#include "dwarf/dwarf_unwind.h"
|
||||
#include "dwarf/dwarf_dump.h"
|
||||
#include "dwarf/dwarf_help.h"
|
||||
#include "dwarf/dwarf_writer.h"
|
||||
// #include "dwarf/dwarf_parse.h"
|
||||
// #include "dwarf/dwarf_expr.h"
|
||||
#include "dwarf/dwarf_expr_2.h"
|
||||
// #include "dwarf/dwarf_unwind.h"
|
||||
// #include "dwarf/dwarf_dump.h"
|
||||
#include "dwarf/dwarf_parse_2.h"
|
||||
#include "dwarf/eh_frame.h"
|
||||
#include "dwarf/eh_dump.h"
|
||||
#if defined(X64_H)
|
||||
# include "dwarf/x64/dwarf_x64.h"
|
||||
#include "dwarf/dwarf_unwind_2.h"
|
||||
#include "dwarf/dwarf_dump_2.h"
|
||||
#if defined(COFF_H)
|
||||
# include "dwarf/dwarf_parse_coff.h"
|
||||
#endif
|
||||
#if defined(ELF_H)
|
||||
# include "dwarf/dwarf_parse_elf.h"
|
||||
#endif
|
||||
|
||||
#if 0 // TODO(rjf): this uses concepts from the old parser
|
||||
# include "dwarf/dwarf_writer.h"
|
||||
#endif
|
||||
|
||||
#endif // DWARF_INC_H
|
||||
@@ -1,42 +0,0 @@
|
||||
--- DWARF NOTES ---------------------------------------------------------------
|
||||
|
||||
DWARF V4 Spec: http://www.dwarfstd.org/doc/DWARF4.pdf
|
||||
DWARF V5 Spec: http://www.dwarfstd.org/doc/DWARF5.pdf
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
$ (2021/04/30) On .debug_pubtypes, .debug_pubnames, and .debug_names:
|
||||
|
||||
.debug_pubtypes and .debug_pubnames are tables that map from a string (the name
|
||||
of a type or function respectively) to an offset into .debug_info, which is the
|
||||
offset of the Debug Information Entry (DIE, in DWARF terminology) of the info
|
||||
associated with the string. THESE TWO SECTIONS ARE OPTIONAL. They don't show up
|
||||
in every DWARF-holding file, and so they cannot be relied upon as acceleration
|
||||
structures. But we're going to support parsing them, to make things a bit nicer
|
||||
in cases where they are present. DWARF doesn't have much in the way of acceler-
|
||||
ation structures built in, so our rationale is that we should take anything we
|
||||
can get to make the format a bit more in some subset of the possible cases.
|
||||
|
||||
.debug_names is a DWARF V5 section that is intended to replace .debug_pubtypes
|
||||
and .debug_pubnames. However, even in cases when DWARF V5 is produced at the
|
||||
time of writing this, we have not found .debug_names sections being produced.
|
||||
We did not exhaustively test all compilers and configurations, but it seems
|
||||
that it is not well-supported at all by major compilers, and there's a very low
|
||||
probability that a user will have that section, so our current thinking is
|
||||
that there's no point in supporting it right now.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
$ (2021/04/30) On producing DWARF V5 with Clang:
|
||||
|
||||
https://lists.llvm.org/pipermail/llvm-dev/2018-August/125068.html
|
||||
|
||||
By default it looks like (at the time of writing this) that Clang, by default,
|
||||
will produce DWARF V4. To produce DWARF V5, however, you can use the -gdwarf-5
|
||||
option. Even when that option is used, it seems that some features of V5 are
|
||||
not used (for example, .debug_names).
|
||||
|
||||
The above link also says that this will produce .debug_names, but it doesn't as
|
||||
of Clang 10.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
+3
-11
@@ -53,18 +53,14 @@ str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out)
|
||||
{
|
||||
U8 byte = 0;
|
||||
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
|
||||
|
||||
if(bytes_read != sizeof(byte))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
U8 val = byte & 0x7fu;
|
||||
value |= ((U64)val) << shift;
|
||||
|
||||
cursor += bytes_read;
|
||||
shift += 7u;
|
||||
|
||||
if((byte & 0x80u) == 0)
|
||||
{
|
||||
break;
|
||||
@@ -92,13 +88,10 @@ str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
U8 val = byte & 0x7fu;
|
||||
value |= ((U64)val) << shift;
|
||||
|
||||
cursor += bytes_read;
|
||||
shift += 7u;
|
||||
|
||||
if((byte & 0x80u) == 0)
|
||||
{
|
||||
if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0)
|
||||
@@ -2912,7 +2905,7 @@ dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc
|
||||
|
||||
U64 id_type = format == DW_Format_32Bit ? max_U32 : max_U64;
|
||||
desc_out->format = format;
|
||||
desc_out->type = (id == id_type) ? DW_DescriptorEntryType_CIE : DW_DescriptorEntryType_FDE;
|
||||
desc_out->type = (id == id_type) ? DW_DescriptorEntryKind_CIE : DW_DescriptorEntryKind_FDE;
|
||||
desc_out->entry_range = entry_range;
|
||||
desc_out->cie_pointer = id;
|
||||
desc_out->cie_pointer_off = length_size;
|
||||
@@ -2952,7 +2945,6 @@ dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out)
|
||||
TryRead(str8_deserial_read_sleb128(data, cursor, &data_align_factor), cursor, exit);
|
||||
|
||||
U64 ret_addr_reg = 0;
|
||||
U64 ret_addr_reg_size = 0;
|
||||
if (version == DW_Version_1) { TryRead(str8_deserial_read(data, cursor, &ret_addr_reg, sizeof(U8), sizeof(U8)), cursor, exit); }
|
||||
else { TryRead(str8_deserial_read_uleb128(data, cursor, &ret_addr_reg), cursor, exit); }
|
||||
|
||||
@@ -3012,14 +3004,14 @@ dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *f
|
||||
B32 is_parsed = 0;
|
||||
DW_DescriptorEntry fde_desc = {0};
|
||||
dw_parse_descriptor_entry_header(data, fde_offset, &fde_desc);
|
||||
if (fde_desc.type == DW_DescriptorEntryType_FDE) {
|
||||
if (fde_desc.type == DW_DescriptorEntryKind_FDE) {
|
||||
U64 cie_pointer_off = fde_desc.format == DW_Format_32Bit ? 4 : 12;
|
||||
U64 cie_pointer = 0;
|
||||
U64 cie_pointer_size = str8_deserial_read_dwarf_uint(data, fde_offset + cie_pointer_off, fde_desc.format, &cie_pointer);
|
||||
if (cie_pointer_size) {
|
||||
DW_DescriptorEntry cie_desc = {0};
|
||||
dw_parse_descriptor_entry_header(data, cie_pointer, &cie_desc);
|
||||
if (cie_desc.type == DW_DescriptorEntryType_CIE) {
|
||||
if (cie_desc.type == DW_DescriptorEntryKind_CIE) {
|
||||
if (dw_parse_cie(str8_substr(data, cie_desc.entry_range), cie_desc.format, arch, cie_out)) {
|
||||
if (dw_parse_fde(str8_substr(data, fde_desc.entry_range), fde_desc.format, cie_out, fde_out)) {
|
||||
is_parsed = 1;
|
||||
|
||||
@@ -335,22 +335,6 @@ typedef struct DW_Expr
|
||||
////////////////////////////////
|
||||
// .debug_frame
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DW_DescriptorEntryType_Null,
|
||||
DW_DescriptorEntryType_CIE,
|
||||
DW_DescriptorEntryType_FDE
|
||||
} DW_DescriptorEntryType;
|
||||
|
||||
typedef struct DW_DescriptorEntry
|
||||
{
|
||||
DW_DescriptorEntryType type;
|
||||
DW_Format format;
|
||||
Rng1U64 entry_range;
|
||||
U64 cie_pointer_off;
|
||||
U64 cie_pointer;
|
||||
} DW_DescriptorEntry;
|
||||
|
||||
typedef struct DW_CIE
|
||||
{
|
||||
String8 insts;
|
||||
@@ -418,8 +402,6 @@ internal U64 dw_hash_from_string(String8 string);
|
||||
|
||||
internal U64 str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_out);
|
||||
internal U64 str8_deserial_read_dwarf_uint (String8 string, U64 off, DW_Format format, U64 *uint_out);
|
||||
internal U64 str8_deserial_read_uleb128 (String8 string, U64 off, U64 *value_out);
|
||||
internal U64 str8_deserial_read_sleb128 (String8 string, U64 off, S64 *value_out);
|
||||
internal U64 str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_out);
|
||||
internal U64 str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out);
|
||||
|
||||
|
||||
+611
-122
File diff suppressed because it is too large.
Load diff
+172
-7
@@ -4,6 +4,23 @@
|
||||
#ifndef DWARF_PARSE_2_H
|
||||
#define DWARF_PARSE_2_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Raw Section Data
|
||||
|
||||
typedef struct DW_Section DW_Section;
|
||||
struct DW_Section
|
||||
{
|
||||
String8 name;
|
||||
String8 data;
|
||||
};
|
||||
|
||||
typedef struct DW_Raw DW_Raw;
|
||||
struct DW_Raw
|
||||
{
|
||||
DW_Section sec[DW_SectionKind_COUNT];
|
||||
DW_Section sup[DW_SectionKind_COUNT];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unit Headers
|
||||
|
||||
@@ -21,6 +38,37 @@ struct DW2_UnitHeader
|
||||
////////////////////////////////
|
||||
//~ rjf: Abbreviation Map (ID -> .debug_abbrev Offset)
|
||||
|
||||
typedef struct DW2_AbbrevAttrib DW2_AbbrevAttrib;
|
||||
struct DW2_AbbrevAttrib
|
||||
{
|
||||
DW_AttribKind attrib_kind;
|
||||
DW_FormKind form_kind;
|
||||
U64 implicit_const;
|
||||
};
|
||||
|
||||
typedef struct DW2_AbbrevAttribNode DW2_AbbrevAttribNode;
|
||||
struct DW2_AbbrevAttribNode
|
||||
{
|
||||
DW2_AbbrevAttribNode *next;
|
||||
DW2_AbbrevAttrib v;
|
||||
};
|
||||
|
||||
typedef struct DW2_AbbrevAttribList DW2_AbbrevAttribList;
|
||||
struct DW2_AbbrevAttribList
|
||||
{
|
||||
DW2_AbbrevAttribNode *first;
|
||||
DW2_AbbrevAttribNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DW2_AbbrevHeader DW2_AbbrevHeader;
|
||||
struct DW2_AbbrevHeader
|
||||
{
|
||||
U64 id;
|
||||
DW_TagKind tag_kind;
|
||||
B8 has_children;
|
||||
};
|
||||
|
||||
typedef struct DW2_AbbrevMapNode DW2_AbbrevMapNode;
|
||||
struct DW2_AbbrevMapNode
|
||||
{
|
||||
@@ -36,6 +84,14 @@ struct DW2_AbbrevMap
|
||||
U64 slots_count;
|
||||
};
|
||||
|
||||
typedef struct DW2_UnitAbbrevMapMap DW2_UnitAbbrevMapMap;
|
||||
struct DW2_UnitAbbrevMapMap
|
||||
{
|
||||
U64 map_count;
|
||||
DW2_AbbrevMap *map_from_idx_table;
|
||||
DW2_AbbrevMap **map_from_unit_idx_table;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Offset Tables (.debug_str_offsets, .debug_rnglists)
|
||||
|
||||
@@ -51,18 +107,55 @@ struct DW2_OffsetTable
|
||||
void *entries;
|
||||
};
|
||||
|
||||
typedef struct DW2_OffsetTableNode DW2_OffsetTableNode;
|
||||
struct DW2_OffsetTableNode
|
||||
{
|
||||
DW2_OffsetTableNode *next;
|
||||
DW2_OffsetTable v;
|
||||
Rng1U64 range;
|
||||
};
|
||||
|
||||
typedef struct DW2_OffsetTableList DW2_OffsetTableList;
|
||||
struct DW2_OffsetTableList
|
||||
{
|
||||
DW2_OffsetTableNode *first;
|
||||
DW2_OffsetTableNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DW2_OffsetTableSet DW2_OffsetTableSet;
|
||||
struct DW2_OffsetTableSet
|
||||
{
|
||||
// rjf: .debug_str_offsets
|
||||
U64 str_offsets_tables_count;
|
||||
DW2_OffsetTable *str_offsets_tables;
|
||||
Rng1U64 *str_offsets_tables_ranges;
|
||||
|
||||
// rjf: .debug_rnglists
|
||||
U64 rnglists_tables_count;
|
||||
DW2_OffsetTable *rnglists_tables;
|
||||
Rng1U64 *rnglists_tables_ranges;
|
||||
|
||||
// rjf: .debug_addr
|
||||
U64 addr_tables_count;
|
||||
DW2_OffsetTable *addr_tables;
|
||||
Rng1U64 *addr_tables_ranges;
|
||||
|
||||
// rjf: .debug_loclists
|
||||
U64 loclists_tables_count;
|
||||
DW2_OffsetTable *loclists_tables;
|
||||
Rng1U64 *loclists_tables_ranges;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parsing Context Bundle
|
||||
|
||||
typedef struct DW2_ParseCtx DW2_ParseCtx;
|
||||
struct DW2_ParseCtx
|
||||
{
|
||||
DW_Raw *raw;
|
||||
// NOTE(rjf): all subsequent fields optional - top-level code fills out whatever
|
||||
// it can from context.
|
||||
DW_Version version;
|
||||
DW_Format format;
|
||||
DW_Ext ext;
|
||||
DW_ExtFlags exts;
|
||||
U64 addr_size;
|
||||
U64 unit_base_addr;
|
||||
U64 unit_base_info_off;
|
||||
@@ -73,6 +166,7 @@ struct DW2_ParseCtx
|
||||
DW2_OffsetTable *loclists_table;
|
||||
String8 unit_dir;
|
||||
String8 unit_file;
|
||||
DW_Language language;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -229,6 +323,57 @@ struct DW2_LocList
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unwind Info
|
||||
|
||||
typedef enum DW_CFIKind
|
||||
{
|
||||
DW_CFIKind_Null,
|
||||
DW_CFIKind_CIE, // Common Information Entry
|
||||
DW_CFIKind_FDE, // Frame Description Entry
|
||||
DW_CFIKind_COUNT
|
||||
}
|
||||
DW_CFIKind;
|
||||
|
||||
typedef struct DW_CFIHeader DW_CFIHeader;
|
||||
struct DW_CFIHeader
|
||||
{
|
||||
DW_CFIKind kind;
|
||||
DW_Format fmt;
|
||||
Rng1U64 entry_range;
|
||||
U64 cie_pointer_off;
|
||||
U64 cie_pointer;
|
||||
};
|
||||
|
||||
typedef struct DW_CIE DW_CIE;
|
||||
struct DW_CIE
|
||||
{
|
||||
Rng1U64 aug_string_range;
|
||||
Rng1U64 aug_data_range;
|
||||
U64 code_align_factor;
|
||||
S64 data_align_factor;
|
||||
U64 ret_addr_reg;
|
||||
U64 ext[4];
|
||||
DW_Format format;
|
||||
U8 version;
|
||||
U8 address_size;
|
||||
U8 segment_selector_size;
|
||||
};
|
||||
|
||||
typedef struct DW_FDE DW_FDE;
|
||||
struct DW_FDE
|
||||
{
|
||||
U64 cie_pointer;
|
||||
Rng1U64 pc_range;
|
||||
};
|
||||
|
||||
typedef struct DW_CFI DW_CFI;
|
||||
struct DW_CFI
|
||||
{
|
||||
DW_CIE cie;
|
||||
DW_FDE fde;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
@@ -239,6 +384,7 @@ global read_only DW2_Attrib dw2_attrib_nil = {0};
|
||||
|
||||
internal U64 dw2_read_initial_length(String8 data, U64 off, U64 *out, DW_Format *fmt_out);
|
||||
internal U64 dw2_read_fmt_u64(String8 data, U64 off, DW_Format format, U64 *out);
|
||||
internal DW_SectionKind dw_section_kind_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unit Range Set Parsing (Top-Level .debug_info, .debug_aranges)
|
||||
@@ -253,30 +399,41 @@ internal U64 dw2_read_unit_header(String8 data, U64 off, DW2_UnitHeader *out);
|
||||
////////////////////////////////
|
||||
//~ rjf: Abbreviation Map Parsing
|
||||
|
||||
internal U64 dw2_read_abbrev(Arena *arena, String8 data, U64 off, DW2_AbbrevHeader *header_out, DW2_AbbrevAttribList *attribs_out);
|
||||
internal DW2_AbbrevMap dw2_abbrev_map_from_data(Arena *arena, String8 data, U64 off);
|
||||
internal DW2_UnitAbbrevMapMap dw2_unit_abbrev_map_map_from_data(Arena *arena, String8 data, DW2_UnitHeader *unit_headers, U64 unit_headers_count);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Form Value Parsing
|
||||
|
||||
internal U64 dw2_read_form_val(DW2_ParseCtx *ctx, String8 data, U64 off, DW_FormKind form_kind, U64 implicit_const, DW2_FormVal *out);
|
||||
internal U64 dw2_read_form_val(DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW_FormKind form_kind, U64 implicit_const, DW2_FormVal *out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Parse Context Construction
|
||||
|
||||
internal void dw2_parse_ctx_equip_unit_header(DW2_ParseCtx *ctx_out, DW2_UnitHeader *hdr, U64 unit_base_info_off);
|
||||
internal void dw2_parse_ctx_equip_unit_abbrev_map(DW2_ParseCtx *ctx_out, DW2_UnitAbbrevMapMap *map, U64 unit_idx);
|
||||
internal void dw2_parse_ctx_equip_unit_root_tag(DW2_ParseCtx *ctx_out, DW2_Tag *tag, DW2_OffsetTableSet *offset_tables);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tag Parsing
|
||||
|
||||
internal U64 dw2_read_tag(Arena *arena, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_Tag *tag_out);
|
||||
internal U64 dw2_read_tag(Arena *arena, DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_Tag *tag_out);
|
||||
internal DW2_Attrib *dw2_attrib_from_kind(DW2_Tag *tag, DW_AttribKind kind);
|
||||
internal U64 dw2_reference_info_off_from_form_val(DW2_ParseCtx *ctx, DW2_FormVal *v);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Line Table Parsing
|
||||
|
||||
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, DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_LineTableHeader *out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ 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 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);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Range List Parsing (.debug_rnglists)
|
||||
@@ -288,4 +445,12 @@ internal Rng1U64List dw2_rnglist_from_form_val(Arena *arena, DW2_ParseCtx *ctx,
|
||||
|
||||
internal DW2_LocList dw2_loclist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unwind Info Parsing (.debug_frame)
|
||||
|
||||
internal U64 dw2_read_cfi_header(String8 data, U64 off, DW_CFIHeader *cfi_header_out);
|
||||
internal U64 dw2_read_cie(String8 data, U64 off, DW_Format fmt, Arch arch, DW_CIE *cie_out);
|
||||
internal U64 dw2_read_fde(String8 data, U64 off, DW_Format fmt, Arch arch, DW_CIE *cie, DW_FDE *fde_out);
|
||||
internal B32 dw2_try_cfi_from_data(String8 data, U64 off, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out);
|
||||
|
||||
#endif // DWARF_PARSE_2_H
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal B32
|
||||
dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table)
|
||||
{
|
||||
B32 is_dwarf_present = 0;
|
||||
for EachIndex(idx, section_count)
|
||||
{
|
||||
COFF_SectionHeader *header = §ion_table[idx];
|
||||
String8 name = coff_name_from_section_header(string_table, header);
|
||||
DW_SectionKind s = dw_section_kind_from_string(name);
|
||||
is_dwarf_present = s != DW_SectionKind_Null;
|
||||
if(is_dwarf_present)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return is_dwarf_present;
|
||||
}
|
||||
|
||||
internal DW_Raw
|
||||
dw_input_from_coff_section_table(Arena *arena, String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table)
|
||||
{
|
||||
DW_Raw input = {0};
|
||||
B32 sect_status[ArrayCount(input.sec)] = {0};
|
||||
for EachIndex(idx, section_count)
|
||||
{
|
||||
COFF_SectionHeader *header = §ion_table[idx];
|
||||
Rng1U64 raw_data_range = rng_1u64(header->foff, header->vsize ? header->foff + header->vsize : header->foff + header->fsize);
|
||||
String8 name = coff_name_from_section_header(string_table, header);
|
||||
DW_SectionKind s = dw_section_kind_from_string(name);
|
||||
if(s != DW_SectionKind_Null)
|
||||
{
|
||||
if(!sect_status[s])
|
||||
{
|
||||
sect_status[s] = 1;
|
||||
DW_Section *d = &input.sec[s];
|
||||
d->name = push_str8_copy(arena, name);
|
||||
d->data = str8_substr(raw_image, raw_data_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DWARF_COFF_H
|
||||
#define DWARF_COFF_H
|
||||
#ifndef DWARF_PARSE_COFF_H
|
||||
#define DWARF_PARSE_COFF_H
|
||||
|
||||
internal B32 dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table);
|
||||
internal DW_Raw dw_input_from_coff_section_table(Arena *arena, String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table);
|
||||
|
||||
#endif // DWARF_COFF_H
|
||||
#endif // DWARF_PARSE_COFF_H
|
||||
|
||||
@@ -11,11 +11,7 @@ dw_is_dwarf_present_from_elf_bin(String8 data, ELF_Bin *bin)
|
||||
if(shdr->sh_type != ELF_ShType_ProgBits) { continue; }
|
||||
String8 name = elf_name_from_shdr64(data, bin, shdr);
|
||||
DW_SectionKind s = dw_section_kind_from_string(name);
|
||||
if(s == DW_Section_Null)
|
||||
{
|
||||
s = dw_section_dwo_kind_from_string(name);
|
||||
}
|
||||
is_dwarf_present = (s != DW_Section_Null);
|
||||
is_dwarf_present = (s != DW_SectionKind_Null);
|
||||
if(is_dwarf_present)
|
||||
{
|
||||
break;
|
||||
@@ -28,7 +24,7 @@ dw_is_dwarf_present_from_elf_bin(String8 data, ELF_Bin *bin)
|
||||
#include "third_party/sinfl/sinfl.h"
|
||||
|
||||
internal DW_Raw
|
||||
dw_input_from_elf_bin(Arena *arena, String8 data, ELF_Bin *bin)
|
||||
dw_raw_from_elf_bin(Arena *arena, String8 data, ELF_Bin *bin)
|
||||
{
|
||||
DW_Raw result = {0};
|
||||
B32 is_section_present[ArrayCount(result.sec)] = {0};
|
||||
@@ -41,14 +37,8 @@ dw_input_from_elf_bin(Arena *arena, String8 data, ELF_Bin *bin)
|
||||
String8 section_name = elf_name_from_shdr64(data, bin, shdr);
|
||||
DW_SectionKind section_kind = dw_section_kind_from_string(section_name);
|
||||
String8 section_data__maybe_compressed = str8_substr(data, r1u64(shdr->sh_offset, shdr->sh_offset + shdr->sh_size));
|
||||
B32 is_dwo = 0;
|
||||
if(section_kind == DW_Section_Null)
|
||||
{
|
||||
section_kind = dw_section_dwo_kind_from_string(section_name);
|
||||
is_dwo = (section_kind != DW_Section_Null);
|
||||
}
|
||||
|
||||
if(section_kind == DW_Section_Null) { continue; } // skip unknown sections
|
||||
if(section_kind == DW_SectionKind_Null) { continue; } // skip unknown sections
|
||||
if(is_section_present[section_kind]) { continue; } // skip duplicate sections
|
||||
|
||||
//- rjf: decompress section data if needed
|
||||
@@ -108,7 +98,6 @@ dw_input_from_elf_bin(Arena *arena, String8 data, ELF_Bin *bin)
|
||||
DW_Section *d = &result.sec[section_kind];
|
||||
d->name = push_str8_copy(arena, section_name);
|
||||
d->data = section_data__uncompressed;
|
||||
d->is_dwo = is_dwo;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DWARF_ELF_H
|
||||
#define DWARF_ELF_H
|
||||
#ifndef DWARF_PARSE_ELF_H
|
||||
#define DWARF_PARSE_ELF_H
|
||||
|
||||
internal B32 dw_is_dwarf_present_from_elf_bin(String8 raw_image, ELF_Bin *bin);
|
||||
internal DW_Raw dw_input_from_elf_bin(Arena *arena, String8 raw_image, ELF_Bin *bin);
|
||||
internal DW_Raw dw_raw_from_elf_bin(Arena *arena, String8 raw_image, ELF_Bin *bin);
|
||||
|
||||
#endif // DWARF_ELF_H
|
||||
#endif // DWARF_PARSE_ELF_H
|
||||
@@ -0,0 +1,2 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DWARF_UNWIND_2_H
|
||||
#define DWARF_UNWIND_2_H
|
||||
|
||||
typedef enum DW_UnwindRuleCode
|
||||
{
|
||||
DW_UnwindRuleCode_SameVal,
|
||||
DW_UnwindRuleCode_Undefined,
|
||||
DW_UnwindRuleCode_Off,
|
||||
DW_UnwindRuleCode_ValOff,
|
||||
DW_UnwindRuleCode_Reg,
|
||||
DW_UnwindRuleCode_Expr,
|
||||
DW_UnwindRuleCode_ValExpr,
|
||||
DW_UnwindRuleCode_Architectural,
|
||||
}
|
||||
DW_UnwindRuleCode;
|
||||
|
||||
typedef struct DW_UnwindRule DW_UnwindRule;
|
||||
struct DW_UnwindRule
|
||||
{
|
||||
DW_UnwindRuleCode code;
|
||||
DW_RegCode reg_code;
|
||||
S64 s64;
|
||||
String8 expr;
|
||||
};
|
||||
|
||||
typedef struct DW_CFIRow DW_CFIRow;
|
||||
struct DW_CFIRow
|
||||
{
|
||||
U64 base_pc_off;
|
||||
DW_UnwindRule cfa_rule;
|
||||
DW_UnwindRule *reg_rules;
|
||||
};
|
||||
|
||||
typedef struct DW_CFIRowNode DW_CFIRowNode;
|
||||
struct DW_CFIRowNode
|
||||
{
|
||||
DW_CFIRowNode *next;
|
||||
DW_CFIRow v;
|
||||
};
|
||||
|
||||
#endif // DWARF_UNWIND_2_H
|
||||
+231
-1
@@ -97,6 +97,119 @@ dw_writer_tag_chunk_list_push(Arena *arena, DW_WriterTagChunkList *list, U64 cap
|
||||
return result;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_write_to_buffer_uleb128(U8 buffer[10], U64 v)
|
||||
{
|
||||
U64 buffer_size = 0;
|
||||
U64 value = v;
|
||||
do {
|
||||
U8 byte = value & 0x7f;
|
||||
value >>= 7;
|
||||
if (value != 0) {
|
||||
byte |= 0x80;
|
||||
}
|
||||
Assert(buffer_size < 10);
|
||||
buffer[buffer_size++] = byte;
|
||||
} while (value > 0);
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_write_to_buffer_sleb128(U8 buffer[10], U64 v)
|
||||
{
|
||||
U64 buffer_size = 0;
|
||||
for (S64 value = v, more = 1; more != 0; ) {
|
||||
U8 byte = value & 0x7f;
|
||||
value >>= 7;
|
||||
U8 sign_bit = byte & 0x40;
|
||||
if ((value == 0 && sign_bit == 0) || (value == -1 && sign_bit != 0)) {
|
||||
more = 0;
|
||||
} else {
|
||||
byte |= 0x80;
|
||||
}
|
||||
Assert(buffer_size < 10);
|
||||
buffer[buffer_size++] = byte;
|
||||
}
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_write_uleb128(Arena *arena, U64 v)
|
||||
{
|
||||
U8 buffer[10];
|
||||
U64 buffer_size = dw_write_to_buffer_uleb128(buffer, v);
|
||||
return str8_copy(arena, str8(buffer, buffer_size));
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_write_sleb128(Arena *arena, S64 v)
|
||||
{
|
||||
U8 buffer[10];
|
||||
U64 buffer_size = dw_write_to_buffer_sleb128(buffer, v);
|
||||
return str8_copy(arena, str8(buffer, buffer_size));
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_size_from_uleb128(U64 v)
|
||||
{
|
||||
U8 buffer[10];
|
||||
return dw_write_to_buffer_uleb128(buffer, v);
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_size_from_sleb128(S64 v)
|
||||
{
|
||||
U8 buffer[10];
|
||||
return dw_write_to_buffer_sleb128(buffer, v);
|
||||
}
|
||||
|
||||
internal void *
|
||||
dw_serial_push_length(Arena *arena, String8List *srl, DW_Format format, U64 length)
|
||||
{
|
||||
void *result;
|
||||
if (format == DW_Format_64Bit) {
|
||||
U8 buffer[sizeof(U32) + sizeof(U64)];
|
||||
MemorySet(&buffer[0], 0xff, sizeof(U32));
|
||||
MemoryCopy(buffer + sizeof(U32), &length, sizeof(length));
|
||||
result = str8_serial_push_string(arena, srl, str8_array_fixed(buffer));
|
||||
} else {
|
||||
result = str8_serial_push_string(arena, srl, str8((U8 *)&length, sizeof(U32)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void *
|
||||
dw_serial_push_uint(Arena *arena, String8List *srl, DW_Format format, U64 v)
|
||||
{
|
||||
String8 uint;
|
||||
if (format == DW_Format_64Bit) {
|
||||
U64 *ptr = push_array(arena, U64, 1);
|
||||
*ptr = v;
|
||||
uint = str8((U8 *)ptr, sizeof(*ptr));
|
||||
} else {
|
||||
U32 *ptr = push_array(arena, U32, 1);
|
||||
*ptr = safe_cast_u32(v);
|
||||
uint = str8((U8 *)ptr, sizeof(*ptr));
|
||||
}
|
||||
return str8_serial_push_string(arena, srl, uint);
|
||||
}
|
||||
|
||||
internal void *
|
||||
dw_serial_push_uleb128(Arena *arena, String8List *srl, U64 v)
|
||||
{
|
||||
U8 buffer[10];
|
||||
U64 buffer_size = dw_write_to_buffer_uleb128(buffer, v);
|
||||
return str8_serial_push_string(arena, srl, str8(buffer, buffer_size));
|
||||
}
|
||||
|
||||
internal void *
|
||||
dw_serial_push_sleb128(Arena *arena, String8List *srl, S64 v)
|
||||
{
|
||||
U8 buffer[10];
|
||||
U64 buffer_size = dw_write_to_buffer_sleb128(buffer, v);
|
||||
return str8_serial_push_string(arena, srl, str8(buffer, buffer_size));
|
||||
}
|
||||
|
||||
internal DW_Writer *
|
||||
dw_writer_begin(DW_Format format, DW_Version version, DW_CompUnitKind cu_kind, Arch arch)
|
||||
{
|
||||
@@ -1195,7 +1308,18 @@ dw_writer_emit(DW_Writer *writer)
|
||||
str8_serial_push_struct(writer->arena, srl, &writer->line.opcode_base);
|
||||
// (12) standard_opcode_lengths
|
||||
U8 *std_op_lens = push_array(writer->arena, U8, writer->line.opcode_base - 1);
|
||||
for (U64 i = 1; i < writer->line.opcode_base; i += 1) { std_op_lens[i-1] = dw_length_from_std_opcode(i); }
|
||||
for (U64 i = 1; i < writer->line.opcode_base; i += 1)
|
||||
{
|
||||
U64 len = 0;
|
||||
switch(i)
|
||||
{
|
||||
default:{}break;
|
||||
#define X(name, code, len_) case DW_StdOpcode_##name:{len = (len_);}break;
|
||||
DW_StdOpcode_XList
|
||||
#undef X
|
||||
}
|
||||
std_op_lens[i-1] = len;
|
||||
}
|
||||
str8_serial_push_string(writer->arena, srl, str8(std_op_lens, writer->line.opcode_base - 1));
|
||||
// directory table
|
||||
str8_list_concat_in_place(srl, &dir_table_srl);
|
||||
@@ -1277,3 +1401,109 @@ dw_writer_emit_to_obj(DW_Writer *writer, OBJ *obj)
|
||||
}
|
||||
#endif
|
||||
|
||||
internal String8
|
||||
dw_encode_expr(Arena *arena, Arch arch, DW_Format format, DW_ExprEnc *encs, U64 encs_count)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8List *srl = push_array(scratch.arena, String8List, 1);
|
||||
str8_serial_begin(scratch.arena, srl);
|
||||
|
||||
HashTable *label_map = hash_table_init(scratch.arena, 128);
|
||||
|
||||
struct Fixup { U64 offset; String8 label; struct Fixup *next; };
|
||||
struct Fixup *first_fixup = 0, *last_fixup = 0;
|
||||
|
||||
for EachIndex(i, encs_count) {
|
||||
DW_ExprEnc *e = &encs[i];
|
||||
|
||||
switch (e->type) {
|
||||
case DW_ExprEncType_Null: {} break;
|
||||
case DW_ExprEncType_Op: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->op);
|
||||
} break;
|
||||
case DW_ExprEncType_U8: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->u8);
|
||||
} break;
|
||||
case DW_ExprEncType_U16: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->u16);
|
||||
} break;
|
||||
case DW_ExprEncType_U32: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->u32);
|
||||
} break;
|
||||
case DW_ExprEncType_U64: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->u64);
|
||||
} break;
|
||||
case DW_ExprEncType_S8: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->s8);
|
||||
} break;
|
||||
case DW_ExprEncType_S16: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->s16);
|
||||
} break;
|
||||
case DW_ExprEncType_S32: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->s32);
|
||||
} break;
|
||||
case DW_ExprEncType_S64: {
|
||||
str8_serial_push_struct(scratch.arena, srl, &e->s64);
|
||||
} break;
|
||||
case DW_ExprEncType_ULEB128: {
|
||||
str8_serial_push_string(scratch.arena, srl, dw_write_uleb128(scratch.arena, e->u64));
|
||||
} break;
|
||||
case DW_ExprEncType_SLEB128: {
|
||||
str8_serial_push_string(scratch.arena, srl, dw_write_sleb128(scratch.arena, e->s64));
|
||||
} break;
|
||||
case DW_ExprEncType_Addr: {
|
||||
U64 addr_size = byte_size_from_arch(arch);
|
||||
Assert(addr_size <= sizeof(e->addr));
|
||||
str8_serial_push_string(scratch.arena, srl, str8((U8 *)&e->addr, addr_size));
|
||||
} break;
|
||||
case DW_ExprEncType_Block: {
|
||||
Assert(e->block.size <= max_U8);
|
||||
str8_serial_push_u8(scratch.arena, srl, (U8)e->block.size);
|
||||
str8_serial_push_string(scratch.arena, srl, e->block);
|
||||
} break;
|
||||
case DW_ExprEncType_DwarfUInt: {
|
||||
switch (format) {
|
||||
case DW_Format_Null: {} break;
|
||||
case DW_Format_32Bit: { str8_serial_push_u32(scratch.arena, srl, e->u32); } break;
|
||||
case DW_Format_64Bit: { str8_serial_push_u64(scratch.arena, srl, e->u64); } break;
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
} break;
|
||||
case DW_ExprEncType_Label: {
|
||||
struct Fixup *fixup = push_array(scratch.arena, struct Fixup, 1);
|
||||
fixup->offset = srl->total_size;
|
||||
fixup->label = e->label;
|
||||
SLLQueuePush(first_fixup, last_fixup, fixup);
|
||||
|
||||
S16 delta_placeholder = 0;
|
||||
str8_serial_push_struct(scratch.arena, srl, &delta_placeholder);
|
||||
} break;
|
||||
case DW_ExprEncType_DeclLabel: {
|
||||
hash_table_push_string_u64(scratch.arena, label_map, e->label, srl->total_size);
|
||||
} break;
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
}
|
||||
|
||||
// finalize expression
|
||||
String8 expr = str8_serial_end(arena, srl);
|
||||
|
||||
// apply fixups
|
||||
for EachNode(fixup, struct Fixup, first_fixup) {
|
||||
U64 label_offset;
|
||||
if (!hash_table_search_string_u64(label_map, fixup->label, &label_offset)) {
|
||||
Assert(0 && "undefined label");
|
||||
continue;
|
||||
}
|
||||
|
||||
S64 delta = (S64)label_offset - (S64)fixup->offset;
|
||||
AssertAlways(min_S16 <= delta && delta <= max_S16);
|
||||
|
||||
S16 *delta_ptr = (S16 *)(expr.str + fixup->offset);
|
||||
*delta_ptr = delta;
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return expr;
|
||||
}
|
||||
@@ -245,6 +245,23 @@ typedef struct DW_Writer
|
||||
DW_WriterTagChunkList tag_chunk_list;
|
||||
} DW_Writer;
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
// Serializers
|
||||
|
||||
internal U64 dw_write_to_buffer_uleb128(U8 buffer[10], U64 v);
|
||||
internal U64 dw_write_to_buffer_sleb128(U8 buffer[10], U64 v);
|
||||
|
||||
internal String8 dw_write_uleb128(Arena *arena, U64 v);
|
||||
internal String8 dw_write_sleb128(Arena *arena, S64 v);
|
||||
internal U64 dw_size_from_uleb128(U64 v);
|
||||
internal U64 dw_size_from_sleb128(S64 v);
|
||||
|
||||
internal void * dw_serial_push_length(Arena *arena, String8List *srl, DW_Format format, U64 length);
|
||||
internal void * dw_serial_push_uint(Arena *arena, String8List *srl, DW_Format format, U64 v);
|
||||
internal void * dw_serial_push_uleb128(Arena *arena, String8List *srl, U64 v);
|
||||
internal void * dw_serial_push_sleb128(Arena *arena, String8List *srl, S64 v);
|
||||
|
||||
////////////////////////////////
|
||||
// Writer
|
||||
|
||||
@@ -334,5 +351,8 @@ internal DW_IntEnc dw_int_enc_from_uint(U64 v);
|
||||
internal U64 dw_size_from_sint(S64 v);
|
||||
internal U64 dw_size_from_uint(U64 v);
|
||||
|
||||
// encoder
|
||||
internal String8 dw_encode_expr(Arena *arena, Arch arch, DW_Format format, DW_ExprEnc *encs, U64 encs_count);
|
||||
|
||||
#endif // DWARF_WRITER_H
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal String8List
|
||||
eh_dump_list_from_data(Arena *arena, Arch arch, U64 eh_frame_hdr_vaddr, U64 eh_frame_vaddr, String8 eh_frame_hdr, String8 eh_frame, EH_DumpSubsetFlags subset_flags)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List strings = {0};
|
||||
#define dumpf(...) str8_list_pushf(arena, &strings, __VA_ARGS__)
|
||||
|
||||
EH_PtrCtx ptr_ctx = { .data_vaddr = eh_frame_hdr_vaddr };
|
||||
EH_FrameHdr hdr = eh_parse_frame_hdr(eh_frame_hdr, byte_size_from_arch(arch), &ptr_ctx);
|
||||
DW_Ext ext = DW_Ext_All;
|
||||
|
||||
if (subset_flags & EH_DumpSubsetFlag_EhFrameHdr) {
|
||||
dumpf("eh_frame_hdr:\n");
|
||||
dumpf("{\n");
|
||||
dumpf(" version: %u\n", hdr.version);
|
||||
dumpf(" eh_frame_ptr_enc: %S\n", eh_string_from_ptr_enc(scratch.arena, hdr.eh_frame_ptr_enc));
|
||||
dumpf(" table_enc: %S\n", eh_string_from_ptr_enc(scratch.arena, hdr.table_enc));
|
||||
dumpf(" fde_count: %llu\n", hdr.fde_count);
|
||||
if (hdr.eh_frame_ptr_enc != EH_PtrEnc_Omit) {
|
||||
dumpf(" eh_frame_ptr: 0x%I64x\n", hdr.eh_frame_ptr);
|
||||
}
|
||||
|
||||
dumpf(" Entries:\n");
|
||||
dumpf(" {\n");
|
||||
for (U64 cursor = 0; cursor < hdr.table.size; ) {
|
||||
U64 entry_off = cursor;
|
||||
|
||||
U64 pc = 0;
|
||||
U64 pc_size = eh_parse_ptr(hdr.table, cursor, cursor, &ptr_ctx, hdr.table_enc, &pc);
|
||||
if (pc_size == 0) { break; }
|
||||
cursor += pc_size;
|
||||
|
||||
U64 fde_addr = 0;
|
||||
U64 fde_addr_size = eh_parse_ptr(hdr.table, cursor, cursor, &ptr_ctx, hdr.table_enc, &fde_addr);
|
||||
if (fde_addr_size == 0) { break; }
|
||||
cursor += fde_addr_size;
|
||||
|
||||
U64 fde_offset = fde_addr - eh_frame_vaddr;
|
||||
dumpf(" { off=0x%04I64x, pc=0x%I64x, fde=0x%I64x }\n", entry_off, pc, fde_offset);
|
||||
}
|
||||
dumpf(" }\n");
|
||||
|
||||
dumpf("}\n");
|
||||
|
||||
}
|
||||
|
||||
if (subset_flags & EH_DumpSubsetFlag_EhFrame) {
|
||||
dumpf(".eh_frame:\n");
|
||||
dumpf("{\n");
|
||||
for (U64 cursor = 0; cursor < eh_frame.size; ) {
|
||||
DW_DescriptorEntry desc = {0};
|
||||
U64 desc_size = eh_parse_descriptor_entry_header(eh_frame, cursor, &desc);
|
||||
if (desc_size == 0) { break; }
|
||||
|
||||
switch (desc.type) {
|
||||
case DW_DescriptorEntryType_Null: break;
|
||||
case DW_DescriptorEntryType_CIE: {
|
||||
String8 cie_data = str8_substr(eh_frame, desc.entry_range);
|
||||
DW_CIE cie = {0};
|
||||
if (eh_parse_cie(cie_data, desc.format, arch, eh_frame_vaddr + cursor, &ptr_ctx, &cie)) {
|
||||
String8List init_insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, ext, cie.format, 0, &cie, eh_decode_ptr, &ptr_ctx, cie.insts);
|
||||
dumpf(" CIE: // entry range: %r\n", desc.entry_range);
|
||||
dumpf(" {\n");
|
||||
dumpf(" Format: %S\n", dw_string_from_format(desc.format));
|
||||
dumpf(" Version: %u\n", cie.version);
|
||||
dumpf(" Aug string: \"%S\"\n", cie.aug_string);
|
||||
dumpf(" Code align: %I64u\n", cie.code_align_factor);
|
||||
dumpf(" Data align: %I64d\n", cie.data_align_factor);
|
||||
dumpf(" Return addr reg: %u\n", cie.ret_addr_reg);
|
||||
if (cie.version > DW_Version_3) {
|
||||
dumpf(" Address size: %u\n", cie.address_size);
|
||||
dumpf(" Segment selector size: %u\n", cie.segment_selector_size);
|
||||
}
|
||||
dumpf(" Initial Insturction:\n");
|
||||
dumpf(" {\n");
|
||||
for EachNode(n, String8Node, init_insts_str_list.first) { dumpf(" %S\n", n->string); }
|
||||
dumpf(" }\n");
|
||||
dumpf(" }\n");
|
||||
} else {
|
||||
dumpf("ERROR: unable to parse CIE @ %I64x\n", desc.entry_range.min);
|
||||
}
|
||||
} break;
|
||||
case DW_DescriptorEntryType_FDE: {
|
||||
U64 cie_offset = desc.cie_pointer_off - desc.cie_pointer;
|
||||
|
||||
DW_CIE cie = {0};
|
||||
{
|
||||
DW_DescriptorEntry cie_desc = {0};
|
||||
eh_parse_descriptor_entry_header(eh_frame, cie_offset, &cie_desc);
|
||||
if (cie_desc.type == DW_DescriptorEntryType_CIE) {
|
||||
String8 cie_data = str8_substr(eh_frame, cie_desc.entry_range);
|
||||
eh_parse_cie(cie_data, cie_desc.format, arch, eh_frame_vaddr + cie_offset, &ptr_ctx, &cie);
|
||||
}
|
||||
}
|
||||
|
||||
String8 fde_raw = str8_substr(eh_frame, desc.entry_range);
|
||||
DW_FDE fde = {0};
|
||||
if (eh_parse_fde(fde_raw, desc.format, eh_frame_vaddr + cursor, &cie, &ptr_ctx, &fde)) {
|
||||
String8List insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, hdr.version, ext, fde.format, 0, &cie, eh_decode_ptr, &ptr_ctx, fde.insts);
|
||||
|
||||
dumpf(" FDE: // entry range: %r\n", desc.entry_range);
|
||||
dumpf(" {\n");
|
||||
{
|
||||
dumpf(" Format: %S\n", dw_string_from_format(fde.format));
|
||||
dumpf(" CIE: 0x%I64x\n", cie_offset);
|
||||
dumpf(" PC range: %r\n", fde.pc_range);
|
||||
dumpf(" Instructions:\n");
|
||||
dumpf(" {\n");
|
||||
for EachNode(n, String8Node, insts_str_list.first) { dumpf(" %S\n", n->string); }
|
||||
dumpf(" }\n");
|
||||
|
||||
dumpf(" Unwind:\n");
|
||||
dumpf(" {\n");
|
||||
DW_CFI_Unwind *cfi_unwind = dw_cfi_unwind_init(scratch.arena, arch, &cie, &fde, eh_decode_ptr, &ptr_ctx);
|
||||
do {
|
||||
String8 cfa_str = dw_string_from_cfa(scratch.arena, arch, cie.address_size, hdr.version, ext, fde.format, cfi_unwind->row->cfa);
|
||||
String8 cfi_row_str = dw_string_from_cfi_row(scratch.arena, arch, cie.address_size, hdr.version, ext, fde.format, cfi_unwind->row);
|
||||
dumpf(" { PC: 0x%I64x, CFA: %-7S, Rules: { %S }\n", cfi_unwind->pc, cfa_str, cfi_row_str);
|
||||
} while (dw_cfi_next_row(scratch.arena, cfi_unwind));
|
||||
dumpf(" }\n");
|
||||
}
|
||||
} else {
|
||||
dumpf("ERROR: unable to parse FDE @ %I64x\n", desc.entry_range.min);
|
||||
}
|
||||
dumpf(" }\n");
|
||||
} break;
|
||||
}
|
||||
|
||||
cursor += desc_size;
|
||||
}
|
||||
dumpf("}\n");
|
||||
}
|
||||
|
||||
#undef dumpf
|
||||
scratch_end(scratch);
|
||||
return strings;
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EH_FRAME_DUMP_H
|
||||
#define EH_FRAME_DUMP_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ Dump Subset Types
|
||||
|
||||
#define EH_DumpSubset_XList \
|
||||
X(EhFrameHdr, eh_frame_hdr, ".eh_frame_hdr") \
|
||||
X(EhFrame, eh_frame, ".eh_frame")
|
||||
|
||||
typedef enum EH_DumpSubset {
|
||||
#define X(name, name_lower, title) EH_DumpSubset_##name,
|
||||
EH_DumpSubset_XList
|
||||
#undef X
|
||||
} EH_DumpSubset;
|
||||
|
||||
typedef U32 EH_DumpSubsetFlags;
|
||||
enum {
|
||||
#define X(name, name_lower, title) EH_DumpSubsetFlag_##name = (1<<EH_DumpSubset_##name),
|
||||
EH_DumpSubset_XList
|
||||
#undef X
|
||||
EH_DumpSubsetFlag_All = 0xffffffff,
|
||||
};
|
||||
|
||||
read_only global String8 eh_name_lowercase_from_dump_subset_table[] =
|
||||
{
|
||||
#define X(name, name_lower, title) str8_lit_comp(#name_lower),
|
||||
EH_DumpSubset_XList
|
||||
#undef X
|
||||
};
|
||||
|
||||
read_only global String8 eh_name_title_from_dump_subset_table[] =
|
||||
{
|
||||
#define X(name, name_lower, title) str8_lit_comp(title),
|
||||
EH_DumpSubset_XList
|
||||
#undef X
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Dump Entry Point
|
||||
|
||||
internal String8List eh_dump_list_from_data(Arena *arena, Arch arch, U64 eh_frame_hdr_vaddr, U64 eh_frame_vaddr, String8 eh_frame_hdr, String8 eh_frame, EH_DumpSubsetFlags subset_flags);
|
||||
|
||||
#endif // EH_FRAME_DUMP_H
|
||||
|
||||
@@ -1,470 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U64
|
||||
eh_parse_ptr(String8 frame_base, U64 off, U64 pc, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out)
|
||||
{
|
||||
U64 ptr_off = off;
|
||||
|
||||
if (encoding == EH_PtrEnc_Omit) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// align read offset as needed
|
||||
if (encoding == EH_PtrEnc_Aligned) {
|
||||
ptr_off = AlignPow2(ptr_off, ptr_ctx->ptr_align);
|
||||
encoding = EH_PtrEnc_Ptr;
|
||||
}
|
||||
|
||||
// decode pointer value
|
||||
U64 decode_size = 0;
|
||||
U64 raw_ptr_size = 0;
|
||||
U64 raw_ptr = 0;
|
||||
switch (encoding & EH_PtrEnc_TypeMask) {
|
||||
default: { InvalidPath; } break;
|
||||
|
||||
case EH_PtrEnc_Ptr : { raw_ptr_size = 8; } goto ufixed;
|
||||
case EH_PtrEnc_UData2: { raw_ptr_size = 2; } goto ufixed;
|
||||
case EH_PtrEnc_UData4: { raw_ptr_size = 4; } goto ufixed;
|
||||
case EH_PtrEnc_UData8: { raw_ptr_size = 8; } goto ufixed;
|
||||
ufixed: {
|
||||
decode_size += str8_deserial_read(frame_base, ptr_off, &raw_ptr, raw_ptr_size, raw_ptr_size);
|
||||
} break;
|
||||
|
||||
// TODO: Signed is actually just a flag that indicates this int is negavite.
|
||||
// There shouldn't be a read for Signed.
|
||||
// For instance, (EH_PtrEnc_UData2 | EH_PtrEnc_Signed) == EH_PtrEnc_SData etc.
|
||||
case EH_PtrEnc_Signed: { raw_ptr_size = 8; } goto sfixed;
|
||||
|
||||
case EH_PtrEnc_SData2: { raw_ptr_size = 2; } goto sfixed;
|
||||
case EH_PtrEnc_SData4: { raw_ptr_size = 4; } goto sfixed;
|
||||
case EH_PtrEnc_SData8: { raw_ptr_size = 8; } goto sfixed;
|
||||
sfixed: {
|
||||
decode_size += str8_deserial_read(frame_base, ptr_off, &raw_ptr, raw_ptr_size, raw_ptr_size);
|
||||
raw_ptr = extend_sign64(raw_ptr, raw_ptr_size);
|
||||
} break;
|
||||
|
||||
case EH_PtrEnc_ULEB128: { decode_size += str8_deserial_read_uleb128(frame_base, ptr_off, &raw_ptr); } break;
|
||||
case EH_PtrEnc_SLEB128: { decode_size += str8_deserial_read_sleb128(frame_base, ptr_off, (S64*)&raw_ptr); } break;
|
||||
}
|
||||
|
||||
// apply relative bases
|
||||
if (decode_size > 0) {
|
||||
U64 ptr = raw_ptr;
|
||||
switch (encoding & EH_PtrEnc_ModifierMask) {
|
||||
case 0: break;
|
||||
case EH_PtrEnc_PcRel: { ptr = pc + raw_ptr; } break;
|
||||
case EH_PtrEnc_TextRel: { ptr = ptr_ctx->text_vaddr + raw_ptr; } break;
|
||||
case EH_PtrEnc_DataRel: { ptr = ptr_ctx->data_vaddr + raw_ptr; } break;
|
||||
case EH_PtrEnc_FuncRel: {
|
||||
Assert(!"TODO: need a sample to verify implementation");
|
||||
ptr = ptr_ctx->func_vaddr + raw_ptr;
|
||||
} break;
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
|
||||
if (ptr_out) {
|
||||
*ptr_out = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return decode_size;
|
||||
}
|
||||
|
||||
internal EH_FrameHdr
|
||||
eh_parse_frame_hdr(String8 data, U64 address_size, EH_PtrCtx *ptr_ctx)
|
||||
{
|
||||
EH_FrameHdr header = {0};
|
||||
U64 cursor = 0;
|
||||
|
||||
U64 version_size = str8_deserial_read_struct(data, cursor, &header.version);
|
||||
if (version_size == 0) { goto exit; }
|
||||
cursor += version_size;
|
||||
|
||||
if (header.version == 1) {
|
||||
U64 eh_frame_ptr_enc_size = str8_deserial_read_struct(data, cursor, &header.eh_frame_ptr_enc);
|
||||
if (eh_frame_ptr_enc_size == 0) { goto exit; }
|
||||
cursor += eh_frame_ptr_enc_size;
|
||||
|
||||
U64 fde_count_enc_size = str8_deserial_read_struct(data, cursor, &header.fde_count_enc);
|
||||
if (fde_count_enc_size == 0) { goto exit; }
|
||||
cursor += fde_count_enc_size;
|
||||
|
||||
U64 table_enc_size = str8_deserial_read_struct(data, cursor, &header.table_enc);
|
||||
if (table_enc_size == 0) { goto exit; }
|
||||
cursor += table_enc_size;
|
||||
|
||||
cursor += eh_parse_ptr(data, cursor, cursor, ptr_ctx, header.eh_frame_ptr_enc, &header.eh_frame_ptr);
|
||||
cursor += eh_parse_ptr(data, cursor, cursor, ptr_ctx, header.fde_count_enc, &header.fde_count);
|
||||
|
||||
switch (header.table_enc & EH_PtrEnc_TypeMask) {
|
||||
case EH_PtrEnc_Ptr: { header.field_byte_size = address_size; } break;
|
||||
case EH_PtrEnc_ULEB128: { InvalidPath; } break; // TODO: when loading module convert these to UData8
|
||||
case EH_PtrEnc_UData2: { header.field_byte_size = 2; } break;
|
||||
case EH_PtrEnc_UData4: { header.field_byte_size = 4; } break;
|
||||
case EH_PtrEnc_UData8: { header.field_byte_size = 8; } break;
|
||||
case EH_PtrEnc_Signed: { header.field_byte_size = address_size; } break;
|
||||
case EH_PtrEnc_SLEB128: { InvalidPath; } break; // TODO: when loading module convert these to UData8
|
||||
case EH_PtrEnc_SData2: { header.field_byte_size = 2; } break;
|
||||
case EH_PtrEnc_SData4: { header.field_byte_size = 4; } break;
|
||||
case EH_PtrEnc_SData8: { header.field_byte_size = 8; } break;
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
header.entry_byte_size = header.field_byte_size * 2;
|
||||
|
||||
header.table = str8_skip(data, cursor);
|
||||
AssertAlways(header.table.size == header.entry_byte_size * header.fde_count);
|
||||
} else {
|
||||
Assert(0 && "unknown version");
|
||||
}
|
||||
|
||||
exit:;
|
||||
return header;
|
||||
}
|
||||
|
||||
internal U64
|
||||
eh_parse_aug_data(String8 aug_string, String8 aug_data, U64 pc, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out)
|
||||
{
|
||||
// TODO:
|
||||
// Handle "eh" param, it indicates presence of EH Data field.
|
||||
// On 32bit arch it is a 4-byte and on 64-bit 8-byte value.
|
||||
// Reference: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
|
||||
// Reference doc doesn't clarify structure for EH Data though
|
||||
|
||||
U64 cursor = 0;
|
||||
|
||||
U64 aug_data_size = 0;
|
||||
EH_AugFlags aug_flags = 0;
|
||||
EH_PtrEnc lsda_encoding = EH_PtrEnc_Omit;
|
||||
EH_PtrEnc addr_encoding = EH_PtrEnc_UData8;
|
||||
EH_PtrEnc handler_encoding = EH_PtrEnc_Omit;
|
||||
U64 handler_ip = 0;
|
||||
if (str8_match(str8_prefix(aug_string, 1), str8_lit("z"), 0)) {
|
||||
cursor = str8_deserial_read_uleb128(aug_data, cursor, &aug_data_size);
|
||||
|
||||
for (U8 *ptr = aug_string.str+1; ptr < (aug_string.str+aug_string.size); ptr += 1) {
|
||||
switch (*ptr) {
|
||||
case 'L': {
|
||||
cursor += str8_deserial_read_struct(aug_data, cursor, &lsda_encoding);
|
||||
aug_flags |= EH_AugFlag_HasLSDA;
|
||||
} break;
|
||||
case 'P': {
|
||||
cursor += str8_deserial_read_struct(aug_data, cursor, &handler_encoding);
|
||||
cursor += eh_parse_ptr(aug_data, cursor, pc + cursor, ptr_ctx, handler_encoding, &handler_ip);
|
||||
aug_flags |= EH_AugFlag_HasHandler;
|
||||
} break;
|
||||
case 'R': {
|
||||
cursor += str8_deserial_read_struct(aug_data, cursor, &addr_encoding);
|
||||
aug_flags |= EH_AugFlag_HasAddrEnc;
|
||||
} break;
|
||||
case 'S': {
|
||||
aug_flags |= EH_AugFlag_SignalFrame;
|
||||
} break;
|
||||
default: { Assert(!"failed to parse augmentation string"); goto exit; } break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aug_out) {
|
||||
aug_out->handler_ip = handler_ip;
|
||||
aug_out->handler_encoding = handler_encoding;
|
||||
aug_out->lsda_encoding = handler_encoding;
|
||||
aug_out->addr_encoding = addr_encoding;
|
||||
aug_out->flags = aug_flags;
|
||||
aug_out->size = aug_data_size;
|
||||
}
|
||||
|
||||
exit:;
|
||||
U64 parse_size = cursor;
|
||||
return parse_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
eh_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out)
|
||||
{
|
||||
U32 first_four_bytes = 0;
|
||||
str8_deserial_read_struct(data, off, &first_four_bytes);
|
||||
DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit;
|
||||
|
||||
U64 length = 0;
|
||||
U64 length_size = str8_deserial_read_dwarf_packed_size(data, off, &length);
|
||||
if (length_size == 0) { goto exit; }
|
||||
|
||||
Rng1U64 entry_range = rng_1u64(off, off + length_size + length);
|
||||
String8 entry_data = str8_substr(data, entry_range);
|
||||
U64 id = 0;
|
||||
U64 id_size = str8_deserial_read_dwarf_uint(entry_data, length_size, format, &id);
|
||||
if (id_size == 0) { goto exit; }
|
||||
|
||||
desc_out->format = format;
|
||||
desc_out->type = (id == 0) ? DW_DescriptorEntryType_CIE : DW_DescriptorEntryType_FDE;
|
||||
desc_out->entry_range = entry_range;
|
||||
desc_out->cie_pointer = id;
|
||||
desc_out->cie_pointer_off = off + length_size;
|
||||
|
||||
exit:;
|
||||
return length + length_size;
|
||||
}
|
||||
|
||||
internal B32
|
||||
eh_parse_cie(String8 data, DW_Format format, Arch arch, U64 pc, EH_PtrCtx *ptr_ctx, DW_CIE *cie_out)
|
||||
{
|
||||
B32 is_parsed = 0;
|
||||
U64 cursor = format == DW_Format_32Bit ? 4 : 12;
|
||||
|
||||
U64 cie_id = 0;
|
||||
U64 cie_id_size = str8_deserial_read_dwarf_uint(data, cursor, format, &cie_id);
|
||||
if (cie_id_size == 0) { goto exit; }
|
||||
cursor += cie_id_size;
|
||||
|
||||
U8 version = 0;
|
||||
U64 version_size = str8_deserial_read_struct(data, cursor, &version);
|
||||
if (version_size == 0) { goto exit; }
|
||||
cursor += version_size;
|
||||
|
||||
String8 aug_string = {0};
|
||||
String8 aug_data = {0};
|
||||
EH_Augmentation aug = {0};
|
||||
U64 code_align_factor = 0;
|
||||
S64 data_align_factor = 0;
|
||||
U64 ret_addr_reg = max_U64;
|
||||
if (version == 1) {
|
||||
U64 aug_string_size = str8_deserial_read_cstr(data, cursor, &aug_string);
|
||||
if (aug_string_size == 0) { goto exit; }
|
||||
cursor += aug_string_size;
|
||||
|
||||
U64 eh_data = 0;
|
||||
if (str8_match(aug_string, str8_lit("eh"), 0)) {
|
||||
U64 arch_byte_size = byte_size_from_arch(arch);
|
||||
cursor += str8_deserial_read(data, cursor, &eh_data, arch_byte_size, arch_byte_size);
|
||||
}
|
||||
|
||||
U64 code_align_factor_size = str8_deserial_read_uleb128(data, cursor, &code_align_factor);
|
||||
if (code_align_factor_size == 0) { goto exit; }
|
||||
cursor += code_align_factor_size;
|
||||
|
||||
U64 data_align_factor_size = str8_deserial_read_sleb128(data, cursor, &data_align_factor);
|
||||
if (data_align_factor_size == 0) { goto exit; }
|
||||
cursor += data_align_factor_size;
|
||||
|
||||
ret_addr_reg = 0;
|
||||
U64 ret_addr_reg_size = str8_deserial_read(data, cursor, &ret_addr_reg, sizeof(U8), sizeof(U8));
|
||||
if (ret_addr_reg_size == 0) { goto exit; }
|
||||
cursor += ret_addr_reg_size;
|
||||
|
||||
U64 aug_data_size = eh_parse_aug_data(aug_string, str8_skip(data, cursor), pc + cursor, ptr_ctx, &aug);
|
||||
aug_data = str8_substr(data, r1u64(cursor, cursor + aug.size));
|
||||
cursor += aug_data_size;
|
||||
} else {
|
||||
Assert(0 && "unexpected version");
|
||||
}
|
||||
|
||||
cie_out->insts = str8_skip(data, cursor);
|
||||
cie_out->aug_string = aug_string;
|
||||
cie_out->aug_data = aug_data;
|
||||
cie_out->code_align_factor = code_align_factor;
|
||||
cie_out->data_align_factor = data_align_factor;
|
||||
cie_out->ret_addr_reg = ret_addr_reg;
|
||||
cie_out->format = format;
|
||||
cie_out->version = version;
|
||||
cie_out->address_size = byte_size_from_arch(arch);
|
||||
cie_out->segment_selector_size = 0;
|
||||
|
||||
cie_out->ext[EH_CIE_Ext_LSDAEnc] = EH_PtrEnc_Omit;
|
||||
cie_out->ext[EH_CIE_Ext_AddrEnc] = EH_PtrEnc_Omit;
|
||||
cie_out->ext[EH_CIE_Ext_HandlerEnc] = EH_PtrEnc_Omit;
|
||||
|
||||
if (aug.flags & EH_AugFlag_HasLSDA) {
|
||||
cie_out->ext[EH_CIE_Ext_LSDAEnc] = aug.lsda_encoding;
|
||||
}
|
||||
if (aug.flags & EH_AugFlag_HasAddrEnc) {
|
||||
cie_out->ext[EH_CIE_Ext_AddrEnc] = aug.addr_encoding;
|
||||
}
|
||||
if (aug.flags & EH_AugFlag_HasHandler) {
|
||||
cie_out->ext[EH_CIE_Ext_HandlerEnc] = aug.handler_encoding;
|
||||
cie_out->ext[EH_CIE_Ext_HandlerIp ] = aug.handler_ip;
|
||||
}
|
||||
|
||||
is_parsed = 1;
|
||||
exit:;
|
||||
return is_parsed;
|
||||
}
|
||||
|
||||
internal B32
|
||||
eh_parse_fde(String8 data, DW_Format format, U64 pc, DW_CIE *cie, EH_PtrCtx *ptr_ctx, DW_FDE *fde_out)
|
||||
{
|
||||
B32 is_parsed = 0;
|
||||
U64 cursor = format == DW_Format_32Bit ? 8 : 20;
|
||||
|
||||
U64 pc_begin = 0;
|
||||
U64 pc_delta = 0;
|
||||
EH_PtrEnc addr_enc = cie->ext[EH_CIE_Ext_AddrEnc];
|
||||
if (addr_enc != EH_PtrEnc_Omit) {
|
||||
U64 pc_begin_size = eh_parse_ptr(data, cursor, pc + cursor, ptr_ctx, addr_enc, &pc_begin);
|
||||
if (pc_begin_size == 0) { goto exit; }
|
||||
cursor += pc_begin_size;
|
||||
|
||||
U64 pc_delta_size = eh_parse_ptr(data, cursor, pc + cursor, ptr_ctx, addr_enc & EH_PtrEnc_TypeMask, &pc_delta);
|
||||
if (pc_delta_size == 0) { goto exit; }
|
||||
cursor += pc_delta_size;
|
||||
}
|
||||
|
||||
if (cursor + cie->aug_data.size > data.size) { goto exit; }
|
||||
cursor += cie->aug_data.size;
|
||||
|
||||
fde_out->format = format;
|
||||
fde_out->pc_range = rng_1u64(pc_begin, pc_begin + pc_delta);
|
||||
fde_out->insts = str8_skip(data, cursor);
|
||||
|
||||
is_parsed = 1;
|
||||
exit:;
|
||||
return is_parsed;
|
||||
}
|
||||
|
||||
internal U64
|
||||
eh_find_nearest_fde(EH_FrameHdr header, EH_PtrCtx *ptr_ctx, U64 pc)
|
||||
{
|
||||
U64 fde_addr = max_U64;
|
||||
U64 fde_idx = max_U64;
|
||||
|
||||
if (header.version == 1) {
|
||||
if (header.fde_count > 0) {
|
||||
U64 first = 0;
|
||||
U64 first_size = eh_parse_ptr(header.table, 0, ptr_ctx->pc_vaddr, ptr_ctx, header.table_enc, &first);
|
||||
AssertAlways(first_size);
|
||||
if (first == pc) {
|
||||
fde_idx = 0;
|
||||
goto exit;
|
||||
}
|
||||
if (first > pc) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
U64 last_off = header.table.size - header.entry_byte_size;
|
||||
U64 last = 0;
|
||||
U64 last_size = eh_parse_ptr(header.table, last_off, ptr_ctx->pc_vaddr + last_off, ptr_ctx, header.table_enc, &last);
|
||||
AssertAlways(last_size);
|
||||
if (last <= pc) {
|
||||
fde_idx = header.fde_count - 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
U64 l = 0;
|
||||
U64 r = header.fde_count - 1;
|
||||
while (l <= r) {
|
||||
U64 m = l + (r - l) / 2;
|
||||
U64 m_pc_off = m * header.entry_byte_size;
|
||||
U64 m_pc = 0;
|
||||
U64 m_pc_size = eh_parse_ptr(header.table, m_pc_off, ptr_ctx->pc_vaddr + m_pc_off, ptr_ctx, header.table_enc, &m_pc);
|
||||
Assert(m_pc_size);
|
||||
if (m_pc > pc) {
|
||||
r = m - 1;
|
||||
} else if (m_pc < pc) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
fde_idx = m;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
fde_idx = l > 0 ? l-1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
exit:;
|
||||
if (fde_idx < header.fde_count) {
|
||||
U64 fde_addr_off = (fde_idx * header.entry_byte_size) + header.field_byte_size;
|
||||
U64 fde_addr_size = eh_parse_ptr(header.table, fde_addr_off, ptr_ctx->pc_vaddr + fde_addr_off, ptr_ctx, header.table_enc, &fde_addr);
|
||||
Assert(fde_addr_size);
|
||||
}
|
||||
return fde_addr;
|
||||
}
|
||||
|
||||
internal int
|
||||
eh_frame_hdr_entry_sort(void *raw_a, void *raw_b)
|
||||
{
|
||||
return ((EH_FrameHdrEntry *)raw_a)->addr < ((EH_FrameHdrEntry *)raw_b)->addr;
|
||||
}
|
||||
|
||||
internal String8
|
||||
eh_frame_hdr_from_call_frame_info(Arena *arena, U64 fde_count, U64 *fde_offsets, DW_FDE *fde)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
// make .eh_frame_hdr
|
||||
String8List srl = {0};
|
||||
str8_serial_begin(scratch.arena, &srl);
|
||||
str8_serial_push_u8(scratch.arena, &srl, 1); // version
|
||||
str8_serial_push_u8(scratch.arena, &srl, EH_PtrEnc_Omit); // omit eh_frame_ptr field
|
||||
str8_serial_push_u8(scratch.arena, &srl, EH_PtrEnc_UData8); // fde_count encoding
|
||||
str8_serial_push_u8(scratch.arena, &srl, EH_PtrEnc_UData8); // table encoding
|
||||
str8_serial_push_u64(scratch.arena, &srl, fde_count); // fde_count
|
||||
String8 header = str8_serial_end(scratch.arena, &srl);
|
||||
|
||||
// alloc buffer for output
|
||||
U64 buffer_size = header.size + sizeof(EH_FrameHdrEntry) * fde_count;
|
||||
U8 *buffer = push_array(arena, U8, buffer_size);
|
||||
|
||||
// copy header
|
||||
MemoryCopyStr8(buffer, header);
|
||||
|
||||
// write the table
|
||||
EH_FrameHdrEntry *table = (EH_FrameHdrEntry *)(buffer + header.size);
|
||||
for EachIndex(fde_idx, fde_count) {
|
||||
table[fde_idx].addr = fde[fde_idx].pc_range.min;
|
||||
table[fde_idx].fde_offset = fde_offsets[fde_idx];
|
||||
}
|
||||
radsort(table, fde_count, eh_frame_hdr_entry_sort);
|
||||
|
||||
String8 eh_frame_hdr = str8(buffer, buffer_size);
|
||||
scratch_end(scratch);
|
||||
return eh_frame_hdr;
|
||||
}
|
||||
|
||||
internal
|
||||
DW_DECODE_PTR(eh_decode_ptr)
|
||||
{
|
||||
EH_DecodePtrCtx *ctx = ud;
|
||||
return eh_parse_ptr(data, 0, ctx->ptr_ctx->pc_vaddr, ctx->ptr_ctx, ctx->addr_enc, ptr_out);
|
||||
}
|
||||
|
||||
internal String8
|
||||
eh_string_from_ptr_enc_type(EH_PtrEnc type)
|
||||
{
|
||||
switch (type) {
|
||||
case EH_PtrEnc_Ptr: return str8_lit("Ptr");
|
||||
case EH_PtrEnc_ULEB128: return str8_lit("ULEB128");
|
||||
case EH_PtrEnc_UData2: return str8_lit("UData2");
|
||||
case EH_PtrEnc_UData4: return str8_lit("UData4");
|
||||
case EH_PtrEnc_UData8: return str8_lit("UData8");
|
||||
case EH_PtrEnc_Signed: return str8_lit("Signed");
|
||||
case EH_PtrEnc_SLEB128: return str8_lit("SLEB128");
|
||||
case EH_PtrEnc_SData2: return str8_lit("SData2");
|
||||
case EH_PtrEnc_SData4: return str8_lit("SData4");
|
||||
case EH_PtrEnc_SData8: return str8_lit("SData8");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
eh_string_from_ptr_enc_modifier(EH_PtrEnc modifier)
|
||||
{
|
||||
switch (modifier) {
|
||||
case EH_PtrEnc_PcRel: return str8_lit("PcRel");
|
||||
case EH_PtrEnc_TextRel: return str8_lit("TextRel");
|
||||
case EH_PtrEnc_DataRel: return str8_lit("DataRel");
|
||||
case EH_PtrEnc_FuncRel: return str8_lit("FuncRel");
|
||||
case EH_PtrEnc_Aligned: return str8_lit("Aligned");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
eh_string_from_ptr_enc(Arena *arena, EH_PtrEnc enc)
|
||||
{
|
||||
String8 type_str = eh_string_from_ptr_enc_type(enc & EH_PtrEnc_TypeMask);
|
||||
String8 modifer_str = eh_string_from_ptr_enc_modifier(enc & EH_PtrEnc_ModifierMask);
|
||||
String8 indir_str = enc & EH_PtrEnc_Indirect ? str8_lit("Indirect") : str8_zero();
|
||||
String8 result = str8f(arena, "Type: %S, Modifier %S (%S)", type_str, modifer_str, indir_str);
|
||||
return result;
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EH_FRAME_H
|
||||
#define EH_FRAME_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ Format
|
||||
|
||||
typedef U8 EH_PtrEnc;
|
||||
enum
|
||||
{
|
||||
EH_PtrEnc_Ptr = 0x00, // Pointer sized unsigned value
|
||||
EH_PtrEnc_ULEB128 = 0x01, // Unsigned LE base-128 value
|
||||
EH_PtrEnc_UData2 = 0x02, // Unsigned 16-bit value
|
||||
EH_PtrEnc_UData4 = 0x03, // Unsigned 32-bit value
|
||||
EH_PtrEnc_UData8 = 0x04, // Unsigned 64-bit value
|
||||
EH_PtrEnc_Signed = 0x08, // Signed pointer
|
||||
EH_PtrEnc_SLEB128 = 0x09, // Signed LE base-128 value
|
||||
EH_PtrEnc_SData2 = 0x0A, // Signed 16-bit value
|
||||
EH_PtrEnc_SData4 = 0x0B, // Signed 32-bit value
|
||||
EH_PtrEnc_SData8 = 0x0C, // Signed 64-bit value
|
||||
|
||||
EH_PtrEnc_TypeMask = 0x0F,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
EH_PtrEnc_PcRel = 0x10, // Value is relative to the current program counter.
|
||||
EH_PtrEnc_TextRel = 0x20, // Value is relative to the .text section.
|
||||
EH_PtrEnc_DataRel = 0x30, // Value is relative to the .got or .eh_frame_hdr section.
|
||||
EH_PtrEnc_FuncRel = 0x40, // Value is relative to the function.
|
||||
EH_PtrEnc_Aligned = 0x50, // Value is aligned to an address unit sized boundary.
|
||||
|
||||
EH_PtrEnc_ModifierMask = 0x70,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
EH_PtrEnc_Indirect = 0x80, // Value is stored in virtual memory.
|
||||
EH_PtrEnc_Omit = 0xFF,
|
||||
};
|
||||
|
||||
typedef struct EH_PtrCtx
|
||||
{
|
||||
U64 pc_vaddr; // address where pointer is being read
|
||||
U64 text_vaddr; // base address of section with instructions (used for encoding pointer on SH and IA64)
|
||||
U64 data_vaddr; // base address of data section (used for encoding pointer on x86-64)
|
||||
U64 func_vaddr; // base address of function where IP is located
|
||||
U64 ptr_align;
|
||||
} EH_PtrCtx;
|
||||
|
||||
typedef U8 EH_AugFlags;
|
||||
enum
|
||||
{
|
||||
EH_AugFlag_HasLSDA = (1 << 0),
|
||||
EH_AugFlag_HasHandler = (1 << 1),
|
||||
EH_AugFlag_HasAddrEnc = (1 << 2),
|
||||
EH_AugFlag_SignalFrame = (1 << 3),
|
||||
};
|
||||
|
||||
typedef struct EH_Augmentation
|
||||
{
|
||||
EH_AugFlags flags;
|
||||
U64 handler_ip;
|
||||
EH_PtrEnc handler_encoding;
|
||||
EH_PtrEnc lsda_encoding;
|
||||
EH_PtrEnc addr_encoding;
|
||||
U64 size;
|
||||
} EH_Augmentation;
|
||||
|
||||
////////////////////////////////
|
||||
//~ Parser
|
||||
|
||||
enum
|
||||
{
|
||||
EH_CIE_Ext_AddrEnc,
|
||||
EH_CIE_Ext_LSDAEnc,
|
||||
EH_CIE_Ext_HandlerEnc,
|
||||
EH_CIE_Ext_HandlerIp,
|
||||
} EH_CIE_Ext;
|
||||
|
||||
typedef struct EH_FrameHdrEntry
|
||||
{
|
||||
U64 addr;
|
||||
U64 fde_offset;
|
||||
} EH_FrameHdrEntry;
|
||||
|
||||
typedef struct EH_FrameHdr
|
||||
{
|
||||
U8 version;
|
||||
EH_PtrEnc eh_frame_ptr_enc;
|
||||
EH_PtrEnc fde_count_enc;
|
||||
EH_PtrEnc table_enc;
|
||||
U64 field_byte_size;
|
||||
U64 entry_byte_size;
|
||||
U64 fde_count;
|
||||
U64 eh_frame_ptr;
|
||||
String8 table;
|
||||
} EH_FrameHdr;
|
||||
|
||||
typedef struct EH_DecodePtrCtx
|
||||
{
|
||||
EH_PtrEnc addr_enc;
|
||||
EH_PtrCtx *ptr_ctx;
|
||||
} EH_DecodePtrCtx;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64 eh_parse_ptr(String8 frame_base, U64 off, U64 pc, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out);
|
||||
internal EH_FrameHdr eh_parse_frame_hdr(String8 data, U64 address_size, EH_PtrCtx *ptr_ctx);
|
||||
internal U64 eh_parse_aug_data(String8 aug_string, String8 aug_data, U64 pc, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out);
|
||||
internal B32 eh_parse_cie(String8 data, DW_Format format, Arch arch, U64 pc, EH_PtrCtx *ptr_ctx, DW_CIE *cie_out);
|
||||
internal B32 eh_parse_fde(String8 data, DW_Format format, U64 pc, DW_CIE *cie, EH_PtrCtx *ptr_ctx, DW_FDE *fde_out);
|
||||
internal U64 eh_find_nearest_fde(EH_FrameHdr header, EH_PtrCtx *ptr_ctx, U64 pc);
|
||||
internal String8 eh_frame_hdr_from_call_frame_info(Arena *arena, U64 fde_count, U64 *fde_offsets, struct DW_FDE *fde);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Enum -> String
|
||||
|
||||
internal String8 eh_string_from_ptr_enc_type(EH_PtrEnc type);
|
||||
internal String8 eh_string_from_ptr_enc_modifier(EH_PtrEnc modifier);
|
||||
internal String8 eh_string_from_ptr_enc(Arena *arena, EH_PtrEnc enc);
|
||||
|
||||
#endif // EH_FRAME_H
|
||||
|
||||
@@ -3,3 +3,72 @@
|
||||
|
||||
//- GENERATED CODE
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
String8 dw_regular_name_from_section_kind_table[18] =
|
||||
{
|
||||
str8_lit_comp(""),
|
||||
str8_lit_comp(".debug_abbrev"),
|
||||
str8_lit_comp(".debug_aranges"),
|
||||
str8_lit_comp(".debug_frame"),
|
||||
str8_lit_comp(".debug_info"),
|
||||
str8_lit_comp(".debug_line"),
|
||||
str8_lit_comp(".debug_loc"),
|
||||
str8_lit_comp(".debug_macinfo"),
|
||||
str8_lit_comp(".debug_pubnames"),
|
||||
str8_lit_comp(".debug_pubtypes"),
|
||||
str8_lit_comp(".debug_ranges"),
|
||||
str8_lit_comp(".debug_str"),
|
||||
str8_lit_comp(".debug_addr"),
|
||||
str8_lit_comp(".debug_loclists"),
|
||||
str8_lit_comp(".debug_rnglists"),
|
||||
str8_lit_comp(".debug_str_offsets"),
|
||||
str8_lit_comp(".debug_line_str"),
|
||||
str8_lit_comp(".debug_names"),
|
||||
};
|
||||
|
||||
String8 dw_macho_name_from_section_kind_table[18] =
|
||||
{
|
||||
str8_lit_comp(""),
|
||||
str8_lit_comp("__debug_abbrev"),
|
||||
str8_lit_comp("__debug_aranges"),
|
||||
str8_lit_comp("__debug_frame"),
|
||||
str8_lit_comp("__debug_info"),
|
||||
str8_lit_comp("__debug_line"),
|
||||
str8_lit_comp("__debug_loc"),
|
||||
str8_lit_comp("__debug_macinfo"),
|
||||
str8_lit_comp("__debug_pubnames"),
|
||||
str8_lit_comp("__debug_pubtypes"),
|
||||
str8_lit_comp("__debug_ranges"),
|
||||
str8_lit_comp("__debug_str"),
|
||||
str8_lit_comp("__debug_addr"),
|
||||
str8_lit_comp("__debug_loclists"),
|
||||
str8_lit_comp("__debug_rnglists"),
|
||||
str8_lit_comp("__debug_str_offsets"),
|
||||
str8_lit_comp("__debug_line_str"),
|
||||
str8_lit_comp("__debug_names"),
|
||||
};
|
||||
|
||||
String8 dw_dwo_name_from_section_kind_table[18] =
|
||||
{
|
||||
str8_lit_comp(""),
|
||||
str8_lit_comp(".debug_abbrev.dwo"),
|
||||
str8_lit_comp(".debug_aranges.dwo"),
|
||||
str8_lit_comp(".debug_frame.dwo"),
|
||||
str8_lit_comp(".debug_info.dwo"),
|
||||
str8_lit_comp(".debug_line.dwo"),
|
||||
str8_lit_comp(".debug_loc.dwo"),
|
||||
str8_lit_comp(".debug_macinfo.dwo"),
|
||||
str8_lit_comp(".debug_pubnames.dwo"),
|
||||
str8_lit_comp(".debug_pubtypes.dwo"),
|
||||
str8_lit_comp(".debug_ranges.dwo"),
|
||||
str8_lit_comp(".debug_str.dwo"),
|
||||
str8_lit_comp(".debug_addr.dwo"),
|
||||
str8_lit_comp(".debug_loclists.dwo"),
|
||||
str8_lit_comp(".debug_rnglists.dwo"),
|
||||
str8_lit_comp(".debug_str_offsets.dwo"),
|
||||
str8_lit_comp(".debug_line_str.dwo"),
|
||||
str8_lit_comp(".debug_names.dwo"),
|
||||
};
|
||||
|
||||
C_LINKAGE_END
|
||||
|
||||
+1697
-16
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#if 0
|
||||
|
||||
internal U64
|
||||
t_dw_test_uleb128(U64 v, U64 expected_length)
|
||||
{
|
||||
@@ -63,6 +65,85 @@ Test(test_leb128)
|
||||
}
|
||||
}
|
||||
|
||||
internal B32
|
||||
dw_test__form_match(DW_Form a, DW_Form b)
|
||||
{
|
||||
B32 is_match = 0;
|
||||
|
||||
if (a.kind == b.kind) {
|
||||
switch (a.kind) {
|
||||
case DW_Form_Null: {} break;
|
||||
|
||||
case DW_Form_Addr: { is_match = str8_match(a.addr, b.addr, 0); } break;
|
||||
case DW_Form_String: { is_match = str8_match(a.string, b.string, 0); } break;
|
||||
case DW_Form_ExprLoc: { is_match = str8_match(a.exprloc, b.exprloc, 0); } break;
|
||||
|
||||
case DW_Form_Block:
|
||||
case DW_Form_Block1:
|
||||
case DW_Form_Block2:
|
||||
case DW_Form_Block4: {
|
||||
is_match = str8_match(a.block, b.block, 0);
|
||||
} break;
|
||||
|
||||
case DW_Form_Data1:
|
||||
case DW_Form_Data2:
|
||||
case DW_Form_Data4:
|
||||
case DW_Form_Data8:
|
||||
case DW_Form_Data16: {
|
||||
is_match = str8_match(a.data, b.data, 0);
|
||||
} break;
|
||||
|
||||
case DW_Form_Flag: { is_match = a.flag == b.flag; } break;
|
||||
case DW_Form_SData: { is_match = a.sdata == b.sdata; } break;
|
||||
case DW_Form_UData: { is_match = a.udata == b.udata; } break;
|
||||
|
||||
case DW_Form_RefAddr:
|
||||
case DW_Form_Ref1:
|
||||
case DW_Form_Ref2:
|
||||
case DW_Form_Ref4:
|
||||
case DW_Form_Ref8:
|
||||
case DW_Form_RefUData:
|
||||
case DW_Form_GNU_RefAlt: {
|
||||
is_match = a.ref == b.ref;
|
||||
} break;
|
||||
|
||||
case DW_Form_Indirect: { NotImplemented; } break;
|
||||
|
||||
case DW_Form_SecOffset:
|
||||
case DW_Form_LineStrp:
|
||||
case DW_Form_GNU_StrpAlt: {
|
||||
is_match = a.sec_offset == b.sec_offset;
|
||||
} break;
|
||||
|
||||
case DW_Form_ImplicitConst: { is_match = a.implicit_const, b.implicit_const; } break;
|
||||
|
||||
case DW_Form_Strx:
|
||||
case DW_Form_Strx1:
|
||||
case DW_Form_Strx2:
|
||||
case DW_Form_Strx3:
|
||||
case DW_Form_Strx4:
|
||||
case DW_Form_Addrx:
|
||||
case DW_Form_Addrx1:
|
||||
case DW_Form_Addrx2:
|
||||
case DW_Form_Addrx3:
|
||||
case DW_Form_Addrx4:
|
||||
case DW_Form_RngListx:
|
||||
case DW_Form_LocListx: {
|
||||
is_match = a.xval == b.xval;
|
||||
} break;
|
||||
|
||||
case DW_Form_StrpSup: { is_match = a.strp_sup == b.strp_sup; } break;
|
||||
|
||||
case DW_Form_RefSup4: { NotImplemented; } break;
|
||||
case DW_Form_RefSup8: { NotImplemented; } break;
|
||||
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
}
|
||||
|
||||
return is_match;
|
||||
}
|
||||
|
||||
internal B32
|
||||
dwt_tags_must_match(DW_WriterTag *writer_tag, DW_TagNode *reader_tag)
|
||||
{
|
||||
@@ -82,7 +163,7 @@ dwt_tags_must_match(DW_WriterTag *writer_tag, DW_TagNode *reader_tag)
|
||||
while (writer_attrib) {
|
||||
if (writer_attrib->kind != reader_attrib->v.attrib_kind) { goto exit; }
|
||||
if (writer_attrib->form.reader.kind != reader_attrib->v.form.kind) { goto exit; }
|
||||
if ( ! dw_form_match(writer_attrib->form.reader, reader_attrib->v.form)) { goto exit; }
|
||||
if ( ! dw_test__form_match(writer_attrib->form.reader, reader_attrib->v.form)) { goto exit; }
|
||||
writer_attrib = writer_attrib->next;
|
||||
reader_attrib = reader_attrib->next;
|
||||
}
|
||||
@@ -1011,7 +1092,6 @@ Test(plus_uconst)
|
||||
TestCheck(expr_value.addr == 0x123 + 4);
|
||||
}
|
||||
|
||||
#if 0
|
||||
Test(reg_split_spill)
|
||||
{
|
||||
// setup register context
|
||||
|
||||
Reference in new issue
Block a user