mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-27 14:01:48 -07:00
2190 lines
85 KiB
C
2190 lines
85 KiB
C
// Copyright (c) Epic Games Tools
|
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Stringification Helpers
|
|
|
|
internal String8
|
|
dw_string_from_reg_off(Arena *arena, Arch arch, U64 reg_idx, S64 reg_off)
|
|
{
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
String8 reg_str = dw_string_from_register(scratch.arena, arch, reg_idx);
|
|
String8 result = push_str8f(arena, "%S%+lld", reg_str, reg_off);
|
|
scratch_end(scratch);
|
|
return result;
|
|
}
|
|
|
|
internal String8List
|
|
dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format)
|
|
{
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
String8List result = {0};
|
|
for (U64 cursor = 0; cursor < raw_data.size; ) {
|
|
U8 op = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &op);
|
|
|
|
String8 op_value = str8_zero();
|
|
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;
|
|
op_value = push_str8f(scratch.arena, "%llu", 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;
|
|
cursor += str8_deserial_read(raw_data, cursor, &x, size_param, 1);
|
|
x = extend_sign64(x, size_param);
|
|
op_value = push_str8f(scratch.arena, "%lld", x);
|
|
} else {
|
|
U64 x = 0;
|
|
cursor += str8_deserial_read(raw_data, cursor, &x, size_param, 1);
|
|
op_value = push_str8f(scratch.arena, "%llu", x);
|
|
}
|
|
} break;
|
|
|
|
case DW_ExprOp_Addr: {
|
|
U64 addr = 0;
|
|
cursor += str8_deserial_read(raw_data, cursor, &addr, address_size, 1);
|
|
op_value = push_str8f(scratch.arena, "%#llx", addr);
|
|
} break;
|
|
|
|
case DW_ExprOp_ConstU: {
|
|
U64 x = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &x);
|
|
op_value = push_str8f(scratch.arena, "%llu", x);
|
|
} break;
|
|
|
|
case DW_ExprOp_ConstS: {
|
|
S64 x = 0;
|
|
cursor += str8_deserial_read_sleb128(raw_data, cursor, &x);
|
|
op_value = push_str8f(scratch.arena, "%lld", 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;
|
|
op_value = dw_string_from_reg_off(scratch.arena, arch, reg_idx, 0);
|
|
} break;
|
|
|
|
case DW_ExprOp_RegX: {
|
|
U64 reg_idx = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx);
|
|
op_value = dw_string_from_reg_off(scratch.arena, arch, reg_idx, 0);
|
|
} break;
|
|
|
|
case DW_ExprOp_ImplicitValue: {
|
|
U64 value_size = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &value_size);
|
|
Rng1U64 value_range = rng_1u64(cursor, cursor + value_size);
|
|
String8 value_data = str8_substr(raw_data, value_range);
|
|
cursor += value_size;
|
|
String8List value_strings = numeric_str8_list_from_data(scratch.arena, 16, value_data, 1);
|
|
op_value = 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;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &size);
|
|
op_value = push_str8f(scratch.arena, "%u", size);
|
|
} break;
|
|
|
|
case DW_ExprOp_BitPiece: {
|
|
U64 bit_size = 0, bit_off = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &bit_size);
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &bit_off);
|
|
op_value = push_str8f(scratch.arena, "bit size %llu, bit offset %llu", bit_size, bit_off);
|
|
} break;
|
|
|
|
case DW_ExprOp_Pick: {
|
|
U8 stack_idx = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &stack_idx);
|
|
op_value = push_str8f(scratch.arena, "stack index %u", stack_idx);
|
|
} break;
|
|
|
|
case DW_ExprOp_PlusUConst: {
|
|
U64 addend = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &addend);
|
|
op_value = push_str8f(arena, "addend %llu", addend);
|
|
} break;
|
|
|
|
case DW_ExprOp_Skip: {
|
|
S16 x = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &x);
|
|
op_value = push_str8f(scratch.arena, "%+d bytes", x);
|
|
} break;
|
|
|
|
case DW_ExprOp_Bra: {
|
|
S16 x = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &x);
|
|
op_value = push_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;
|
|
cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off);
|
|
op_value = dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off);
|
|
} break;
|
|
|
|
case DW_ExprOp_FBReg: {
|
|
S64 reg_off = 0;
|
|
cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off);
|
|
op_value = push_str8f(scratch.arena, "offset %lld", reg_off);
|
|
} break;
|
|
|
|
case DW_ExprOp_BRegX: {
|
|
U64 reg_idx = 0;
|
|
S64 reg_off = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx);
|
|
cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off);
|
|
op_value = dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off);
|
|
} break;
|
|
|
|
case DW_ExprOp_XDerefSize:
|
|
case DW_ExprOp_DerefSize: {
|
|
U8 x = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &x);
|
|
op_value = push_str8f(scratch.arena, "%u", x);
|
|
} break;
|
|
|
|
case DW_ExprOp_Call2: {
|
|
U16 x = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &x);
|
|
op_value = push_str8f(scratch.arena, "%u", x);
|
|
} break;
|
|
case DW_ExprOp_Call4: {
|
|
U32 x = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &x);
|
|
op_value = push_str8f(arena, "%u", x);
|
|
} break;
|
|
case DW_ExprOp_CallRef: {
|
|
U64 x = 0;
|
|
cursor += str8_deserial_read_dwarf_uint(raw_data, cursor, format, &x);
|
|
op_value = push_str8f(scratch.arena, "%llu", x);
|
|
} break;
|
|
case DW_ExprOp_ImplicitPointer:
|
|
case DW_ExprOp_GNU_ImplicitPointer: {
|
|
U64 info_off = 0;
|
|
cursor += str8_deserial_read_dwarf_uint(raw_data, cursor, format, &info_off);
|
|
S64 ptr = 0;
|
|
cursor += str8_deserial_read_sleb128(raw_data, cursor, &ptr);
|
|
|
|
op_value = push_str8f(scratch.arena, ".debug_info+%#llx, ptr %llx", info_off, ptr);
|
|
} break;
|
|
case DW_ExprOp_Convert:
|
|
case DW_ExprOp_GNU_Convert: {
|
|
U64 type_cu_off = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &type_cu_off);
|
|
op_value = push_str8f(scratch.arena, "TypeCuOff %#llx", cu_base + type_cu_off);
|
|
} break;
|
|
case DW_ExprOp_GNU_ParameterRef: {
|
|
// TODO: always 4 bytes?
|
|
U32 cu_off = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &cu_off);
|
|
op_value = push_str8f(scratch.arena, "CuOff %#x", cu_base + cu_off);
|
|
} break;
|
|
case DW_ExprOp_DerefType:
|
|
case DW_ExprOp_GNU_DerefType: {
|
|
U8 deref_size = 0;
|
|
U64 type_cu_off = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &deref_size);
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &type_cu_off);
|
|
op_value = push_str8f(scratch.arena, "%#x, TypeCuOff %#llx", deref_size, cu_base + type_cu_off);
|
|
} break;
|
|
case DW_ExprOp_ConstType:
|
|
case DW_ExprOp_GNU_ConstType: {
|
|
U64 type_cu_off = 0;
|
|
U8 const_value_size = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &type_cu_off);
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &const_value_size);
|
|
Rng1U64 const_value_range = rng_1u64(cursor, cursor + const_value_size);
|
|
String8 const_value_data = str8_substr(raw_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(", ")});
|
|
op_value = push_str8f(scratch.arena, "TypeCuOff %#llx, Const Value { %S }", cu_base + type_cu_off, const_value_str);
|
|
cursor += const_value_size;
|
|
} break;
|
|
case DW_ExprOp_RegvalType:
|
|
case DW_ExprOp_GNU_RegvalType: {
|
|
U64 reg_idx = 0, type_cu_off = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx);
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &type_cu_off);
|
|
op_value = push_str8f(scratch.arena, "%S, TypeCuOff %#llx", dw_string_from_register(scratch.arena, arch, reg_idx), cu_base + type_cu_off);
|
|
} break;
|
|
case DW_ExprOp_EntryValue:
|
|
case DW_ExprOp_GNU_EntryValue: {
|
|
U64 block_size = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size);
|
|
Rng1U64 block_range = rng_1u64(cursor, cursor + block_size);
|
|
String8 block_data = str8_substr(raw_data, block_range);
|
|
String8List block_expr = dw_string_list_from_expression(scratch.arena, block_data, cu_base, address_size, arch, ver, ext, format);
|
|
op_value = str8_list_join(scratch.arena, &block_expr, &(StringJoin){.pre = str8_lit("{ "), .sep = str8_lit(","), .post = str8_lit(" }")});
|
|
cursor += block_size;
|
|
} break;
|
|
case DW_ExprOp_Addrx: {
|
|
U64 addr = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &addr);
|
|
op_value = push_str8f(scratch.arena, "%#llx", addr);
|
|
} break;
|
|
|
|
case DW_ExprOp_CallFrameCfa:
|
|
case DW_ExprOp_FormTlsAddress:
|
|
case DW_ExprOp_PushObjectAddress:
|
|
case DW_ExprOp_Nop:
|
|
case DW_ExprOp_Eq:
|
|
case DW_ExprOp_Ge:
|
|
case DW_ExprOp_Gt:
|
|
case DW_ExprOp_Le:
|
|
case DW_ExprOp_Lt:
|
|
case DW_ExprOp_Ne:
|
|
case DW_ExprOp_Shl:
|
|
case DW_ExprOp_Shr:
|
|
case DW_ExprOp_Shra:
|
|
case DW_ExprOp_Xor:
|
|
case DW_ExprOp_XDeref:
|
|
case DW_ExprOp_Abs:
|
|
case DW_ExprOp_And:
|
|
case DW_ExprOp_Div:
|
|
case DW_ExprOp_Minus:
|
|
case DW_ExprOp_Mod:
|
|
case DW_ExprOp_Mul:
|
|
case DW_ExprOp_Neg:
|
|
case DW_ExprOp_Not:
|
|
case DW_ExprOp_Or:
|
|
case DW_ExprOp_Plus:
|
|
case DW_ExprOp_Rot:
|
|
case DW_ExprOp_Swap:
|
|
case DW_ExprOp_Deref:
|
|
case DW_ExprOp_Dup:
|
|
case DW_ExprOp_Drop:
|
|
case DW_ExprOp_Over:
|
|
case DW_ExprOp_StackValue: {
|
|
// no operands
|
|
} break;
|
|
}
|
|
|
|
String8 opcode_str = dw_string_from_expr_op(scratch.arena, ver, ext, op);
|
|
if (op_value.size == 0) {
|
|
str8_list_pushf(arena, &result, "DW_OP_%S", opcode_str);
|
|
} else {
|
|
str8_list_pushf(arena, &result, "DW_OP_%S = %S", opcode_str, op_value);
|
|
}
|
|
}
|
|
scratch_end(scratch);
|
|
return result;
|
|
}
|
|
|
|
internal String8
|
|
dw_single_line_string_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format)
|
|
{
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
String8List list = dw_string_list_from_expression(scratch.arena, raw_data, cu_base, address_size, arch, ver, ext, format);
|
|
String8 expression = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")});
|
|
scratch_end(scratch);
|
|
return expression;
|
|
}
|
|
|
|
#if 0
|
|
|
|
internal void
|
|
dw_string_from_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format)
|
|
{
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
|
|
U64 address_bit_size = bit_size_from_arch(arch);
|
|
U64 address_size = address_bit_size / 8;
|
|
|
|
for (U64 cursor = 0; cursor < raw_data.size; /* empty */) {
|
|
DW_CFA opcode = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &opcode);
|
|
|
|
U64 operand = 0;
|
|
if ((opcode & DW_CFAMask_OpcodeHi) != 0) {
|
|
operand = opcode & DW_CFAMask_Operand;
|
|
opcode = opcode & DW_CFAMask_OpcodeHi;
|
|
}
|
|
|
|
switch (opcode) {
|
|
case DW_CFA_Nop: {
|
|
rd_printf("DW_CFA_nop");
|
|
} break;
|
|
case DW_CFA_SetLoc: {
|
|
U64 address = 0;
|
|
switch (arch) {
|
|
case Arch_x64: cursor += dw_unwind_parse_pointer_x64(raw_data.str, rng_1u64(0,raw_data.size), ptr_ctx, cie->addr_encoding, cursor, &address); break;
|
|
|
|
default: NotImplemented; break;
|
|
}
|
|
rd_printf("DW_CFA_set_loc: %#llx", address);
|
|
} break;
|
|
case DW_CFA_AdvanceLoc1: {
|
|
U8 delta = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &delta);
|
|
|
|
rd_printf("DW_CFA_advance_loc1: %+u", delta * cie->code_align_factor);
|
|
} break;
|
|
case DW_CFA_AdvanceLoc2: {
|
|
U16 delta = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &delta);
|
|
|
|
rd_printf("DW_CFA_advance_loc2: %+u", delta * cie->code_align_factor);
|
|
} break;
|
|
case DW_CFA_AdvanceLoc4: {
|
|
U32 delta = 0;
|
|
cursor += str8_deserial_read_struct(raw_data, cursor, &delta);
|
|
|
|
rd_printf("DW_CFA_advance_loc4: %+u", delta * cie->code_align_factor);
|
|
} break;
|
|
case DW_CFA_OffsetExt: {
|
|
U64 reg_idx = 0, reg_off = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx);
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_off);
|
|
|
|
rd_printf("DW_CFA_offset_extended: %S register %llu (%S), offset %+llu",
|
|
dw_string_from_reg_off(scratch.arena, arch, reg_idx, (S64)reg_off * cie->data_align_factor));
|
|
} break;
|
|
case DW_CFA_RestoreExt: {
|
|
rd_printf("DW_CFA_restore_extended");
|
|
} break;
|
|
case DW_CFA_Undefined: {
|
|
U64 reg = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®);
|
|
|
|
rd_printf("DW_CFA_undefined: %llu", reg);
|
|
} break;
|
|
case DW_CFA_SameValue: {
|
|
U64 reg = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®);
|
|
|
|
rd_printf("DW_CFA_same_value: %S", dw_string_from_register(scratch.arena, arch, reg));
|
|
} break;
|
|
case DW_CFA_Register: {
|
|
U64 reg_idx = 0, reg_off = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx);
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_off);
|
|
|
|
rd_printf("DW_CFA_register: %S", dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off));
|
|
} break;
|
|
case DW_CFA_RememberState: {
|
|
rd_printf("DW_CFA_remember_state");
|
|
} break;
|
|
case DW_CFA_RestoreState: {
|
|
rd_printf("DW_CFA_restore_state");
|
|
} break;
|
|
case DW_CFA_DefCfa: {
|
|
U64 reg_idx = 0, reg_off = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx);
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_off);
|
|
|
|
rd_printf("DW_CFA_def_cfa: %S", dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off));
|
|
} break;
|
|
case DW_CFA_DefCfaRegister: {
|
|
U64 reg = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®);
|
|
|
|
rd_printf("DW_CFA_register: %llu (%S)",
|
|
reg,
|
|
dw_string_from_register(arena, arch, reg));
|
|
} break;
|
|
case DW_CFA_DefCfaOffset: {
|
|
U64 offset = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset);
|
|
|
|
rd_printf("DW_CFA_def_cfa_offset: %llu", offset);
|
|
} break;
|
|
case DW_CFA_DefCfaExpr: {
|
|
U64 block_size = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size);
|
|
String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size));
|
|
cursor += block_size;
|
|
|
|
rd_printf("DW_CFA_def_cfa_expression: %S",
|
|
dw_single_line_string_from_expression(scratch.arena, raw_expr, 0, address_size, arch, ver, ext, format));
|
|
} break;
|
|
case DW_CFA_Expr: {
|
|
U64 reg = 0, block_size = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®);
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size);
|
|
String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size));
|
|
cursor += block_size;
|
|
|
|
rd_printf("DW_CFA_expression: %S, expression %S",
|
|
dw_string_from_register(scratch.arena, arch, reg),
|
|
dw_single_line_string_from_expression(scratch.arena, raw_expr, 0, address_size, arch, ver, ext, format));
|
|
} break;
|
|
case DW_CFA_OffsetExtSf: {
|
|
U64 reg_idx = 0;
|
|
S64 reg_off = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx);
|
|
cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off);
|
|
|
|
rd_printf("DW_CFA_offset_ext_sf: %S", dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off * cie->data_align_factor));
|
|
} break;
|
|
case DW_CFA_DefCfaSf: {
|
|
U64 reg_idx = 0;
|
|
S64 reg_off = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx);
|
|
cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off);
|
|
|
|
rd_printf("DW_CFA_def_cfa_sf: %S", dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off * cie->data_align_factor));
|
|
} break;
|
|
case DW_CFA_ValOffset: {
|
|
U64 val = 0, offset = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &val);
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset);
|
|
|
|
rd_printf("DW_CFA_val_offset: value %llu, offset %+llu", val, offset);
|
|
} break;
|
|
case DW_CFA_ValOffsetSf: {
|
|
U64 val = 0;
|
|
S64 offset = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &val);
|
|
cursor += str8_deserial_read_sleb128(raw_data, cursor, &offset);
|
|
|
|
rd_printf("DW_CFA_val_offset_sf: value %llu, offset %+lld", val, offset);
|
|
} break;
|
|
case DW_CFA_ValExpr: {
|
|
U64 val = 0;
|
|
U64 block_size = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &val);
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size);
|
|
String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size));
|
|
cursor += block_size;
|
|
|
|
rd_printf("DW_CFA_val_expr: value %+llu, expression %S",
|
|
val,
|
|
dw_single_line_string_from_expression(scratch.arena, raw_expr, 0, address_size, arch, ver, ext, format));
|
|
} break;
|
|
case DW_CFA_AdvanceLoc: {
|
|
rd_printf("DW_CFA_advance_loc: %+llu", operand);
|
|
} break;
|
|
case DW_CFA_Offset: {
|
|
U64 offset = 0;
|
|
cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset);
|
|
S64 v = (S64)offset * cie->data_align_factor;
|
|
|
|
rd_printf("DW_CFA_offset: %S", dw_string_from_reg_off(scratch.arena, arch, operand, v));
|
|
} break;
|
|
case DW_CFA_Restore: {
|
|
rd_printf("DW_CFA_restore: %S", operand, dw_string_from_register(scratch.arena, arch, operand));
|
|
} break;
|
|
default: {
|
|
rd_errorf("unknown CFI opcode %u", opcode);
|
|
} break;
|
|
}
|
|
}
|
|
|
|
scratch_end(scratch);
|
|
}
|
|
|
|
internal String8
|
|
dw_string_from_eh_ptr_enc(Arena *arena, DW_EhPtrEnc enc)
|
|
{
|
|
U8 type = enc & DW_EhPtrEnc_TypeMask;
|
|
String8 type_str = str8_lit("NULL");
|
|
switch (type) {
|
|
case DW_EhPtrEnc_Ptr: type_str = str8_lit("PTR"); break;
|
|
case DW_EhPtrEnc_ULEB128: type_str = str8_lit("ULEB128"); break;
|
|
case DW_EhPtrEnc_UData2: type_str = str8_lit("UDATA2"); break;
|
|
case DW_EhPtrEnc_UData4: type_str = str8_lit("UDATA4"); break;
|
|
case DW_EhPtrEnc_UData8: type_str = str8_lit("UDATA8"); break;
|
|
case DW_EhPtrEnc_Signed: type_str = str8_lit("SIGNED"); break;
|
|
case DW_EhPtrEnc_SLEB128: type_str = str8_lit("SLEB128"); break;
|
|
case DW_EhPtrEnc_SData2: type_str = str8_lit("SDATA2"); break;
|
|
case DW_EhPtrEnc_SData4: type_str = str8_lit("SDATA4"); break;
|
|
case DW_EhPtrEnc_SData8: type_str = str8_lit("SDATA8"); break;
|
|
}
|
|
U8 modifier = enc & DW_EhPtrEnc_ModifyMask;
|
|
String8 modifier_str = str8_lit("NULL");
|
|
switch (modifier) {
|
|
case DW_EhPtrEnc_PcRel: modifier_str = str8_lit("PCREL"); break;
|
|
case DW_EhPtrEnc_TextRel: modifier_str = str8_lit("TEXTREL"); break;
|
|
case DW_EhPtrEnc_DataRel: modifier_str = str8_lit("DATAREL"); break;
|
|
case DW_EhPtrEnc_FuncRel: modifier_str = str8_lit("FUNCREL"); break;
|
|
}
|
|
String8 indir_str = str8_lit("");
|
|
if (enc & DW_EhPtrEnc_Indirect) {
|
|
indir_str = str8_lit("(INDIRECT)");
|
|
}
|
|
return push_str8f(arena, "Type: %S, Modifier: %S %S", type_str, modifier_str, indir_str);
|
|
}
|
|
|
|
internal void
|
|
dw_print_eh_frame(Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, DW_EhPtrCtx *ptr_ctx)
|
|
{
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
DW_CIEUnpacked cie = {0};
|
|
|
|
for (U64 cursor = 0; cursor < raw_eh_frame.size; ) {
|
|
U64 header_offset = cursor;
|
|
|
|
U64 length = 0; // doesn't include bytes for size
|
|
cursor += dw_based_range_read_length(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), cursor, &length);
|
|
|
|
if (length == 0) {
|
|
break; // encountered exit marker
|
|
}
|
|
|
|
U64 entry_start = cursor;
|
|
U64 entry_end = cursor + length;
|
|
|
|
U32 entry_id = 0; // always 4-bytes, even when length is encoded as 64-bit integer
|
|
cursor += str8_deserial_read_struct(raw_eh_frame, cursor, &entry_id);
|
|
|
|
// TODO: fix the freaking DW_EhPtrEnc_PCREL encoding.
|
|
// it assumes "frame_base" points to the first byte of .eh_frame
|
|
// but here base is start of ELF and we use range to select .eh_frame
|
|
// bytes to read, which breaks parsing.
|
|
String8 raw_frame = str8_substr(raw_eh_frame, rng_1u64(cursor, cursor + length - sizeof(entry_id)));
|
|
Rng1U64 cfi_range = rng_1u64(0,0);
|
|
|
|
// CIE
|
|
if (entry_id == 0) {
|
|
dw_unwind_parse_cie_x64(raw_frame.str, rng_1u64(0,raw_frame.size), ptr_ctx, 0, &cie);
|
|
cfi_range = cie.cfi_range;
|
|
|
|
rd_printf("CIE @ 0x%X, Length %u", header_offset, length);
|
|
rd_indent();
|
|
rd_printf("LSDA Encoding: %S", dw_string_from_eh_ptr_enc(scratch.arena, cie.lsda_encoding));
|
|
rd_printf("Address Encoding: %S", dw_string_from_eh_ptr_enc(scratch.arena, cie.addr_encoding));
|
|
rd_printf("Augmentation: %S", cie.augmentation);
|
|
rd_printf("Code Align Factor: %llu", cie.code_align_factor);
|
|
rd_printf("Data Align Factor: %lld", cie.data_align_factor);
|
|
rd_printf("Return Address Register: %u", cie.ret_addr_reg);
|
|
rd_printf("Handler IP: %#llx", cie.handler_ip);
|
|
rd_unindent();
|
|
}
|
|
// FDE
|
|
else {
|
|
DW_FDEUnpacked fde = {0};
|
|
dw_unwind_parse_fde_x64(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), ptr_ctx, &cie, 0, &fde);
|
|
cfi_range = fde.cfi_range;
|
|
|
|
// calc parent CIE offset
|
|
AssertAlways(entry_start >= entry_id);
|
|
U64 cie_offset = entry_start - entry_id; NotImplemented; // TODO: syms_safe_sub_u64(range.min + entry_start, entry_id);
|
|
|
|
rd_printf("FDE @ %#llx, Length %u, Parent CIE @ %#llx", header_offset, length, cie_offset);
|
|
rd_indent();
|
|
rd_printf("IP Range: %#llx-%#llx", fde.ip_voff_range.min, fde.ip_voff_range.max);
|
|
rd_printf("LSDA IP: %#llx", fde.lsda_ip);
|
|
rd_unindent();
|
|
}
|
|
|
|
// print CFI program
|
|
rd_printf("CFI Program:");
|
|
rd_indent();
|
|
|
|
DW_Format format = DW_FormatFromSize(length);
|
|
String8 raw_cfi = str8_substr(raw_eh_frame, cfi_range);
|
|
dw_string_from_cfi_program(scratch.arena, out, indent, raw_cfi, &cie, ptr_ctx, arch, ver, ext, format);
|
|
|
|
rd_unindent();
|
|
rd_newline();
|
|
|
|
// advance to next entry
|
|
cursor = entry_end;
|
|
}
|
|
|
|
scratch_end(scratch);
|
|
}
|
|
|
|
internal void
|
|
dw_print_debug_loc(Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ExecutableImageKind image_type, B32 relaxed)
|
|
{
|
|
#if 0
|
|
DW_Section info = input->sec[DW_Section_Info];
|
|
DW_Section loc = input->sec[DW_Section_Loc];
|
|
|
|
if (loc.data.size == 0) {
|
|
return;
|
|
}
|
|
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
|
|
rd_printf("# %S", input->sec[DW_Section_Loc].name);
|
|
rd_indent();
|
|
|
|
// TODO: warn about overlaps in ranges
|
|
|
|
Rng1U64List cu_range_list = dw_comp_unit_ranges_from_info(scratch.arena, info);
|
|
|
|
// parse debug_info for attributes with LOCLIST and store .debug_loc offsets
|
|
U64List *loc_lists = push_array(scratch.arena, U64List, cu_range_list.count);
|
|
U64 *address_sizes = push_array(scratch.arena, U64, cu_range_list.count);
|
|
U64 *address_bases = push_array(scratch.arena, U64, cu_range_list.count);
|
|
U64 *cu_bases = push_array(scratch.arena, U64, cu_range_list.count);
|
|
DW_Version *ver_arr = push_array(scratch.arena, DW_Version, cu_range_list.count);
|
|
DW_Ext *ext_arr = push_array(scratch.arena, DW_Ext, cu_range_list.count);
|
|
|
|
U64 comp_idx = 0;
|
|
for (Rng1U64Node *cu_range_n = cu_range_list.first; cu_range_n != 0; cu_range_n = cu_range_n->next, ++comp_idx) {
|
|
Temp comp_temp = temp_begin(arena);
|
|
|
|
Rng1U64 cu_range = cu_range_n->v;
|
|
DW_CompUnit cu = dw_comp_unit_from_info_off(comp_temp.arena, input, cu_range.min, relaxed);
|
|
|
|
// store info about comp unit
|
|
address_sizes[comp_idx] = cu.address_size;
|
|
address_bases[comp_idx] = cu.base_addr;
|
|
ver_arr[comp_idx] = cu.version;
|
|
cu_bases[comp_idx] = cu_range_n->v.min;
|
|
|
|
// parse tags
|
|
for (U64 info_off = cu.tags_range.min; info_off < cu.tags_range.max; /* empty */) {
|
|
Temp tag_temp = temp_begin(scratch.arena);
|
|
|
|
DW_Tag tag = dw_tag_from_info_offset_cu(tag_temp.arena, input, &cu, ext_arr[comp_idx], info_off);
|
|
|
|
// parse attribs
|
|
for (DW_AttribNode *attrib_node = tag.attribs.first; attrib_node != 0; attrib_node = attrib_node->next) {
|
|
DW_Attrib *attrib = &attrib_node->v;
|
|
B32 is_sect_offset = attrib->value_class == DW_AttribClass_LocListPtr || (attrib->value_class == DW_AttribClass_LocList && attrib->form_kind == DW_Form_SecOffset);
|
|
B32 is_sect_index = attrib->value_class == DW_AttribClass_LocList && attrib->form_kind == DW_Form_LocListx;
|
|
if (is_sect_offset) {
|
|
u64_list_push(scratch.arena, &loc_lists[comp_idx], attrib->value.v[0]);
|
|
} else if (is_sect_index) {
|
|
// TODO: support for section indexing
|
|
}
|
|
}
|
|
|
|
// advance to next tag
|
|
info_off = tag.next_info_off;
|
|
|
|
temp_end(tag_temp);
|
|
}
|
|
|
|
temp_end(comp_temp);
|
|
}
|
|
|
|
void *base = dw_base_from_sec(input, DW_Section_Loc);
|
|
Rng1U64 range = dw_range_from_sec(input, DW_Section_Loc);
|
|
|
|
rd_printf(".debug_loc");
|
|
rd_indent();
|
|
rd_printf("%-8s %-8s %-8s %s", "Offset", "Min", "Max", "Expression");
|
|
for (U32 comp_idx = 0; comp_idx < cu_range_list.count; ++comp_idx) {
|
|
Temp locs_temp = temp_begin(scratch.arena);
|
|
|
|
DW_Version ver = ver_arr[comp_idx];
|
|
DW_Ext ext = ext_arr[comp_idx];
|
|
|
|
U64Array locs = u64_array_from_list(locs_temp.arena, &loc_lists[comp_idx]);
|
|
u64_array_sort(locs.count, locs.v);
|
|
|
|
U64Array locs_set = remove_duplicates_u64_array(locs_temp.arena, locs);
|
|
U64 address_size = address_sizes[comp_idx];
|
|
U64 base_selector = (address_size == 8) ? max_U64 : max_U32;
|
|
|
|
for (U64 loc_idx = 0; loc_idx < locs_set.count; ++loc_idx) {
|
|
U64 base_address = address_bases[comp_idx];
|
|
for (U64 cursor = locs_set.v[loc_idx]; cursor < dim_1u64(range); /* empty */) {
|
|
Temp range_temp = temp_begin(arena);
|
|
|
|
String8List list = {0};
|
|
|
|
// offset
|
|
str8_list_pushf(range_temp.arena, &list, "%08llx", cursor);
|
|
|
|
// parse entry
|
|
U64 v0 = 0, v1 = 0;
|
|
cursor += dw_based_range_read(base, range, cursor, address_size, &v0);
|
|
cursor += dw_based_range_read(base, range, cursor, address_size, &v1);
|
|
|
|
B32 is_list_end = v0 == 0 && v1 == 0;
|
|
if (is_list_end) {
|
|
str8_list_pushf(range_temp.arena, &list, "<LIST END>");
|
|
} else if (v0 == base_selector) {
|
|
base_address = v1;
|
|
} else {
|
|
U16 expr_size = 0;
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &expr_size);
|
|
Rng1U64 expr_range = rng_1u64(range.min+cursor, range.min+cursor+expr_size);
|
|
cursor += expr_size;
|
|
|
|
// format dwarf expression
|
|
B32 is_dwarf64 = (address_size == 8);
|
|
String8 raw_expr = str8((U8*)base+expr_range.min, dim_1u64(expr_range));
|
|
String8 expression = dw_single_line_string_from_expression(range_temp.arena, raw_expr, cu_bases[comp_idx], address_size, arch, ver, ext, input->sec[DW_Section_Loc].mode);
|
|
|
|
// push entry
|
|
U64 min = base_address + v0;
|
|
U64 max = base_address + v1;
|
|
str8_list_pushf(range_temp.arena, &list, "%08llx %08llx %S", min, max, expression);
|
|
}
|
|
|
|
// print entry
|
|
String8 print = str8_list_join(range_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")});
|
|
rd_printf("%S", print);
|
|
|
|
// cleanup temp
|
|
temp_end(range_temp);
|
|
|
|
// exit check
|
|
if (is_list_end) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
temp_end(locs_temp);
|
|
}
|
|
rd_unindent();
|
|
|
|
rd_unindent();
|
|
scratch_end(scratch);
|
|
#endif
|
|
}
|
|
|
|
internal void
|
|
dw_print_debug_ranges(Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ExecutableImageKind image_type, B32 relaxed)
|
|
{
|
|
NotImplemented;
|
|
#if 0
|
|
DW_Section ranges = input->sec[DW_Section_Ranges];
|
|
void *base = dw_base_from_sec(input, DW_Section_Ranges);
|
|
Rng1U64 range = dw_range_from_sec(input, DW_Section_Ranges);
|
|
|
|
if (dim_1u64(range) == 0) {
|
|
return;
|
|
}
|
|
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
|
|
Rng1U64List cu_range_list = dw_comp_unit_ranges_from_info(scratch.arena, sections->v[DW_Section_Info]);
|
|
|
|
// parse debug_info for attributes with LOCLIST and store .debug_loc offsets
|
|
U64List *loc_lists = push_array(scratch.arena, U64List, cu_range_list.count);
|
|
U64 *address_sizes = push_array(scratch.arena, U64, cu_range_list.count);
|
|
U64 *address_bases = push_array(scratch.arena, U64, cu_range_list.count);
|
|
|
|
{
|
|
U64 comp_idx = 0;
|
|
for (Rng1U64Node *cu_range_n = cu_range_list.first; cu_range_n != 0; cu_range_n = cu_range_n->next, ++comp_idx) {
|
|
Rng1U64 cu_range = cu_range_n->v;
|
|
DW_CompUnit cu = dw_comp_unit_from_info_offset(scratch.arena, sections, cu_range.min, relaxed);
|
|
|
|
// store info about comp unit
|
|
address_sizes[comp_idx] = cu.address_size;
|
|
address_bases[comp_idx] = cu.base_addr;
|
|
|
|
// parse tags
|
|
for (U64 info_off = cu.tags_range.min; info_off < cu.tags_range.max; /* empty */) {
|
|
DW_Tag tag = dw_tag_from_info_offset_cu(scratch.arena, sections, &cu, info_off);
|
|
|
|
// parse attribs
|
|
for (DW_AttribNode *attrib_node = tag.attribs.first; attrib_node != 0; attrib_node = attrib_node->next) {
|
|
DW_Attrib *attrib = &attrib_node->v;
|
|
B32 is_sect_offset = attrib->value_class == DW_AttribClass_RngListPtr || (attrib->value_class == DW_AttribClass_RngList && attrib->form_kind == DW_Form_SecOffset);
|
|
B32 is_sect_index = attrib->value_class == DW_AttribClass_RngList && attrib->form_kind == DW_Form_RngListx;
|
|
if (is_sect_offset) {
|
|
u64_list_push(scratch.arena, &loc_lists[comp_idx], attrib->value.v[0]);
|
|
} else if (is_sect_index) {
|
|
// TODO: support for section indexing
|
|
}
|
|
}
|
|
|
|
info_off = tag.next_info_off;
|
|
}
|
|
}
|
|
}
|
|
|
|
rd_printf("# %S", sections->v[DW_Section_Ranges].name);
|
|
rd_indent();
|
|
rd_printf("%-8s %-8s %-8s", "Offset", "Min", "Max");
|
|
for (U32 comp_idx = 0; comp_idx < cu_range_list.count; ++comp_idx) {
|
|
U64Array locs = u64_array_from_list(scratch.arena, &loc_lists[comp_idx]);
|
|
u64_array_sort(locs.count, locs.v);
|
|
U64Array locs_set = remove_duplicates_u64_array(scratch.arena, locs);
|
|
U64 address_size = address_sizes[comp_idx];
|
|
U64 base_selector = (address_size == 8) ? max_U64 : max_U32;
|
|
|
|
for (U64 loc_idx = 0; loc_idx < locs_set.count; ++loc_idx) {
|
|
U64 base_address = address_bases[comp_idx];
|
|
for (U64 cursor = locs_set.v[loc_idx]; cursor < dim_1u64(range); /* empty */) {
|
|
Temp range_temp = temp_begin(scratch.arena);
|
|
|
|
String8List list = {0};
|
|
|
|
// offset
|
|
str8_list_pushf(range_temp.arena, &list, "%08llx", cursor);
|
|
|
|
// parse entry
|
|
U64 v0 = 0, v1 = 0;
|
|
cursor += dw_based_range_read(base, range, cursor, address_size, &v0);
|
|
cursor += dw_based_range_read(base, range, cursor, address_size, &v1);
|
|
|
|
B32 is_list_end = v0 == 0 && v1 == 0;
|
|
if (is_list_end) {
|
|
str8_list_pushf(range_temp.arena, &list, "<LIST END>");
|
|
} else if (v0 == base_selector) {
|
|
base_address = v1;
|
|
} else {
|
|
// push entry
|
|
U64 min = base_address + v0;
|
|
U64 max = base_address + v1;
|
|
str8_list_pushf(range_temp.arena, &list, "%08llx %08llx", min, max);
|
|
}
|
|
|
|
// print entry
|
|
String8 print = str8_list_join(range_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")});
|
|
rd_printf("%S", print);
|
|
|
|
temp_end(range_temp);
|
|
|
|
// exit check
|
|
if (is_list_end) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
internal void
|
|
dw_print_debug_aranges(Arena *arena, String8List *out, String8 indent, DW_Input *input)
|
|
{
|
|
NotImplemented;
|
|
#if 0
|
|
void *base = dw_base_from_sec(sections, DW_Section_ARanges);
|
|
Rng1U64 range = dw_range_from_sec(sections, DW_Section_ARanges);
|
|
|
|
if (dim_1u64(range) == 0) {
|
|
return;
|
|
}
|
|
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
|
|
rd_printf("# %S", sections->v[DW_Section_ARanges].name);
|
|
rd_indent();
|
|
for (U64 cursor = 0; cursor < dim_1u64(range); ) {
|
|
U64 unit_length = 0;
|
|
DW_Version version = 0;
|
|
U64 debug_info_offset = 0;
|
|
U8 address_size = 0;
|
|
U8 segment_selector_size = 0;
|
|
|
|
cursor += dw_based_range_read_length(base, range, cursor, &unit_length);
|
|
U64 unit_opl = cursor + unit_length;
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &version);
|
|
|
|
B32 is_dwarf64 = unit_length >= max_U32;
|
|
U64 int_size = is_dwarf64 ? sizeof(U64) : sizeof(U32);
|
|
cursor += dw_based_range_read(base, range, cursor, int_size, &debug_info_offset);
|
|
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &address_size);
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &segment_selector_size);
|
|
|
|
U64 tuple_size = address_size * 2 + segment_selector_size;
|
|
U64 bytes_too_far_past_boundary = cursor % tuple_size;
|
|
if (bytes_too_far_past_boundary > 0) {
|
|
cursor += tuple_size - bytes_too_far_past_boundary;
|
|
}
|
|
|
|
rd_printf("Unit length: %llu", unit_length);
|
|
rd_printf("Version: %u", version);
|
|
rd_printf("Debug info offset: %#llx", debug_info_offset);
|
|
rd_printf("Address size: %u", address_size);
|
|
rd_printf("Segment selector size: %u", segment_selector_size);
|
|
|
|
if (version != DW_Version_2) {
|
|
rd_warningf("Version value must be 2 (DWARF5 sepc, Feb 13, 2017)");
|
|
}
|
|
|
|
rd_indent();
|
|
rd_printf("%-8s %-8s", "Offset", "Range");
|
|
for (; cursor < unit_opl; ) {
|
|
Temp temp = temp_begin(arena);
|
|
|
|
String8List list = {0};
|
|
|
|
str8_list_pushf(temp.arena, &list, "%08llx", cursor);
|
|
|
|
U64 segment_selector = 0;
|
|
U64 address = 0;
|
|
U64 length = 0;
|
|
cursor += dw_based_range_read(base, range, cursor, segment_selector_size, &segment_selector);
|
|
cursor += dw_based_range_read(base, range, cursor, address_size, &address);
|
|
cursor += dw_based_range_read(base, range, cursor, address_size, &length);
|
|
|
|
if (segment_selector == 0 && address == 0 && length == 0) {
|
|
str8_list_pushf(temp.arena, &list, "<LIST END>");
|
|
} else {
|
|
if (segment_selector != 0) {
|
|
str8_list_pushf(temp.arena, &list, "%02llu:", segment_selector);
|
|
}
|
|
str8_list_pushf(temp.arena, &list, "%llx-%llx", address, address+length);
|
|
}
|
|
|
|
String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ") });
|
|
rd_printf("%S", print);
|
|
|
|
temp_end(temp);
|
|
}
|
|
rd_unindent();
|
|
rd_newline();
|
|
}
|
|
rd_unindent();
|
|
|
|
scratch_end(scratch);
|
|
#endif
|
|
}
|
|
|
|
internal void
|
|
dw_print_debug_addr(Arena *arena, String8List *out, String8 indent, DW_Input *input)
|
|
{
|
|
NotImplemented;
|
|
#if 0
|
|
void *base = dw_base_from_sec(sections, DW_Section_Addr);
|
|
Rng1U64 range = dw_range_from_sec(sections, DW_Section_Addr);
|
|
|
|
if (dim_1u64(range) == 0) {
|
|
return;
|
|
}
|
|
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
|
|
rd_printf("# %S", sections->v[DW_Section_Addr].name);
|
|
rd_indent();
|
|
for (U64 cursor = 0; cursor < dim_1u64(range); ) {
|
|
U64 unit_length = 0;
|
|
DW_Version version = 0;
|
|
U8 address_size = 0;
|
|
U8 segment_selector_size = 0;
|
|
|
|
U64 unit_offset = cursor;
|
|
cursor += dw_based_range_read_length(base, range, cursor, &unit_length);
|
|
|
|
U64 unit_opl = cursor + unit_length;
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &version);
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &address_size);
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &segment_selector_size);
|
|
|
|
U64 tuple_size = address_size * 2 + segment_selector_size;
|
|
U64 bytes_too_far_past_boundary = cursor % tuple_size;
|
|
if (bytes_too_far_past_boundary > 0) {
|
|
cursor += tuple_size - bytes_too_far_past_boundary;
|
|
}
|
|
|
|
rd_printf("Unit @ %#llx, length %llu", unit_offset, unit_length);
|
|
rd_printf("Version: %u", version);
|
|
rd_printf("Address size: %u", address_size);
|
|
rd_printf("Segment selector size: %u", segment_selector_size);
|
|
|
|
if (version != DW_Version_2) {
|
|
rd_warningf("Version value must be 5 (DWARF5 sepc, Feb 13, 2017)");
|
|
}
|
|
|
|
rd_indent();
|
|
rd_printf("%-8s %-8s", "Offset", "Address");
|
|
for (; cursor < unit_opl; ) {
|
|
Temp temp = temp_begin(arena);
|
|
|
|
String8List list = {0};
|
|
|
|
str8_list_pushf(temp.arena, &list, "%08X", cursor);
|
|
|
|
U64 segment_selector = 0;
|
|
U64 address = 0;
|
|
cursor += dw_based_range_read(base, range, cursor, segment_selector_size, &segment_selector);
|
|
cursor += dw_based_range_read(base, range, cursor, address_size, &address);
|
|
|
|
if (segment_selector == 0 && address == 0) {
|
|
str8_list_pushf(temp.arena, &list, "<LIST END>");
|
|
} else {
|
|
if (segment_selector != 0) {
|
|
str8_list_pushf(temp.arena, &list, "%02u:", segment_selector);
|
|
}
|
|
str8_list_pushf(temp.arena, &list, "%llx", address);
|
|
}
|
|
|
|
String8 print = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(" ")});
|
|
rd_printf("%S", print);
|
|
|
|
temp_end(temp);
|
|
}
|
|
rd_unindent();
|
|
rd_newline();
|
|
}
|
|
rd_unindent();
|
|
|
|
scratch_end(scratch);
|
|
#endif
|
|
}
|
|
|
|
internal U64
|
|
dw_based_range_read_address(void *base, Rng1U64 range, U64 offset, Rng1U64Array segment_ranges, U8 segment_selector_size, U8 address_size, U64 *address_out)
|
|
{
|
|
U64 read_offset = offset;
|
|
|
|
// read segment
|
|
U64 segment_selector = 0;
|
|
read_offset += dw_based_range_read(base, range, read_offset, segment_selector_size, &segment_selector);
|
|
|
|
// read address
|
|
U64 address = 0;
|
|
read_offset += dw_based_range_read(base, range, read_offset, address_size, &address);
|
|
|
|
// apply segment offset
|
|
B32 is_address_segment_relative = segment_selector_size > 0;
|
|
if (is_address_segment_relative) {
|
|
if (segment_selector < segment_ranges.count) {
|
|
address += segment_ranges.v[segment_selector].min;
|
|
} else {
|
|
Assert(!"invalid segment selector");
|
|
}
|
|
}
|
|
|
|
U64 read_size = (read_offset - offset);
|
|
return read_size;
|
|
}
|
|
|
|
internal void
|
|
dw_print_debug_loclists(Arena *arena, String8List *out, String8 indent, DW_Input *input, Rng1U64Array segment_virtual_ranges, Arch arch)
|
|
{
|
|
NotImplemented;
|
|
#if 0
|
|
void *base = dw_base_from_sec(sections, DW_Section_LocLists);
|
|
Rng1U64 range = dw_range_from_sec(sections, DW_Section_LocLists);
|
|
|
|
if (dim_1u64(range) == 0) {
|
|
return;
|
|
}
|
|
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
|
|
rd_printf("# %S", sections->v[DW_Section_LocLists].name);
|
|
rd_indent();
|
|
for (U64 cursor = 0; cursor < dim_1u64(range); ) {
|
|
U64 unit_offset = cursor;
|
|
U64 unit_length = 0;
|
|
cursor += dw_based_range_read_length(base, range, cursor, &unit_length);
|
|
|
|
U64 unit_opl = cursor + unit_length;
|
|
DW_Version version = 0;
|
|
U8 address_size = 0;
|
|
U8 segment_selector_size = 0;
|
|
U32 offset_entry_count = 0;
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &version);
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &address_size);
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &segment_selector_size);
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &offset_entry_count);
|
|
|
|
U64 past_header_offset = cursor;
|
|
B32 is_dwarf64 = unit_length > max_U32;
|
|
U64 offset_size = is_dwarf64 ? sizeof(U64) : sizeof(U32);
|
|
|
|
rd_printf("Unit @ %#llx, length %llu", unit_offset, unit_length);
|
|
rd_printf("Version: %u", version);
|
|
rd_printf("Address size: %u", address_size);
|
|
rd_printf("Segment selector size: %u", segment_selector_size);
|
|
rd_printf("Offset entry count: %u", offset_entry_count);
|
|
if (version != DW_Version_5) {
|
|
rd_warningf("Version value must be 5 (DWARF5 sepc, Feb 13, 2017)");
|
|
}
|
|
|
|
if (offset_entry_count > 0) {
|
|
rd_printf("Offsets:");
|
|
rd_indent();
|
|
rd_printf("%-8s %-8s", "Index", "Offset");
|
|
for (U64 offset_idx = 0; offset_idx < offset_entry_count; ++offset_idx) {
|
|
U64 offset = 0;
|
|
cursor += dw_based_range_read(base, range, cursor, offset_size, &offset);
|
|
rd_printf("%-8llu %llx", offset_idx, offset+past_header_offset);
|
|
}
|
|
rd_unindent();
|
|
}
|
|
|
|
rd_printf("Locations:");
|
|
rd_indent();
|
|
rd_printf("%-8s %-8s", "Offset", "Location");
|
|
for (; cursor < unit_opl; ) {
|
|
Temp temp = temp_begin(arena);
|
|
|
|
String8List list = {0};
|
|
|
|
str8_list_pushf(temp.arena, &list, "%08llx", cursor);
|
|
|
|
U8 kind = 0;
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &kind);
|
|
str8_list_pushf(temp.arena, &list, "DW_LLE_%S", dw_string_from_loc_list_entry_kind(temp.arena, kind));
|
|
|
|
B32 has_loc_desc = 0;
|
|
switch (kind) {
|
|
case DW_LocListEntryKind_EndOfList:
|
|
break;
|
|
case DW_LocListEntryKind_DefaultLocation: {
|
|
has_loc_desc = 1;
|
|
} break;
|
|
case DW_LocListEntryKind_BaseAddress: {
|
|
U64 base_address = 0;
|
|
cursor += dw_based_range_read_address(base, range, cursor, segment_virtual_ranges, segment_selector_size, address_size, &base_address);
|
|
str8_list_pushf(temp.arena, &list, "%llx", base_address);
|
|
} break;
|
|
case DW_LocListEntryKind_StartLength: {
|
|
U64 start = 0;
|
|
U64 length = 0;
|
|
cursor += dw_based_range_read_address(base, range, cursor, segment_virtual_ranges, segment_selector_size, address_size, &start);
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &length);
|
|
str8_list_pushf(temp.arena, &list, "%llx, %llx", start, length);
|
|
} break;
|
|
case DW_LocListEntryKind_StartEnd: {
|
|
U64 start = 0;
|
|
U64 end = 0;
|
|
cursor += dw_based_range_read_address(base, range, cursor, segment_virtual_ranges, segment_selector_size, address_size, &start);
|
|
cursor += dw_based_range_read_address(base, range, cursor, segment_virtual_ranges, segment_selector_size, address_size, &end);
|
|
str8_list_pushf(temp.arena, &list, "%llx, %llx", start, end);
|
|
} break;
|
|
case DW_LocListEntryKind_BaseAddressX: {
|
|
U64 base_addressx = 0;
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &base_addressx);
|
|
str8_list_pushf(temp.arena, &list, "%llx", base_addressx);
|
|
} break;
|
|
case DW_LocListEntryKind_StartXEndX: {
|
|
U64 startx = 0;
|
|
U64 endx = 0;
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &startx);
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &endx);
|
|
str8_list_pushf(temp.arena, &list, "%llx, %llx", startx, endx);
|
|
} break;
|
|
case DW_LocListEntryKind_OffsetPair: {
|
|
U64 a = 0;
|
|
U64 b = 0;
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &a);
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &b);
|
|
str8_list_pushf(temp.arena, &list, "%llx, %llx", a, b);
|
|
|
|
U8 expr_length = 0;
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &expr_length);
|
|
|
|
String8 raw_expr = str8((U8*)base+cursor, expr_length);
|
|
cursor += expr_length;
|
|
|
|
// TODO: we need actual cu base to format expression correctly
|
|
NotImplemented;
|
|
String8 expression = dw_single_line_string_from_expression(temp.arena, raw_expr, 0, address_size, arch, version, DW_Ext_Null, is_dwarf64);
|
|
str8_list_pushf(temp.arena, &list, "(%S)", expression);
|
|
} break;
|
|
case DW_LocListEntryKind_StartXLength: {
|
|
U64 startx = 0;
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &startx);
|
|
U64 length = 0;
|
|
if (version < DW_Version_5) {
|
|
// pre-standard length
|
|
cursor += dw_based_range_read(base, range, cursor, sizeof(U32), &length);
|
|
} else {
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &length);
|
|
}
|
|
} break;
|
|
}
|
|
|
|
String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")});
|
|
rd_printf("%S", print);
|
|
|
|
temp_end(temp);
|
|
}
|
|
rd_unindent();
|
|
rd_newline();
|
|
}
|
|
rd_unindent();
|
|
|
|
scratch_end(scratch);
|
|
#endif
|
|
}
|
|
|
|
internal void
|
|
dw_print_debug_rnglists(Arena *arena, String8List *out, String8 indent, DW_Input *input, Rng1U64Array segment_ranges)
|
|
{
|
|
NotImplemented;
|
|
#if 0
|
|
void *base = dw_base_from_sec(sections, DW_Section_RngLists);
|
|
Rng1U64 range = dw_range_from_sec(sections, DW_Section_RngLists);
|
|
|
|
if (dim_1u64(range) == 0) {
|
|
return;
|
|
}
|
|
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
|
|
rd_printf("# %S", sections->v[DW_Section_RngLists].name);
|
|
rd_indent();
|
|
for (U64 cursor = 0; cursor < dim_1u64(range); ) {
|
|
U64 unit_offset = cursor;
|
|
U64 unit_length = 0;
|
|
cursor += dw_based_range_read_length(base, range, cursor, &unit_length);
|
|
U64 unit_opl = cursor + unit_length;
|
|
DW_Version version = 0;
|
|
U8 address_size = 0;
|
|
U8 segment_selector_size = 0;
|
|
U32 offset_entry_count = 0;
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &version);
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &address_size);
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &segment_selector_size);
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &offset_entry_count);
|
|
|
|
U64 past_header_offset = cursor;
|
|
B32 is_dwarf64 = unit_length > max_U32;
|
|
U64 offset_size = is_dwarf64 ? sizeof(U64) : sizeof(U32);
|
|
|
|
rd_printf("Unit @ %#llx, length %llu", unit_offset, unit_length);
|
|
rd_printf("Version: %u", version);
|
|
rd_printf("Address size: %u", address_size);
|
|
rd_printf("Segment selector size: %u", segment_selector_size);
|
|
rd_printf("Offset entry count: %u", offset_entry_count);
|
|
|
|
if (version != DW_Version_5) {
|
|
rd_warningf("Version value must be 5 (DWARF5 sepc, Feb 13, 2017)");
|
|
}
|
|
|
|
if (offset_entry_count > 0) {
|
|
rd_printf("Offsets:");
|
|
rd_indent();
|
|
rd_printf("%-8s %-8s", "Index", "Offset");
|
|
for (U64 offset_idx = 0; offset_idx < offset_entry_count; ++offset_idx) {
|
|
U64 offset = 0;
|
|
cursor += dw_based_range_read(base, range, cursor, offset_size, &offset);
|
|
rd_printf("%-8llu %llx", offset_idx, offset+past_header_offset);
|
|
}
|
|
rd_unindent();
|
|
}
|
|
|
|
rd_printf("Ranges:");
|
|
rd_indent();
|
|
rd_printf("%-8s %-8s", "Offset", "Range");
|
|
for (; cursor < unit_opl; ) {
|
|
Temp temp = temp_begin(scratch.arena);
|
|
|
|
String8List list = {0};
|
|
|
|
// offset
|
|
str8_list_pushf(temp.arena, &list, "%08llx", cursor);
|
|
|
|
// opcode mnemonic
|
|
U8 kind = 0;
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &kind);
|
|
str8_list_pushf(temp.arena, &list, "DW_RLE_%S", dw_string_from_rng_list_entry_kind(temp.arena, kind));
|
|
|
|
// operand
|
|
switch (kind) {
|
|
case DW_RngListEntryKind_EndOfList: {
|
|
// empty
|
|
} break;
|
|
case DW_RngListEntryKind_BaseAddressX: {
|
|
U64 base_addressx = 0;
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &base_addressx);
|
|
str8_list_pushf(temp.arena, &list, "%llx", base_addressx);
|
|
} break;
|
|
case DW_RngListEntryKind_BaseAddress: {
|
|
U64 base_address = 0;
|
|
cursor += dw_based_range_read_address(base, range, cursor, segment_ranges, segment_selector_size, address_size, &base_address);
|
|
str8_list_pushf(temp.arena, &list, "%llx", base_address);
|
|
} break;
|
|
case DW_RngListEntryKind_OffsetPair: {
|
|
U64 min = 0;
|
|
U64 max = 0;
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &min);
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &max);
|
|
str8_list_pushf(temp.arena, &list, "%llx, %llx", min, max);
|
|
} break;
|
|
case DW_RngListEntryKind_StartxLength: {
|
|
U64 startx = 0;
|
|
U64 length = 0;
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &startx);
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &length);
|
|
str8_list_pushf(temp.arena, &list, "%llx, %llx", startx, length);
|
|
} break;
|
|
case DW_RngListEntryKind_StartxEndx: {
|
|
U64 startx = 0;
|
|
U64 endx = 0;
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &startx);
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &endx);
|
|
str8_list_pushf(temp.arena, &list, "%llx, %llx", startx, endx);
|
|
} break;
|
|
case DW_RngListEntryKind_StartEnd: {
|
|
U64 start = 0;
|
|
U64 end = 0;
|
|
cursor += dw_based_range_read_address(base, range, cursor, segment_ranges, segment_selector_size, address_size, &start);
|
|
cursor += dw_based_range_read_address(base, range, cursor, segment_ranges, segment_selector_size, address_size, &end);
|
|
str8_list_pushf(temp.arena, &list, "%llx, %llx", start, end);
|
|
} break;
|
|
case DW_RngListEntryKind_StartLength: {
|
|
U64 start = 0;
|
|
U64 length = 0;
|
|
cursor += dw_based_range_read_address(base, range, cursor, segment_ranges, segment_selector_size, address_size, &start);
|
|
cursor += dw_based_range_read_uleb128(base, range, cursor, &length);
|
|
str8_list_pushf(temp.arena, &list, "%llx, %llx", start, length);
|
|
} break;
|
|
}
|
|
|
|
// output row
|
|
String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")});
|
|
rd_printf("%S", print);
|
|
|
|
temp_end(temp);
|
|
}
|
|
rd_unindent();
|
|
rd_newline();
|
|
}
|
|
rd_unindent();
|
|
|
|
scratch_end(scratch);
|
|
#endif
|
|
}
|
|
|
|
internal void
|
|
dw_format_string_table(Arena *arena, String8List *out, String8 indent, DW_Input *input, DW_SectionKind sec)
|
|
{
|
|
NotImplemented;
|
|
#if 0
|
|
void *base = dw_base_from_sec(sections, sec);
|
|
Rng1U64 range = dw_range_from_sec(sections, sec);
|
|
|
|
if (dim_1u64(range) == 0) {
|
|
return;
|
|
}
|
|
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
|
|
rd_printf("# %S", sections->v[sec].name);
|
|
rd_indent();
|
|
for (U64 cursor = 0; cursor < dim_1u64(range); ) {
|
|
U64 unit_offset = cursor;
|
|
|
|
U64 unit_length = 0;
|
|
cursor += dw_based_range_read_length(base, range, cursor, &unit_length);
|
|
U64 unit_opl = cursor + unit_length;
|
|
|
|
DW_Version version = 0;
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &version);
|
|
|
|
if (version != DW_Version_2) {
|
|
rd_warningf("Version value must be 2");
|
|
}
|
|
|
|
B32 is_dwarf64 = unit_length > max_U32;
|
|
U32 sec_offset_size = is_dwarf64 ? sizeof(U64) : sizeof(U32);
|
|
|
|
U64 debug_info_offset = 0, debug_info_length = 0;
|
|
cursor += dw_based_range_read(base, range, cursor, sec_offset_size, &debug_info_offset);
|
|
cursor += dw_based_range_read(base, range, cursor, sec_offset_size, &debug_info_length);
|
|
|
|
rd_printf("Unit @ %#llx, length %llu", unit_offset, unit_length);
|
|
rd_printf("Version: %u", version);
|
|
rd_printf("Debug info offset: %#llx", debug_info_offset);
|
|
rd_printf("Debug info length: %#llx", debug_info_length);
|
|
|
|
rd_printf("Entries:");
|
|
rd_indent();
|
|
rd_printf("%-8s %-8s", "Offset", "String");
|
|
for (; cursor < unit_opl; ) {
|
|
U64 info_offset = 0;
|
|
cursor += dw_based_range_read(base, range, cursor, sec_offset_size, &info_offset);
|
|
String8 string = dw_based_range_read_string(base, range, cursor);
|
|
cursor += (string.size + 1);
|
|
|
|
rd_printf("%08llx %S", info_offset, string);
|
|
}
|
|
rd_unindent();
|
|
rd_newline();
|
|
}
|
|
rd_unindent();
|
|
|
|
scratch_end(scratch);
|
|
#endif
|
|
}
|
|
|
|
internal void
|
|
dw_print_debug_pubnames(Arena *arena, String8List *out, String8 indent, DW_Input *input)
|
|
{
|
|
dw_format_string_table(arena, out, indent, input, DW_Section_PubNames);
|
|
}
|
|
|
|
internal void
|
|
dw_print_debug_pubtypes(Arena *arena, String8List *out, String8 indent, DW_Input *input)
|
|
{
|
|
dw_format_string_table(arena, out, indent, input, DW_Section_PubTypes);
|
|
}
|
|
|
|
internal void
|
|
dw_print_debug_line_str(Arena *arena, String8List *out, String8 indent, DW_Input *input)
|
|
{
|
|
NotImplemented;
|
|
#if 0
|
|
void *base = dw_base_from_sec(sections, DW_Section_LineStr);
|
|
Rng1U64 range = dw_range_from_sec(sections, DW_Section_LineStr);
|
|
|
|
if (dim_1u64(range) == 0) {
|
|
return;
|
|
}
|
|
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
|
|
rd_printf("# %S", sections->v[DW_Section_LineStr].name);
|
|
rd_indent();
|
|
|
|
rd_printf("%-8s %-8s", "Offset", "String");
|
|
for (U64 cursor = 0; cursor < dim_1u64(range); ) {
|
|
U64 offset = cursor;
|
|
String8 string = dw_based_range_read_string(base, range, cursor);
|
|
cursor += (string.size + 1);
|
|
rd_printf("%08llX %S", offset, string);
|
|
}
|
|
rd_unindent();
|
|
|
|
scratch_end(scratch);
|
|
#endif
|
|
}
|
|
|
|
internal void
|
|
dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Input *input)
|
|
{
|
|
NotImplemented;
|
|
#if 0
|
|
void *base = dw_base_from_sec(sections, DW_Section_StrOffsets);
|
|
Rng1U64 range = dw_range_from_sec(sections, DW_Section_StrOffsets);
|
|
|
|
void *debug_str_base = dw_base_from_sec(sections, DW_Section_Str);
|
|
Rng1U64 debug_str_range = dw_range_from_sec(sections, DW_Section_Str);
|
|
|
|
if (dim_1u64(range) == 0) {
|
|
return;
|
|
}
|
|
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
|
|
rd_printf("# %S", sections->v[DW_Section_StrOffsets].name);
|
|
rd_indent();
|
|
for (U64 cursor = 0; cursor < dim_1u64(range); ) {
|
|
U64 unit_offset = cursor;
|
|
|
|
U64 unit_length = 0;
|
|
cursor += dw_based_range_read_length(base, range, cursor, &unit_length);
|
|
U64 unit_opl = cursor + unit_length;
|
|
|
|
DW_Version version = 0;
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &version);
|
|
if (version != DW_Version_5) {
|
|
rd_warningf("Version value must be 5 (DWARF5 sepc, Feb 13, 2017)");
|
|
}
|
|
|
|
U16 padding = 0;
|
|
cursor += dw_based_range_read_struct(base, range, cursor, &padding);
|
|
if (padding != 0) {
|
|
rd_warningf("unexpected padding byte");
|
|
}
|
|
|
|
B32 is_dwarf64 = unit_length > max_U32;
|
|
U32 offset_size = is_dwarf64 ? sizeof(U64) : sizeof(U32);
|
|
|
|
rd_printf("Unit @ %#llX, length %lld", unit_offset, unit_length);
|
|
rd_printf("Version: %d", version);
|
|
rd_printf("Padding: %d", padding);
|
|
rd_indent();
|
|
rd_printf("%-8s %-8s", "@", "Offset");
|
|
for (; cursor < unit_opl; ) {
|
|
U64 read_at = cursor;
|
|
U64 offset = 0;
|
|
cursor += dw_based_range_read(base, range, cursor, offset_size, &offset);
|
|
rd_printf("%08llx %08llx", read_at, offset);
|
|
if (dim_1u64(debug_str_range) > 0) {
|
|
String8 string = dw_based_range_read_string(debug_str_base, debug_str_range, offset);
|
|
rd_printf(" %S", string);
|
|
}
|
|
rd_newline();
|
|
}
|
|
rd_unindent();
|
|
rd_newline();
|
|
}
|
|
rd_unindent();
|
|
|
|
scratch_end(scratch);
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Dump Entry Point
|
|
|
|
internal String8List
|
|
dw_dump_list_from_sections(Arena *arena, DW_Input *input, Arch arch, DW_DumpSubsetFlags subset_flags)
|
|
{
|
|
String8List strings = {0};
|
|
String8 indent = str8_lit(" ");
|
|
#define dump(str) str8_list_push(arena, &strings, (str))
|
|
#define dumpf(...) str8_list_pushf(arena, &strings, __VA_ARGS__)
|
|
#define DumpSubset(name) if(subset_flags & DW_DumpSubsetFlag_##name) DeferLoop(dumpf("// %S\n\n", dw_name_title_from_dump_subset_table[DW_DumpSubset_##name]), dump(str8_lit("\n")))
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
Rng1U64Array segment_vranges = {0};
|
|
DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, input);
|
|
Rng1U64List unit_ranges_list = dw_unit_ranges_from_data(scratch.arena, input->sec[DW_Section_Info].data);
|
|
Rng1U64Array unit_ranges = rng1u64_array_from_list(scratch.arena, &unit_ranges_list);
|
|
B32 relaxed = 1;
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_info
|
|
//
|
|
DumpSubset(DebugInfo)
|
|
{
|
|
for EachIndex(unit_idx, unit_ranges.count)
|
|
{
|
|
Temp unit_temp = temp_begin(scratch.arena);
|
|
|
|
//- rjf: unpack unit
|
|
Rng1U64 unit_range = unit_ranges.v[unit_idx];
|
|
DW_CompUnit unit = dw_cu_from_info_off(unit_temp.arena, input, lu_input, unit_range.min, relaxed);
|
|
String8 unit_dir = dw_string_from_tag_attrib_kind(input, &unit, unit.tag, DW_AttribKind_CompDir );
|
|
String8 unit_name = dw_string_from_tag_attrib_kind(input, &unit, unit.tag, DW_AttribKind_Name );
|
|
String8 stmt_list = dw_line_ptr_from_tag_attrib_kind(input, &unit, unit.tag, DW_AttribKind_StmtList);
|
|
DW_LineVMHeader line_vm = {0};
|
|
dw_read_line_vm_header(unit_temp.arena, stmt_list, 0, input, unit_dir, unit_name, unit.address_size, unit.str_offsets_lu, &line_vm);
|
|
|
|
//- rjf: log top-level unit info
|
|
dumpf("unit: // compile_unit[%I64u]\n{\n", unit_idx);
|
|
dumpf(" version: %u\n", unit.version);
|
|
dumpf(" address_size: %I64u\n", unit.address_size);
|
|
dumpf(" abbrev_off: 0x%I64x\n", unit.abbrev_off);
|
|
dumpf(" info_range: [0x%I64x, 0x%I64x) // (%M)\n", unit.info_range.min, unit.info_range.max, dim_1u64(unit.info_range));
|
|
|
|
//- rjf: log tags
|
|
S64 tag_depth = 0;
|
|
U64 tag_idx = 0;
|
|
for(U64 info_off = unit.first_tag_info_off; info_off < unit.info_range.max; tag_idx += 1)
|
|
{
|
|
Temp tag_temp = temp_begin(scratch.arena);
|
|
|
|
// rjf: unpack tag
|
|
String8 tag_indent = str8_prefix(indent, (tag_depth+1)*2);
|
|
U64 tag_info_off = info_off;
|
|
DW_Tag tag = {0};
|
|
info_off += dw_read_tag_cu(tag_temp.arena, input, &unit, tag_info_off, &tag);
|
|
|
|
// rjf: log top-level tag info
|
|
dumpf("%Stag: // compile_unit[%I64u].tag[%I64u]\n%S{\n", tag_indent, unit_idx, tag_idx, tag_indent);
|
|
dumpf("%S kind: %S\n", tag_indent, dw_string_from_tag_kind(tag_temp.arena, tag.kind));
|
|
dumpf("%S info_off: 0x%I64x\n", tag_indent, tag_info_off);
|
|
dumpf("%S abbrev_id: %I64u\n", tag_indent, tag.abbrev_id);
|
|
|
|
// rjf: log attribs
|
|
for(DW_AttribNode *attrib_n = tag.attribs.first;
|
|
attrib_n != 0;
|
|
attrib_n = attrib_n->next)
|
|
{
|
|
Temp attrib_temp = temp_begin(tag_temp.arena);
|
|
DW_Attrib *attrib = &attrib_n->v;
|
|
|
|
// rjf: log attrib begin
|
|
dumpf("%S attrib: {");
|
|
|
|
// rjf: log basic info
|
|
dumpf(" off: 0x%I64x", attrib->info_off);
|
|
dumpf(", kind: %S", dw_string_from_attrib_kind(attrib_temp.arena, unit.version, unit.ext, attrib->attrib_kind));
|
|
dumpf(", form_kind: %S", dw_string_from_form_kind(attrib_temp.arena, unit.version, attrib->form_kind));
|
|
|
|
// rjf: log attrib's value based on vlass
|
|
dumpf(", ");
|
|
DW_AttribClass value_class = dw_value_class_from_attrib(&unit, attrib);
|
|
switch(value_class)
|
|
{
|
|
default: {dumpf("`unknown value class`");}break;
|
|
case DW_AttribClass_Undefined: {dumpf("`undefined value class`");}break;
|
|
case DW_AttribClass_Address: {dumpf("0x%I64x", dw_address_from_attrib(input, &unit, attrib));}break;
|
|
case DW_AttribClass_Const: {dumpf("0x%I64x", dw_const_u64_from_attrib(input, &unit, attrib));}break;
|
|
case DW_AttribClass_Block:
|
|
{
|
|
String8 block = dw_block_from_attrib(input, &unit, attrib);
|
|
String8List block_strs = numeric_str8_list_from_data(attrib_temp.arena, 16, block, 1);
|
|
String8 block_str = str8_list_join(attrib_temp.arena, &block_strs, &(StringJoin){.sep = str8_lit(", ")});
|
|
dump(block_str);
|
|
}break;
|
|
case DW_AttribClass_ExprLoc:
|
|
{
|
|
String8 exprloc = dw_exprloc_from_attrib(input, &unit, attrib);
|
|
String8 exprloc_str = dw_single_line_string_from_expression(attrib_temp.arena, exprloc, unit_range.min, unit.address_size, arch, unit.version, unit.ext, unit.format);
|
|
dump(exprloc_str);
|
|
}break;
|
|
case DW_AttribClass_Flag:
|
|
{
|
|
B32 flag = dw_flag_from_attrib(input, &unit, attrib);
|
|
dumpf("%llu: %s", flag, flag == 0 ? "false" : "true");
|
|
}break;
|
|
case DW_AttribClass_LinePtr:
|
|
case DW_AttribClass_LocListPtr:
|
|
case DW_AttribClass_MacPtr:
|
|
case DW_AttribClass_RngListPtr:
|
|
case DW_AttribClass_RngList:
|
|
case DW_AttribClass_StrOffsetsPtr:
|
|
case DW_AttribClass_AddrPtr:
|
|
{
|
|
if(attrib->form_kind == DW_Form_SecOffset)
|
|
{
|
|
dumpf("0x%I64x", attrib->form.sec_offset);
|
|
}
|
|
else
|
|
{
|
|
dumpf("`unexpected form kind %S`", dw_string_from_form_kind(attrib_temp.arena, unit.version, attrib->form_kind));
|
|
}
|
|
}break;
|
|
case DW_AttribClass_Reference:
|
|
{
|
|
if(attrib->form_kind == DW_Form_Ref1 ||
|
|
attrib->form_kind == DW_Form_Ref2 ||
|
|
attrib->form_kind == DW_Form_Ref4 ||
|
|
attrib->form_kind == DW_Form_Ref8 ||
|
|
attrib->form_kind == DW_Form_RefUData)
|
|
{
|
|
U64 info_off = unit.info_range.min + attrib->form.ref;
|
|
dumpf("0x%I64x", info_off);
|
|
if(!contains_1u64(unit.info_range, attrib->form.ref))
|
|
{
|
|
dumpf(": `(out of this unit's bounds)`");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dumpf("0x%I64x", attrib->form.ref);
|
|
}
|
|
}break;
|
|
case DW_AttribClass_String:
|
|
{
|
|
if(attrib->form_kind == DW_Form_Strp)
|
|
{
|
|
dumpf("0x%I64x", attrib->form.sec_offset);
|
|
}
|
|
String8 string = dw_string_from_attrib(input, &unit, attrib);
|
|
dumpf(": \"%S\"", string);
|
|
}break;
|
|
}
|
|
|
|
// rjf: extend attrib's value with enum info
|
|
switch(attrib->attrib_kind)
|
|
{
|
|
case DW_AttribKind_Language:
|
|
{
|
|
DW_Language lang = dw_const_u64_from_attrib(input, &unit, attrib);
|
|
dumpf(": %S", dw_string_from_language(attrib_temp.arena, lang));
|
|
}break;
|
|
case DW_AttribKind_DeclFile:
|
|
{
|
|
U64 file_idx = dw_const_u64_from_attrib(input, &unit, attrib);
|
|
DW_LineFile *file = dw_file_from_attrib(&unit, &line_vm, attrib);
|
|
if(file != 0)
|
|
{
|
|
dumpf(": %S", dw_path_from_file(attrib_temp.arena, &line_vm, file));
|
|
}
|
|
}break;
|
|
case DW_AttribKind_DeclLine:
|
|
{
|
|
dumpf(": %I64u", dw_const_u64_from_attrib(input, &unit, attrib));
|
|
}break;
|
|
case DW_AttribKind_Inline:
|
|
{
|
|
DW_InlKind inl = dw_const_u64_from_attrib(input, &unit, attrib);
|
|
dumpf(": %S", dw_string_from_inl(attrib_temp.arena, inl));
|
|
}break;
|
|
case DW_AttribKind_Accessibility:
|
|
{
|
|
DW_AccessKind access = dw_const_u64_from_attrib(input, &unit, attrib);
|
|
dumpf(": %S", dw_string_from_access_kind(attrib_temp.arena, access));
|
|
}break;
|
|
case DW_AttribKind_CallingConvention:
|
|
{
|
|
DW_CallingConventionKind calling_convetion = dw_const_u64_from_attrib(input, &unit, attrib);
|
|
dumpf(": %S", dw_string_from_calling_convetion(attrib_temp.arena, calling_convetion));
|
|
}break;
|
|
case DW_AttribKind_Encoding:
|
|
{
|
|
DW_ATE encoding = dw_const_u64_from_attrib(input, &unit, attrib);
|
|
dumpf(": %S", dw_string_from_attrib_type_encoding(attrib_temp.arena, encoding));
|
|
}break;
|
|
}
|
|
|
|
// rjf: log attrib end
|
|
dumpf(" }\n");
|
|
|
|
temp_end(attrib_temp);
|
|
}
|
|
|
|
// rjf: log tag closes
|
|
if(!tag.has_children || tag.abbrev_id == 0)
|
|
{
|
|
dumpf("%S}\n", tag_indent);
|
|
}
|
|
|
|
// rjf: indent/unindent
|
|
if(tag.has_children)
|
|
{
|
|
tag_depth += 1;
|
|
}
|
|
if(tag.abbrev_id)
|
|
{
|
|
tag_depth -= 1;
|
|
}
|
|
|
|
temp_end(tag_temp);
|
|
}
|
|
temp_end(unit_temp);
|
|
dumpf("} // compile_unit[/%u]\n\n", unit_idx);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_abbrev
|
|
//
|
|
DumpSubset(DebugAbbrev)
|
|
{
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
DW_Section abbrev = input->sec[DW_Section_Abbrev];
|
|
S64 depth = 0;
|
|
U64 idx = 0;
|
|
for(U64 cursor = 0; cursor < abbrev.data.size; idx += 1)
|
|
{
|
|
// rjf: read id & advance
|
|
U64 id_off = cursor;
|
|
U64 id = 0;
|
|
cursor += str8_deserial_read_uleb128(abbrev.data, cursor, &id);
|
|
if(id == 0) { continue; }
|
|
|
|
// rjf: unpack abbrev
|
|
U64 tag = 0;
|
|
U8 has_children = 0;
|
|
cursor += str8_deserial_read_uleb128(abbrev.data, cursor, &tag);
|
|
cursor += str8_deserial_read_struct(abbrev.data, cursor, &has_children);
|
|
|
|
// rjf: log abbrev
|
|
Temp temp = temp_begin(scratch.arena);
|
|
dumpf("abbrev: // abbrev[%I64u]\n{\n", idx);
|
|
dumpf(" offset: 0x%I64x\n", id_off);
|
|
dumpf(" id: %I64u\n", id);
|
|
dumpf(" tag_kind: %S\n", dw_string_from_tag_kind(temp.arena, tag));
|
|
dumpf(" has_children: %s\n", has_children ? "true" : "false");
|
|
for(;;)
|
|
{
|
|
U64 attrib_off = cursor;
|
|
U64 attrib_id = 0, form_id = 0;
|
|
cursor += str8_deserial_read_uleb128(abbrev.data, cursor, &attrib_id);
|
|
cursor += str8_deserial_read_uleb128(abbrev.data, cursor, &form_id);
|
|
if(attrib_id == 0) { break; }
|
|
String8 attrib_str = dw_string_from_attrib_kind(temp.arena, DW_Version_Last, DW_Ext_All, attrib_id);
|
|
String8 form_str = dw_string_from_form_kind(temp.arena, DW_Version_Last, form_id);
|
|
dumpf(" attrib: { offset: 0x%I64x, kind: %S, form_kind: %S }\n", attrib_off, attrib_str, form_str);
|
|
}
|
|
dumpf("}\n");
|
|
temp_end(temp);
|
|
}
|
|
scratch_end(scratch);
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_line
|
|
//
|
|
DumpSubset(DebugLine)
|
|
{
|
|
for EachIndex(unit_idx, unit_ranges.count)
|
|
{
|
|
Temp unit_temp = temp_begin(scratch.arena);
|
|
|
|
// rjf: unpack unit
|
|
String8 unit_data = str8_substr(input->sec[DW_Section_Line].data, unit_ranges.v[unit_idx]);
|
|
String8 cu_dir = {0};
|
|
String8 cu_name = {0};
|
|
DW_ListUnit cu_str_offsets = {0};
|
|
DW_LineVMHeader line_vm = {0};
|
|
U64 line_vm_size = dw_read_line_vm_header(unit_temp.arena, unit_data, 0, input, cu_dir, cu_name, line_vm.address_size, &cu_str_offsets, &line_vm);
|
|
if(line_vm_size == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// rjf: begin logging line table
|
|
dumpf("line_table: // line_table[%I64u]\n{\n", unit_idx);
|
|
|
|
// rjf: log line table header
|
|
DeferLoop(dumpf(" header:\n {\n"), dumpf(" }\n\n"))
|
|
{
|
|
String8List opcode_length_strings = numeric_str8_list_from_data(unit_temp.arena, 16, str8(line_vm.opcode_lens, line_vm.num_opcode_lens), 1);
|
|
String8 opcode_lengths_string = str8_list_join(arena, &opcode_length_strings, &(StringJoin){.sep = str8_lit(", ")});
|
|
dumpf(" version: %u\n", line_vm.version );
|
|
dumpf(" line_table_off: 0x%I64x\n", line_vm.unit_range.min );
|
|
dumpf(" line_table_size: %I64u\n", dim_1u64(line_vm.unit_range) );
|
|
dumpf(" address_size: %u\n", line_vm.address_size );
|
|
dumpf(" segment_selector_size: %u\n", line_vm.segment_selector_size);
|
|
dumpf(" header_length: %I64u\n", line_vm.header_length );
|
|
dumpf(" min_instruction_length: %u\n", line_vm.min_inst_len );
|
|
dumpf(" max_ops_for_instruction: %u\n", line_vm.max_ops_for_inst );
|
|
dumpf(" default_is_stmt: %u\n", line_vm.default_is_stmt );
|
|
dumpf(" line_base: %d\n", line_vm.line_base );
|
|
dumpf(" line_range: %u\n", line_vm.line_range );
|
|
dumpf(" opcode_base: %u\n", line_vm.opcode_base );
|
|
dumpf(" opcode_lengths: %S\n", opcode_lengths_string );
|
|
}
|
|
|
|
// rjf: log directory table
|
|
DeferLoop(dumpf(" directory_table:\n {\n"), dumpf(" }\n\n"))
|
|
{
|
|
dumpf(" // %-4s %-8s\n", "no.", "name");
|
|
for EachIndex(dir_idx, line_vm.dir_table.count)
|
|
{
|
|
dumpf(" { %-4llu %S }\n", dir_idx, line_vm.dir_table.v[dir_idx]);
|
|
}
|
|
}
|
|
|
|
// rjf: log file table
|
|
DeferLoop(dumpf(" file_table:\n {\n"), dumpf(" }\n\n"))
|
|
{
|
|
dumpf(" // %-4s %-8s %-8s %-33s %-8s %-8s\n", "no.", "dir_idx", "time", "md5", "size", "name");
|
|
for EachIndex(file_idx, line_vm.file_table.count)
|
|
{
|
|
DW_LineFile *file = &line_vm.file_table.v[file_idx];
|
|
dumpf(" { %-4llu %-8llu %-8llu %016llx-%016llx %-8llu %S }\n",
|
|
file_idx,
|
|
file->dir_idx,
|
|
file->modify_time,
|
|
file->md5_digest.u64[1],
|
|
file->md5_digest.u64[0],
|
|
file->file_size,
|
|
file->file_name);
|
|
}
|
|
}
|
|
|
|
// rjf: log opcodes
|
|
DeferLoop(dumpf(" opcodes:\n {\n"), dumpf(" }\n\n"))
|
|
{
|
|
String8 opcodes = str8_skip(unit_data, line_vm_size);
|
|
B32 end_of_seq = 0;
|
|
DW_LineVMState vm_state = {0};
|
|
dw_line_vm_reset(&vm_state, line_vm.default_is_stmt);
|
|
for(U64 cursor = 0; cursor < opcodes.size;)
|
|
{
|
|
Temp opcode_temp = temp_begin(unit_temp.arena);
|
|
String8List opcode_fmt = {0};
|
|
|
|
// opcode offset
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "[%08llx]", cursor);
|
|
|
|
// parse opcode
|
|
U8 opcode = 0;
|
|
cursor += str8_deserial_read_struct(opcodes, cursor, &opcode);
|
|
|
|
// push opcode id
|
|
String8 opcode_str = dw_string_from_std_opcode(opcode_temp.arena, opcode);
|
|
str8_list_push(arena, &opcode_fmt, opcode_str);
|
|
|
|
// format operands
|
|
switch(opcode)
|
|
{
|
|
default:
|
|
{
|
|
if(opcode >= line_vm.opcode_base)
|
|
{
|
|
U32 adjusted_opcode = 0;
|
|
U32 op_advance = 0;
|
|
S32 line_advance = 0;
|
|
U64 addr_advance = 0;
|
|
if(line_vm.line_range > 0 && line_vm.max_ops_for_inst > 0)
|
|
{
|
|
adjusted_opcode = (U32)(opcode - line_vm.opcode_base);
|
|
op_advance = adjusted_opcode / line_vm.line_range;
|
|
line_advance = (S32)line_vm.line_base + ((S32)adjusted_opcode) % (S32)line_vm.line_range;
|
|
addr_advance = line_vm.min_inst_len * ((vm_state.op_index+op_advance) / line_vm.max_ops_for_inst);
|
|
}
|
|
vm_state.address += addr_advance;
|
|
vm_state.op_index = (vm_state.op_index + op_advance) % line_vm.max_ops_for_inst;
|
|
vm_state.line = (U32)((S32)vm_state.line + line_advance);
|
|
vm_state.basic_block = 0;
|
|
vm_state.prologue_end = 0;
|
|
vm_state.epilogue_begin = 0;
|
|
vm_state.discriminator = 0;
|
|
end_of_seq = 0;
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "advance line by %d, advance address by %lld", line_advance, addr_advance);
|
|
}
|
|
else
|
|
{
|
|
if(opcode > 0 && opcode <= line_vm.num_opcode_lens)
|
|
{
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "skip operands:");
|
|
U64 num_operands = line_vm.opcode_lens[opcode - 1];
|
|
for(U8 i = 0; i < num_operands; i += 1)
|
|
{
|
|
U64 operand = 0;
|
|
cursor += str8_deserial_read_uleb128(opcodes, cursor, &operand);
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, " %llx", operand);
|
|
}
|
|
}
|
|
}
|
|
}break;
|
|
case DW_StdOpcode_Copy:
|
|
{
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "Line = %u, Column = %u, Address = %#llx", vm_state.line, vm_state.column, vm_state.address);
|
|
end_of_seq = 0;
|
|
vm_state.discriminator = 0;
|
|
vm_state.basic_block = 0;
|
|
vm_state.prologue_end = 0;
|
|
vm_state.epilogue_begin = 0;
|
|
}break;
|
|
case DW_StdOpcode_AdvancePc:
|
|
{
|
|
U64 advance = 0;
|
|
cursor += str8_deserial_read_uleb128(opcodes, cursor, &advance);
|
|
dw_line_vm_advance(&vm_state, advance, line_vm.min_inst_len, line_vm.max_ops_for_inst);
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "advance %#llx ; current address %#llx", advance, vm_state.address);
|
|
}break;
|
|
case DW_StdOpcode_AdvanceLine:
|
|
{
|
|
S64 advance = 0;
|
|
cursor += str8_deserial_read_sleb128(opcodes, cursor, &advance);
|
|
vm_state.line += advance;
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "advance %lld ; current line %u", advance, vm_state.line);
|
|
}break;
|
|
case DW_StdOpcode_SetFile:
|
|
{
|
|
U64 file_idx = 0;
|
|
cursor += str8_deserial_read_uleb128(opcodes, cursor, &file_idx);
|
|
vm_state.file_index = file_idx;
|
|
String8 path = dw_path_from_file_idx(opcode_temp.arena, &line_vm, file_idx);
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%llu \"%S\"", file_idx, path);
|
|
}break;
|
|
case DW_StdOpcode_SetColumn:
|
|
{
|
|
U64 column = 0;
|
|
cursor += str8_deserial_read_uleb128(opcodes, cursor, &column);
|
|
vm_state.column = column;
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%llu", column);
|
|
}break;
|
|
case DW_StdOpcode_NegateStmt:
|
|
{
|
|
vm_state.is_stmt = !vm_state.is_stmt;
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "is_stmt = %u", vm_state.is_stmt);
|
|
}break;
|
|
case DW_StdOpcode_SetBasicBlock:
|
|
{
|
|
vm_state.basic_block = 1;
|
|
}break;
|
|
case DW_StdOpcode_ConstAddPc:
|
|
{
|
|
U64 advance = (0xffu - line_vm.opcode_base)/line_vm.line_range;
|
|
dw_line_vm_advance(&vm_state, advance, line_vm.min_inst_len, line_vm.max_ops_for_inst);
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%lld ; address %#llx", advance, vm_state.address);
|
|
}break;
|
|
case DW_StdOpcode_FixedAdvancePc:
|
|
{
|
|
U64 operand = 0;
|
|
cursor += str8_deserial_read_struct(opcodes, cursor, &operand);
|
|
vm_state.address += operand;
|
|
vm_state.op_index = 0;
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%llu", operand);
|
|
}break;
|
|
case DW_StdOpcode_SetPrologueEnd:
|
|
{
|
|
vm_state.prologue_end = 1;
|
|
}break;
|
|
case DW_StdOpcode_SetEpilogueBegin:
|
|
{
|
|
vm_state.epilogue_begin = 1;
|
|
}break;
|
|
case DW_StdOpcode_SetIsa:
|
|
{
|
|
U64 v = 0;
|
|
cursor += str8_deserial_read_uleb128(opcodes, cursor, &v);
|
|
vm_state.isa = v;
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%llu", v);
|
|
}break;
|
|
case DW_StdOpcode_ExtendedOpcode:
|
|
{
|
|
U64 length = 0;
|
|
U8 ext_opcode = 0;
|
|
cursor += str8_deserial_read_uleb128(opcodes, cursor, &length);
|
|
U64 opcode_end = cursor + length;
|
|
cursor += str8_deserial_read_struct(opcodes, cursor, &ext_opcode);
|
|
String8 ext_opcode_str = dw_string_from_ext_opcode(opcode_temp.arena, ext_opcode);
|
|
//str8_list_pushf(opcode_temp.arena, &opcode_fmt, "length: %u", length);
|
|
str8_list_push(opcode_temp.arena, &opcode_fmt, ext_opcode_str);
|
|
switch(ext_opcode)
|
|
{
|
|
case DW_ExtOpcode_EndSequence:
|
|
{
|
|
vm_state.end_sequence = 1;
|
|
dw_line_vm_reset(&vm_state, line_vm.default_is_stmt);
|
|
end_of_seq = 1;
|
|
}break;
|
|
case DW_ExtOpcode_SetAddress:
|
|
{
|
|
U64 address = 0;
|
|
cursor += str8_deserial_read(opcodes, cursor, &address, line_vm.address_size, line_vm.address_size);
|
|
vm_state.address = address;
|
|
vm_state.op_index = 0;
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%#llx", address);
|
|
}break;
|
|
case DW_ExtOpcode_DefineFile:
|
|
{
|
|
String8 file_name = {0};
|
|
cursor += str8_deserial_read_cstr(opcodes, cursor, &file_name);
|
|
U64 dir_idx = 0, modify_time = 0, file_size = 0;
|
|
cursor += str8_deserial_read_uleb128(opcodes, cursor, &dir_idx);
|
|
cursor += str8_deserial_read_uleb128(opcodes, cursor, &modify_time);
|
|
cursor += str8_deserial_read_uleb128(opcodes, cursor, &file_size);
|
|
str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%S Dir: %llu, Time: %llu, Size: %llu", file_name, dir_idx, modify_time, file_size);
|
|
}break;
|
|
case DW_ExtOpcode_SetDiscriminator:
|
|
{
|
|
U64 v = 0;
|
|
cursor += str8_deserial_read_uleb128(opcodes, cursor, &v);
|
|
vm_state.discriminator = v;
|
|
str8_list_pushf(arena, &opcode_fmt, "%llu", v);
|
|
}break;
|
|
}
|
|
cursor = opcode_end;
|
|
}break;
|
|
}
|
|
String8 string = str8_list_join(opcode_temp.arena, &opcode_fmt, &(StringJoin){.sep=str8_lit(" ")});
|
|
dumpf("%S\n", string);
|
|
temp_end(opcode_temp);
|
|
}
|
|
}
|
|
temp_end(unit_temp);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_str
|
|
//
|
|
DumpSubset(DebugStr) DeferLoop(dumpf("strings:\n{\n"), dumpf("}\n\n"))
|
|
{
|
|
String8 data = input->sec[DW_Section_Str].data;
|
|
for(U64 cursor = 0, read_size = 0; cursor < data.size; cursor += read_size)
|
|
{
|
|
String8 string = {0};
|
|
read_size = str8_deserial_read_cstr(data, cursor, &string);
|
|
dumpf(" { 0x%08I64x %llu \"%S\" }\n", cursor, string.size, string);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_loc
|
|
//
|
|
DumpSubset(DebugLoc)
|
|
{
|
|
// dw_print_debug_loc(arena, out, indent, input, arch, image_type, relaxed);
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_ranges
|
|
//
|
|
DumpSubset(DebugRanges)
|
|
{
|
|
// dw_print_debug_ranges(arena, out, indent, input, arch, image_type, relaxed);
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_aranges
|
|
//
|
|
DumpSubset(DebugARanges)
|
|
{
|
|
// dw_print_debug_aranges(arena, out, indent, input);
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_addr
|
|
//
|
|
DumpSubset(DebugAddr)
|
|
{
|
|
// dw_print_debug_addr(arena, out, indent, input);
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_loclists
|
|
//
|
|
DumpSubset(DebugLocLists)
|
|
{
|
|
// dw_print_debug_loclists(arena, out, indent, input, segment_vranges, arch);
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_rnglists
|
|
//
|
|
DumpSubset(DebugRngLists)
|
|
{
|
|
// dw_print_debug_rnglists(arena, out, indent, input, segment_vranges);
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_pubnames
|
|
//
|
|
DumpSubset(DebugPubNames)
|
|
{
|
|
// dw_print_debug_pubnames(arena, out, indent, input);
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_pubtypes
|
|
//
|
|
DumpSubset(DebugPubTypes)
|
|
{
|
|
// dw_print_debug_pubtypes(arena, out, indent, input);
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_linestr
|
|
//
|
|
DumpSubset(DebugLineStr)
|
|
{
|
|
// dw_print_debug_line_str(arena, out, indent, input);
|
|
}
|
|
|
|
//////////////////////////////
|
|
//- rjf: dump .debug_stroffs
|
|
//
|
|
DumpSubset(DebugStrOffsets)
|
|
{
|
|
// dw_print_debug_str_offsets(arena, out, indent, input);
|
|
}
|
|
|
|
scratch_end(scratch);
|
|
#undef DumpSubset
|
|
#undef dumpf
|
|
#undef dump
|
|
return strings;
|
|
}
|