diff --git a/obsolete/dwarf/dwarf_dump_old.c b/obsolete/dwarf/dwarf_dump_old.c new file mode 100644 index 00000000..9b6d6481 --- /dev/null +++ b/obsolete/dwarf/dwarf_dump_old.c @@ -0,0 +1,2220 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#define dw_indent() do { indent += 1; } while (0) +#define dw_unindent() do { indent -= 1; } while (0) +#define dw_print(string) dw_print_ (arena, strings, indent, string) +#define dw_printf(...) dw_printf_(arena, strings, indent, __VA_ARGS__) +static char g_spaces[] = " "; + +internal void +dw_print_(Arena *arena, String8List *out, int indent, String8 string) +{ + Temp scratch = scratch_begin(&arena, 1); + str8_list_pushf(arena, out, "%.*s%S", Min(indent * 2, sizeof(g_spaces)), g_spaces, string); + scratch_end(scratch); +} + +internal void +dw_printf_(Arena *arena, String8List *out, int indent, char *fmt, ...) +{ + Temp scratch = scratch_begin(&arena, 1); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + dw_print_(arena, out, indent, string); + va_end(args); + scratch_end(scratch); +} + +internal Rng1U64Array +dw_get_info_ranges(DW_Dumper *dumper) +{ + if (!(dumper->cache_flags & DW_DumperCacheFlag_InfoRanges)) { + dumper->cache.info_ranges = dw_unit_ranges_from_data_arr(dumper->arena, dumper->input->sec[DW_Section_Info].data); + } + return dumper->cache.info_ranges; +} + +internal DW_CompUnit * +dw_get_cu_arr(DW_Dumper *dumper) +{ + if (!(dumper->cache_flags & DW_DumperCacheFlag_CuArr)) { + Rng1U64Array info_ranges = dw_get_info_ranges(dumper); + DW_ListUnitInput lu_input = dw_list_unit_input_from_input(dumper->arena, dumper->input); + dumper->cache.cu_arr = push_array(dumper->arena, DW_CompUnit, info_ranges.count); + for EachIndex(cu_idx, info_ranges.count) { + dumper->cache.cu_arr[cu_idx] = dw_cu_from_info_off(dumper->arena, dumper->input, lu_input, info_ranges.v[cu_idx].min, dumper->is_relaxed); + } + } + return dumper->cache.cu_arr; +} + +internal HashTable * +dw_get_line_vm_map(DW_Dumper *dumper) +{ + if (!(dumper->cache_flags & DW_DumperCacheFlag_LineVmMap)) { + Rng1U64Array unit_ranges = dw_unit_ranges_from_data_arr(dumper->arena, dumper->input->sec[DW_Section_Line].data); + dumper->cache.line_vm_map = hash_table_init(dumper->arena, unit_ranges.count * 2); + } + return dumper->cache.line_vm_map; +} + +internal DW_TagTree * +dw_get_tag_trees(DW_Dumper *dumper) +{ + if (!(dumper->cache_flags & DW_DumperCacheFlag_TagTrees)) { + Rng1U64Array info_ranges = dw_get_info_ranges(dumper); + DW_CompUnit *cu_arr = dw_get_cu_arr(dumper); + dumper->cache.tag_trees = push_array(dumper->arena, DW_TagTree, info_ranges.count); + for EachIndex(cu_idx, info_ranges.count) { + dumper->cache.tag_trees[cu_idx] = dw_tag_tree_from_cu(dumper->arena, dumper->input, &cu_arr[cu_idx]); + } + } + return dumper->cache.tag_trees; +} + +//////////////////////////////// +//~ rjf: Stringification Helpers + +internal String8List +dw_string_list_from_cfi_program(Arena *arena, + U64 cu_base, + Arch arch, + DW_Version ver, + DW_Ext ext, + DW_Format format, + U64 pc_begin, + DW_CIE *cie, + DW_DecodePtr *decode_ptr_func, + void *deocde_ptr_ud, + String8 program) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + + U64 reg_max = dw_reg_count_from_arch(arch); + U64 pc = pc_begin; + for (U64 cursor = 0, inst_size; cursor < program.size; cursor += inst_size) { + // unpack instruction + DW_CFA_Inst inst = {0}; + DW_CFA_ParseErrorCode error_code = dw_parse_cfa_inst(str8_skip(program, cursor), cie->code_align_factor, cie->data_align_factor, 0, 0, &inst_size, &inst); + if (error_code == DW_CFA_ParseErrorCode_End) { break; } + if (error_code != DW_CFA_ParseErrorCode_NewInst) { + str8_list_pushf(arena, &list, "ERROR: failed to unpack CFA instruction @ 0x%I64", cursor); + break; + } + + // error check operands + DW_CFA_OperandType *operand_types = dw_operand_types_from_cfa_op(inst.opcode); + U64 operand_count = dw_operand_count_from_cfa_opcode(inst.opcode); + for EachIndex(operand_idx, operand_count) { + switch (operand_types[operand_idx]) { + case DW_CFA_OperandType_Null: break; + case DW_CFA_OperandType_Value: break; + case DW_CFA_OperandType_Register: { + if (inst.operands[operand_idx].u64 >= reg_max) { + str8_list_pushf(arena, &list, "ERROR: DW_CFA_%S @ 0x%I64x has an invalid register", + dw_string_from_cfa_opcode(inst.opcode), + cursor); + } + } break; + case DW_CFA_OperandType_Expression: { + DW_Expr expr = dw_expr_from_data(scratch.arena, format, cie->address_size, inst.operands[operand_idx].block); + for EachNode(inst, DW_ExprInst, expr.first) { + if (dw_is_cfa_expr_opcode_invalid(inst->opcode)) { + String8 expr_opcode_str = dw_string_from_expr_op(scratch.arena, ver, ext, inst->opcode); + str8_list_pushf(arena, &list, "ERROR: Exrepssion in DW_CFA_%S @ 0x%I64x has an invalid opcode DW_ExprOp_%S", expr_opcode_str); + } + } + } break; + default: { InvalidPath; } break; + } + } + + // format operands + String8 operand_str = str8_lit("???"); + switch (inst.opcode) { + case DW_CFA_Nop: { operand_str = str8_zero(); } break; + case DW_CFA_SetLoc: { + operand_str = str8f(arena, "0x%X", inst.operands[0].u64); + pc = inst.operands[0].u64; + } break; + case DW_CFA_AdvanceLoc1: { + U64 delta = inst.operands[0].u64; + pc += delta; + operand_str = str8f(arena, "%+u `PC 0x%I64x`", delta, pc); + } break; + case DW_CFA_AdvanceLoc2: { + U64 delta = inst.operands[0].u64; + pc += delta; + operand_str = str8f(arena, "%+u `PC 0x%I64x`", delta, pc); + } break; + case DW_CFA_AdvanceLoc4: { + U64 delta = inst.operands[0].u64; + pc += delta; + operand_str = str8f(arena, "%+u `PC 0x%I64x`", delta, pc); + } break; + case DW_CFA_OffsetExt: { + U64 reg = inst.operands[0].u64; + S64 offset = (S64)inst.operands[1].u64; + operand_str = dw_string_from_reg_off(arena, arch, reg, offset); + } break; + case DW_CFA_RestoreExt: { operand_str = str8_zero(); } break; + case DW_CFA_Undefined: { + operand_str = str8f(arena, "%I64u", inst.operands[0].u64); + } break; + case DW_CFA_SameValue: { + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, 0); + } break; + case DW_CFA_Register: { + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].u64); + } break; + case DW_CFA_RememberState: { operand_str = str8_zero(); } break; + case DW_CFA_RestoreState: { operand_str = str8_zero(); } break; + case DW_CFA_DefCfa: { + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].u64); + } break; + case DW_CFA_DefCfaRegister: { + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, 0); + } break; + case DW_CFA_DefCfaOffset: { + operand_str = str8f(arena, "+%I64u", inst.operands[0].u64); + } break; + case DW_CFA_DefCfaExpr: { + operand_str = dw_string_from_expression(arena, inst.operands[0].block, cu_base, cie->address_size, arch, ver, ext, format); + } break; + case DW_CFA_Expr: { + String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, inst.operands[0].u64, 0); + String8 expr_str = dw_string_from_expression(scratch.arena, inst.operands[1].block, cu_base, cie->address_size, arch, ver, ext, format); + operand_str = str8f(arena, "%S expression %S", reg_str, expr_str); + } break; + case DW_CFA_OffsetExtSf: { + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].s64); + } break; + case DW_CFA_DefCfaSf: { + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].s64); + } break; + case DW_CFA_DefCfaOffsetSf: { operand_str = str8_zero(); } break; + case DW_CFA_ValOffset: { + operand_str = str8f(arena, "value 0x%I64x, offset %+I64d", inst.operands[0].u64, inst.operands[1].u64); + } break; + case DW_CFA_ValOffsetSf: { + operand_str = str8f(arena, "value %I64u, offset %+I64d", inst.operands[0].u64, inst.operands[1].s64); + } break; + case DW_CFA_ValExpr: { + String8 expr_str = dw_string_from_expression(scratch.arena, inst.operands[1].block, cu_base, cie->address_size, arch, ver, ext, format); + operand_str = str8f(arena, "value +%I64u, expression %S", inst.operands[0].u64, expr_str); + } break; + case DW_CFA_AdvanceLoc: { + U64 delta = inst.operands[0].u64; + pc += delta; + operand_str = str8f(arena, "+%I64u `PC 0x%I64x`", delta, pc); + } break; + case DW_CFA_Offset: { + U64 reg = inst.operands[0].u64; + S64 offset = (S64)inst.operands[1].u64; + operand_str = dw_string_from_reg_off(arena, arch, reg, offset); + } break; + case DW_CFA_Restore: { + operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, 0); + } break; + default: { + str8_list_pushf(arena, &list, "ERROR: unknown CFA opcode 0x%I64u", inst.opcode); + } goto exit; + } + + if (operand_str.size) { + str8_list_pushf(arena, &list, "DW_CFA_%S: %S", dw_string_from_cfa_opcode(inst.opcode), operand_str); + } else { + str8_list_pushf(arena, &list, "DW_CFA_%S", dw_string_from_cfa_opcode(inst.opcode)); + } + } + + exit:; + scratch_end(scratch); + return list; +} + +internal String8List +dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 addr_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, "%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; + cursor += str8_deserial_read(raw_data, cursor, &x, size_param, 1); + x = extend_sign64(x, size_param); + op_value = push_str8f(scratch.arena, "%I64d", x); + } else { + U64 x = 0; + cursor += str8_deserial_read(raw_data, cursor, &x, size_param, 1); + op_value = push_str8f(scratch.arena, "%I64u", x); + } + } break; + + case DW_ExprOp_Addr: { + U64 addr = 0; + cursor += str8_deserial_read(raw_data, cursor, &addr, addr_size, 1); + op_value = push_str8f(scratch.arena, "%#I64x", addr); + } break; + + case DW_ExprOp_ConstU: { + U64 x = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &x); + op_value = push_str8f(scratch.arena, "%I64u", x); + } break; + + case DW_ExprOp_ConstS: { + S64 x = 0; + cursor += str8_deserial_read_sleb128(raw_data, cursor, &x); + op_value = push_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; + 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 %I64u, bit offset %I64u", 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 %I64u", 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 %I64d", 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, "%I64u", 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+%#I64x, ptr %I64x", 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 %#I64x", 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 %#I64x", 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 %#I64x, 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 %#I64x", 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, addr_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, "%#I64x", 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_string_from_reg_off(Arena *arena, Arch arch, DW_Reg 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; + if (reg_off != 0) { + result = push_str8f(arena, "%S%+I64d", reg_str, reg_off); + } else { + result = reg_str; + } + scratch_end(scratch); + return result; +} + +internal String8 +dw_string_from_expression(Arena *arena, String8 expr, U64 cu_base, U64 addr_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, expr, cu_base, addr_size, arch, ver, ext, format); + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + return result; +} + +internal String8 +dw_string_from_cfa(Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFA cfa) +{ + String8 cfa_str = str8_lit("???"); + switch (cfa.rule) { + case DW_CFA_Rule_Null: {} break; + case DW_CFA_Rule_RegOff: { cfa_str = dw_string_from_reg_off(arena, arch, cfa.reg, cfa.off); } break; + case DW_CFA_Rule_Expression: { cfa_str = dw_string_from_expression(arena, cfa.expr, max_U64, address_size, arch, version, ext, format); } break; + default: { InvalidPath; } break; + } + return cfa_str; +} + +internal String8 +dw_string_from_cfi_row(Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFI_Row *row) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List cfi_regs_list = {0}; + U64 reg_count = dw_reg_count_from_arch(arch); + for EachIndex(reg_idx, reg_count) { + DW_CFI_Register *cfi_reg = &row->regs[reg_idx]; + String8 rule_str = str8_lit("???"); + switch (cfi_reg->rule) { + case DW_CFI_RegisterRule_Undefined: { + rule_str = str8f(scratch.arena, "Undefined(%S)", dw_string_from_register(scratch.arena, arch, cfi_reg->n)); + } break; + case DW_CFI_RegisterRule_SameValue: { + rule_str = str8_zero(); + } break; + case DW_CFI_RegisterRule_Offset: { + rule_str = str8f(scratch.arena, "[CFA%+I64d]", cfi_reg->n); + } break; + case DW_CFI_RegisterRule_ValOffset: { + rule_str = str8f(scratch.arena, "Val(CFA%+I64d)", cfi_reg->n); + } break; + case DW_CFI_RegisterRule_Register: { + rule_str = str8f(scratch.arena, "Register(%S)", dw_string_from_register(scratch.arena, arch, cfi_reg->n)); + } break; + case DW_CFI_RegisterRule_Expression: { + rule_str = str8f(scratch.arena, "Expression(%S)", dw_string_from_expression(scratch.arena, cfi_reg->expr, max_U64, address_size, arch, version, ext, format)); + } break; + case DW_CFI_RegisterRule_ValExpression: { + rule_str = str8f(scratch.arena, "ValExpression(%S)", dw_string_from_expression(scratch.arena, cfi_reg->expr, max_U64, address_size, arch, version, ext, format)); + } break; + case DW_CFI_RegisterRule_Architectural: { + rule_str = str8_lit("???"); + } break; + default: { InvalidPath; } break; + } + + if (rule_str.size) { + str8_list_pushf(scratch.arena, &cfi_regs_list, "%S: %S", dw_string_from_register(scratch.arena, arch, reg_idx), rule_str); + } + } + + String8 string = str8_list_join(arena, &cfi_regs_list, &(StringJoin){.sep=str8_lit(", ")}); + + scratch_end(scratch); + return string; +} + +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; +} + +internal String8 +dw_string_from_attrib_value(Arena *arena, DW_Raw *input, Arch arch, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8List attrib_fmt = {0}; + + // rjf: log attrib's value based on vlass + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + switch(value_class) + { + default: {str8_list_pushf(scratch.arena, &attrib_fmt, "`unknown value class`");}break; + case DW_AttribClass_Undefined: {str8_list_pushf(scratch.arena, &attrib_fmt, "`undefined value class`");}break; + case DW_AttribClass_Address: {str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", dw_address_from_attrib(input, cu, attrib));}break; + case DW_AttribClass_Const: {str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", dw_const_u64_from_attrib(input, cu, attrib));}break; + case DW_AttribClass_Block: + { + String8 block = dw_block_from_attrib(input, cu, attrib); + String8List block_strs = numeric_str8_list_from_data(scratch.arena, 16, block, 1); + String8 block_str = str8_list_join(scratch.arena, &block_strs, &(StringJoin){.sep = str8_lit(", ")}); + str8_list_pushf(scratch.arena, &attrib_fmt, "{ %S }", block_str); + }break; + case DW_AttribClass_ExprLoc: + { + String8 exprloc = dw_exprloc_from_attrib(input, cu, attrib); + String8 exprloc_str = dw_single_line_string_from_expression(scratch.arena, exprloc, cu->info_range.min, cu->address_size, arch, cu->version, cu->ext, cu->format); + str8_list_pushf(scratch.arena, &attrib_fmt, "{ %S }", exprloc_str); + }break; + case DW_AttribClass_Flag: + { + B32 flag = dw_flag_from_attrib(input, cu, attrib); + str8_list_pushf(scratch.arena, &attrib_fmt, "%I64u (%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) + { + str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", attrib->form.sec_offset); + } + else + { + str8_list_pushf(scratch.arena, &attrib_fmt, "`unexpected form kind %S`", dw_string_from_form_kind(scratch.arena, cu->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 = cu->info_range.min + attrib->form.ref; + str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", info_off); + if(!contains_1u64(cu->info_range, info_off)) + { + str8_list_pushf(scratch.arena, &attrib_fmt, ": `(out of this cu's bounds)`"); + } + } + else + { + str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", attrib->form.ref); + } + }break; + case DW_AttribClass_String: + { + if(attrib->form.kind == DW_Form_Strp || attrib->form.kind == DW_Form_LineStrp || attrib->form.kind == DW_Form_StrpSup) + { + str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x ", attrib->form.sec_offset); + } + String8 string = dw_string_from_attrib(input, cu, attrib); + str8_list_pushf(scratch.arena, &attrib_fmt, "\"%S\"", string); + }break; + } + + // rjf: extend attrib's value with enum info + { + String8 enum_info = {0}; + switch(attrib->attrib_kind) + { + case DW_AttribKind_Language: + { + DW_Language lang = dw_const_u64_from_attrib(input, cu, attrib); + enum_info = dw_string_from_language(scratch.arena, lang); + }break; + case DW_AttribKind_DeclFile: + { + U64 file_idx = dw_const_u64_from_attrib(input, cu, attrib); + DW_LineFile *file = dw_file_from_attrib(cu, line_vm, attrib); + if(file != 0) + { + enum_info = dw_path_from_file(scratch.arena, line_vm->header.dir_table, file); + } + }break; + case DW_AttribKind_DeclLine: + { + enum_info = str8f(scratch.arena, "%I64u", dw_const_u64_from_attrib(input, cu, attrib)); + }break; + case DW_AttribKind_Inline: + { + DW_InlKind inl = dw_const_u64_from_attrib(input, cu, attrib); + enum_info = dw_string_from_inl(scratch.arena, inl); + }break; + case DW_AttribKind_Accessibility: + { + DW_AccessKind access = dw_const_u64_from_attrib(input, cu, attrib); + enum_info = dw_string_from_access_kind(scratch.arena, access); + }break; + case DW_AttribKind_CallingConvention: + { + DW_CallingConventionKind calling_convetion = dw_const_u64_from_attrib(input, cu, attrib); + enum_info = dw_string_from_calling_convetion(scratch.arena, calling_convetion); + }break; + case DW_AttribKind_Encoding: + { + DW_ATE encoding = dw_const_u64_from_attrib(input, cu, attrib); + enum_info = dw_string_from_attrib_type_encoding(scratch.arena, encoding); + }break; + case DW_AttribKind_Visibility: + { + DW_Vis vis = dw_const_u64_from_attrib(input, cu, attrib); + enum_info = dw_string_from_attrib_visibility(scratch.arena, vis); + }break; + } + + if(enum_info.size) + { + str8_list_pushf(scratch.arena, &attrib_fmt, " `%S`", enum_info); + } + } + + String8 result = str8_list_join(arena, &attrib_fmt, 0); + + scratch_end(scratch); + return result; +} + +internal +DW_PRINTER(dw_print_abbrev) +{ + DW_Raw *input = dumper->input; + + 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); + dw_printf("abbrev: // abbrev[%I64u] abbrev_off: 0x%I64x \n {\n", idx, id_off); + dw_indent(); + dw_printf("id: %I64u tag_kind: %S has_children: %s\n", id, dw_string_from_tag_kind(temp.arena, tag), has_children ? "true" : "false"); + U64 attrib_kind_max_size = 0; + U64 form_kind_max_size = 0; + { + for(U64 off = cursor;;) + { + U64 attrib_id = 0, form_id = 0; + off += str8_deserial_read_uleb128(abbrev.data, off, &attrib_id); + off += str8_deserial_read_uleb128(abbrev.data, off, &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); + attrib_kind_max_size = Max(attrib_kind_max_size, attrib_str.size); + form_kind_max_size = Max(form_kind_max_size, form_str.size); + } + } + 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); + + String8List fmt = {0}; + str8_list_pushf(temp.arena, &fmt, "%S%.*s", attrib_str, attrib_kind_max_size - attrib_str.size, g_spaces); + str8_list_pushf(temp.arena, &fmt, "%S%.*s", form_str, form_kind_max_size - form_str.size, g_spaces); + String8 value = str8_list_join(temp.arena, &fmt, &(StringJoin){.sep=str8_lit(" ")}); + dw_printf("attrib: { %S } // 0x%I64x\n", value, attrib_off); + } + dw_unindent(); + dw_printf("}\n"); + temp_end(temp); + } + scratch_end(scratch); +} + +internal void +dw_print_tag(Arena *arena, String8List *strings, int indent, Arch arch, DW_Raw *input, DW_CompUnit *cu, DW_LineVM *line_vm, DW_TagNode *root) +{ + Temp scratch = scratch_begin(0, 0); + + for (DW_TagNode *n = root; n != 0; n = n->sibling) { + DW_Tag *tag = &n->tag; + + // compute columns' max widths + U64 attrib_name_max_size = 0, form_kind_max_size = 0, value_max_size = 0; + for EachNode(attrib_n, DW_AttribNode, tag->attribs.first) + { + Temp attrib_temp = temp_begin(scratch.arena); + attrib_name_max_size = Max(attrib_name_max_size, dw_string_from_attrib_kind (attrib_temp.arena, cu->version, cu->ext, attrib_n->v.attrib_kind).size); + form_kind_max_size = Max(form_kind_max_size, dw_string_from_form_kind (attrib_temp.arena, cu->version, attrib_n->v.form.kind).size); + value_max_size = Max(value_max_size, dw_string_from_attrib_value(attrib_temp.arena, input, arch, cu, line_vm, &attrib_n->v).size); + temp_end(attrib_temp); + } + attrib_name_max_size = Min(40, attrib_name_max_size); + form_kind_max_size = Min(20, form_kind_max_size); + value_max_size = Min(80, value_max_size); + + dw_printf("tag: // info_off: 0x%I64x abbrev_id: %I64u\n", tag->info_off, tag->abbrev_id); + dw_printf("{\n"); + dw_indent(); + dw_printf("kind: %S\n", dw_string_from_tag_kind(scratch.arena, tag->kind)); + for EachNode(attrib_n, DW_AttribNode, tag->attribs.first) { + DW_Attrib *attrib = &attrib_n->v; + + String8 attrib_kind_str = dw_string_from_attrib_kind(scratch.arena, cu->version, cu->ext, attrib->attrib_kind); + String8 form_kind_str = dw_string_from_form_kind(scratch.arena, cu->version, attrib->form.kind); + String8 value_str = dw_string_from_attrib_value(scratch.arena, input, arch, cu, line_vm, attrib); + + String8List fmt = {0}; + str8_list_pushf(scratch.arena, &fmt, "%S%.*s", attrib_kind_str, attrib_kind_str.size <= attrib_name_max_size ? attrib_name_max_size - attrib_kind_str.size : 0, g_spaces); + str8_list_pushf(scratch.arena, &fmt, "%S%.*s", form_kind_str, form_kind_str.size <= form_kind_max_size ? form_kind_max_size - form_kind_str.size : 0, g_spaces); + str8_list_pushf(scratch.arena, &fmt, "%S%.*s", value_str, value_str.size <= value_max_size ? value_max_size - value_str.size : 0, g_spaces); + String8 attrib_str = str8_list_join(scratch.arena, &fmt, &(StringJoin){.sep = str8_lit(" ")}); + + dw_printf("attrib: { %S } // info_off: 0x%I64x\n", attrib_str, attrib->info_off); + } + + if (tag->has_children) { + dw_print_tag(arena, strings, indent, arch, input, cu, line_vm, n->first_child); + } + + dw_unindent(); + dw_printf("}\n"); + } + + scratch_end(scratch); +} + +internal +DW_PRINTER(dw_print_info) +{ + DW_Raw *input = dumper->input; + Arch arch = dumper->arch; + HashTable *line_vm_map = dw_get_line_vm_map(dumper); + Rng1U64Array cu_ranges = dw_get_info_ranges(dumper); + DW_CompUnit *cu_arr = dw_get_cu_arr(dumper); + DW_TagTree *tag_trees = dw_get_tag_trees(dumper); + + Temp scratch = scratch_begin(&arena, 1); + for EachIndex(cu_idx, cu_ranges.count) { + Rng1U64 cu_range = cu_ranges.v[cu_idx]; + DW_CompUnit *cu = &cu_arr[cu_idx]; + String8 cu_dir = dw_string_from_tag_attrib_kind (input, cu, cu->tag, DW_AttribKind_CompDir ); + String8 cu_name = dw_string_from_tag_attrib_kind (input, cu, cu->tag, DW_AttribKind_Name ); + String8 stmt_list = dw_line_ptr_from_tag_attrib_kind(input, cu, cu->tag, DW_AttribKind_StmtList); + + DW_LineVM *line_vm = 0; + if (stmt_list.str) { + line_vm = hash_table_search_raw_raw(line_vm_map, stmt_list.str); + if (line_vm == 0) { + line_vm = dw_line_vm_init(input, cu); + // decode line table to find all the defined files, in version 5 this behaviour was deprecated + if (cu->version < DW_Version_5) { + while (dw_line_vm_step(line_vm)); + } + hash_table_push_raw_raw(scratch.arena, line_vm_map, stmt_list.str, line_vm); + } + } + + dw_printf("cu: // compile_unit[%I64u] @ %r (%M)\n", cu_idx, cu_range, dim_1u64(cu->info_range)); + dw_printf("{\n"); + dw_indent(); + dw_printf("format: %S\n", dw_string_from_format(cu->format)); + dw_printf("version: %u\n", cu->version); + dw_printf("kind: %S\n", dw_string_from_comp_unit_kind(scratch.arena, cu->kind)); + dw_printf("address_size: %I64u\n", cu->address_size); + dw_printf("abbrev_off: 0x%I64x\n", cu->abbrev_off); + dw_print_tag(arena, strings, indent, arch, input, cu, line_vm, tag_trees[cu_idx].root); + dw_unindent(); + dw_printf("} // compile_unit[/%u]\n", cu_idx); + } +} + +DW_PRINTER(dw_print_line) +{ + DW_Raw *input = dumper->input; + B32 is_verbose = dumper->is_verbose; + DW_CompUnit *cu_arr = dw_get_cu_arr(dumper); + Temp scratch = scratch_begin(&arena, 1); + Rng1U64Array unit_ranges = dw_unit_ranges_from_data_arr(scratch.arena, input->sec[DW_Section_Line].data); + for EachIndex(unit_idx, unit_ranges.count) + { + Temp unit_temp = temp_begin(scratch.arena); + + DW_CompUnit *cu = &cu_arr[unit_idx]; + DW_LineVM *vm = dw_line_vm_init(input, cu); + + // rjf: begin logging line table + dw_printf("line_table: // line_table[%I64u]\n", unit_idx); + dw_printf("{\n"); + dw_indent(); + { + // rjf: log line table header + dw_printf("header:\n"); + dw_printf("{\n"); + dw_indent(); + { + String8List opcode_length_strings = numeric_str8_list_from_data(unit_temp.arena, 16, str8(vm->header.opcode_lens, vm->header.num_opcode_lens), 1); + String8 opcode_lengths_string = str8_list_join(arena, &opcode_length_strings, &(StringJoin){.sep = str8_lit(", ")}); + dw_printf("version: %u\n", vm->header.version ); + dw_printf("line_table_size: %I64u\n", vm->header.unit_length ); + dw_printf("address_size: %u\n", vm->header.address_size ); + dw_printf("segment_selector_size: %u\n", vm->header.segment_selector_size); + dw_printf("header_length: %I64u\n", vm->header.header_length ); + dw_printf("min_instruction_length: %u\n", vm->header.min_inst_len ); + dw_printf("max_ops_for_instruction: %u\n", vm->header.max_ops_for_inst ); + dw_printf("default_is_stmt: %u\n", vm->header.default_is_stmt ); + dw_printf("line_base: %d\n", vm->header.line_base ); + dw_printf("line_range: %u\n", vm->header.line_range ); + dw_printf("opcode_base: %u\n", vm->header.opcode_base ); + dw_printf("opcode_lengths: { %S }\n", opcode_lengths_string ); + } + dw_unindent(); + dw_printf("}\n"); + + // rjf: log directory table + dw_printf("directory_table:\n"); + dw_printf("{\n"); + dw_indent(); + { + dw_printf("// %-4s %-30s\n", "No.", "Name"); + dw_printf("// ---- ------------------------------\n"); + for EachIndex(dir_idx, vm->header.dir_table.count) + { + dw_printf("{ %-4I64u %-30S }\n", dir_idx, vm->header.dir_table.v[dir_idx]); + } + } + dw_unindent(); + dw_printf("}\n"); + + // rjf: log file table + dw_printf("file_table:\n"); + dw_printf("{\n"); + dw_indent(); + { + dw_printf("// %-4s %-8s %-8s %-33s %-8s %-20s\n", "No.", "Dir No.", "Time", "MD5", "Size", "Path"); + dw_printf("// ---- -------- -------- --------------------------------- -------- --------------------\n"); + for EachIndex(file_idx, vm->header.file_table.count) + { + DW_LineFile *file = &vm->header.file_table.v[file_idx]; + dw_printf("{ %-4I64u %-8I64u %-8I64u %016I64x-%016I64x %-8I64u %-20S }\n", + file_idx, + file->dir_idx, + file->time_stamp, + file->md5.u64[1], + file->md5.u64[0], + file->size, + file->path); + } + } + dw_unindent(); + dw_printf("}\n"); + + // rjf: log opcodes + dw_printf("line_table:\n"); + dw_printf("{\n"); + dw_indent(); + { + dw_printf("//\n"); + dw_printf("// %-16s %-8s %-4s %-5s %-3s %-7s %-16s\n", "Address", "Line", "Col", "File", "ISA", "Discrim", "Flags"); + dw_printf("// ---------------- -------- ---- ----- --- ------- ----------------\n"); + + for(;;) + { + U64 global_opcode_off = unit_ranges.v[unit_idx].min + vm->cursor; + + if( ! dw_line_vm_step(vm)) { break; } + + Temp opcode_temp = temp_begin(unit_temp.arena); + String8List opcode_fmt = {0}; + + // opcode offset + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%08I64x:", global_opcode_off); + + // push opcode id + if (vm->opcode != 0) { + String8 opcode_str = dw_string_from_std_opcode(opcode_temp.arena, vm->opcode); + str8_list_pushf(arena, &opcode_fmt, "%-11S:", opcode_str); + } + + // print operands + switch(vm->opcode) + { + default: + { + if(vm->opcode >= vm->header.opcode_base) + { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "advance line by %I64d, advance address by %I64d", vm->line_advance, vm->addr_advance); + } + else + { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "skipping %I64x unknown opcodes", vm->header.opcode_lens[vm->opcode - 1]); + } + }break; + case DW_StdOpcode_Copy: + { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "Line = %I64u, Column = %I64u, Address = %#I64x", vm->state.line, vm->state.column, vm->state.address); + }break; + case DW_StdOpcode_AdvancePc: + { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "advance %#I64x ; current address %#I64x", vm->operands[0].u64, vm->state.address); + }break; + case DW_StdOpcode_AdvanceLine: + { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "advance %I64d ; current line %I64u", vm->operands[0].s64, vm->state.line); + }break; + case DW_StdOpcode_SetFile: + { + DW_LineFile *file = dw_line_vm_find_file(vm, vm->state.file_index); + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%I64u \"%S\"", vm->state.file_index, dw_path_from_file(opcode_temp.arena, vm->header.dir_table, file)); + }break; + case DW_StdOpcode_SetColumn: + { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%I64u", vm->state.column); + }break; + case DW_StdOpcode_NegateStmt: + { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "is_stmt = %u", vm->state.is_stmt); + }break; + case DW_StdOpcode_SetBasicBlock: + { + }break; + case DW_StdOpcode_ConstAddPc: + { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%I64d ; address %#I64x", vm->advance, vm->state.address); + }break; + case DW_StdOpcode_FixedAdvancePc: + { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%I64u", vm->operands[0].u64); + }break; + case DW_StdOpcode_SetPrologueEnd: + { + }break; + case DW_StdOpcode_SetEpilogueBegin: + { + }break; + case DW_StdOpcode_SetIsa: + { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%I64u", vm->state.isa); + }break; + case DW_StdOpcode_ExtendedOpcode: + { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%S*", dw_string_from_ext_opcode(opcode_temp.arena, vm->ext_opcode)); + //str8_list_pushf(opcode_temp.arena, &opcode_fmt, "length: %u", length); + switch(vm->ext_opcode) + { + case DW_ExtOpcode_EndSequence: {} break; + case DW_ExtOpcode_SetAddress: { str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%#I64x", vm->operands[0].u64); } break; + case DW_ExtOpcode_DefineFile: { str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%S Dir: %I64u, Time: %I64u, Size: %I64u", + vm->operands[0].string, vm->operands[1].u64, vm->operands[2].u64, vm->operands[3].u64); } break; + case DW_ExtOpcode_SetDiscriminator: { str8_list_pushf(arena, &opcode_fmt, "%I64u", vm->state.discriminator); }break; + } + }break; + } + + if(is_verbose) + { + String8 string = str8_list_join(opcode_temp.arena, &opcode_fmt, &(StringJoin){.sep=str8_lit(" ")}); + dw_printf("// %S\n", string); + } + + if(vm->new_line) { + String8List l = {0}; + if(vm->state.is_stmt) + { + str8_list_pushf(opcode_temp.arena, &l, "is_stmt"); + } + if(vm->state.end_sequence) + { + str8_list_pushf(opcode_temp.arena, &l, "end_seq"); + } + String8 flags = str8_list_join(opcode_temp.arena, &l, &(StringJoin){.sep = str8_lit("|")}); + + dw_printf("{ %#016I64x %8I64u %4I64u %5I64u %3I64u %7I64u %-16S } %s\n", vm->state.address, vm->state.line, vm->state.column, vm->state.file_index, vm->state.isa, vm->state.discriminator, flags, vm->new_seq ? "// new seq" : ""); + } + + temp_end(opcode_temp); + } + + if(vm->error.size) + { + dw_printf("ERROR: Line VM failed stepping @ 0x%I64x\n", vm->cursor); + } + } + dw_unindent(); + dw_printf("}\n"); + + temp_end(unit_temp); + } + dw_unindent(); + dw_printf("}\n"); + } + scratch_end(scratch); +} + +DW_PRINTER(dw_print_strings) +{ + DW_Raw *input = dumper->input; + 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); + dw_printf(" { 0x%08I64x %I64u \"%S\" }\n", cursor, string.size, string); + } +} + +DW_PRINTER(dw_print_frame) +{ + DW_Raw *input = dumper->input; + Arch arch = dumper->arch; + Temp scratch = scratch_begin(&arena, 1); + HashTable *cie_ht = hash_table_init(scratch.arena, 0x2000); + String8 debug_frame = input->sec[DW_Section_Frame].data; + U64 addr_size = byte_size_from_arch(arch); + + // make offset -> CIE hash table + 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_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); + if (dw_parse_cie(raw_cie, desc.format, arch, cie)) { + hash_table_push_u64_raw(scratch.arena, cie_ht, cursor, cie); + } else { + arena_pop_to(scratch.arena, restore_pos); + } + } + } + + 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); + String8 raw_desc = str8_substr(debug_frame, desc.entry_range); + switch (desc.type) { + 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); + + dw_printf("CIE: // entry range: %r\n", desc.entry_range); + dw_printf("{\n"); + dw_printf(" Format: %S\n", dw_string_from_format(desc.format)); + dw_printf(" Version: %u\n", cie.version); + dw_printf(" Aug string: \"%S\"\n", cie.aug_string); + dw_printf(" Code align: %I64u\n", cie.code_align_factor); + dw_printf(" Data align: %I64d\n", cie.data_align_factor); + dw_printf(" Return addr reg: %u\n", cie.ret_addr_reg); + if (cie.version > DW_Version_3) { + dw_printf(" Address size: %u\n", cie.address_size); + dw_printf(" Segment selector size: %u\n", cie.segment_selector_size); + } + dw_printf(" Initial Insturction:\n"); + dw_printf(" {\n"); + for EachNode(n, String8Node, init_insts_str_list.first) { dw_printf(" %S\n", n->string); } + dw_printf(" }\n"); + dw_printf("}\n"); + } else { + dw_printf("ERROR: unable to parse CIE @ %I64x\n", desc.entry_range.min); + } + } break; + 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); + DW_CIE cie = {0}; + dw_parse_cie(cie_data, cie_desc.format, arch, &cie); + + DW_FDE fde = {0}; + if (dw_parse_fde(raw_desc, desc.format, &cie, &fde)) { + DW_Version version = DW_Version_5; + DW_Ext ext = DW_Ext_All; + String8List insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, version, ext, fde.format, fde.pc_range.min, &cie, dw_decode_ptr_debug_frame, &cie, fde.insts); + dw_printf("FDE: // entry range: %r\n", desc.entry_range); + dw_printf("{\n"); + { + dw_printf(" Format: %S\n", dw_string_from_format(fde.format)); + dw_printf(" CIE pointer: 0x%I64x\n", fde.cie_pointer); + dw_printf(" PC range: %r\n", fde.pc_range); + dw_printf(" Instructions:\n"); + dw_printf(" {\n"); + for EachNode(n, String8Node, insts_str_list.first) { dw_printf(" %S\n", n->string); } + dw_printf(" }\n"); + } + dw_printf(" Unwind:\n"); + dw_printf(" {\n"); + DW_CFI_Unwind *cfi_unwind = dw_cfi_unwind_init(scratch.arena, arch, &cie, &fde, dw_decode_ptr_debug_frame, &cie); + do { + String8 cfa_str = dw_string_from_cfa(scratch.arena, arch, cie.address_size, version, ext, fde.format, cfi_unwind->row->cfa); + String8 cfi_regs_str = dw_string_from_cfi_row(scratch.arena, arch, cie.address_size, version, ext, fde.format, cfi_unwind->row); + dw_printf(" { PC: 0x%I64x, CFA: %-7S, Rules: { %S }\n", cfi_unwind->pc, cfa_str, cfi_regs_str); + } while (dw_cfi_next_row(scratch.arena, cfi_unwind)); + dw_printf(" }\n"); + + dw_printf("}\n"); + } else { + dw_printf("ERROR: unable to parse FDE @ %I64x\n", desc.entry_range.min); + } + } break; + } + } +} + +#if 0 +internal +DW_PRINTER(dw_print_debug_loc) +{ + DW_Raw *input = dumper->input; + DW_TagTree *tag_trees = dw_get_tag_trees(dumper); + 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); + + // TODO: warn about overlaps in ranges + + Rng1U64Array info_ranges = dw_get_info_ranges(dumper); + DW_CompUnit *cu_arr = dw_get_cu_arr(dumper); + + // parse debug_info for attributes with LOCLIST and store .debug_loc offsets + U64List *loc_lists = push_array(scratch.arena, U64List, info_ranges.count); + for EachIndex(cu_idx, info_ranges.count) { + DW_CompUnit *cu = &cu_arr[cu_idx]; + DW_TagTree *tag_tree = tag_trees[cu_idx]; + for (D2R_TagIterator *it = d2r_tag_iterator_init(scratch.arena, tag_tree); + it->tag_node != 0; + d2r_tag_iterator_next(it)) { + DW_TagNode *tag_node = it->tag_node; + DW_Tag tag = tag_node->tag; + for EachNode(attrib_n, DW_AttribNode, tag.attribs.first) { + DW_Attrib *attrib = &attrib_n->v; + DW_AttribClass attrib_class = dw_attrib_class_from_attrib(cu->version, cu->ext, attrib->kind); + B32 is_sect_offset = attrib_class == DW_AttribClass_LocListPtr || (attrib_class == DW_AttribClass_LocList && attrib->form.kind == DW_Form_SecOffset); + B32 is_sect_index = attrib_class == DW_AttribClass_LocList && attrib->form.kind == DW_Form_LocListx; + if (is_sect_offset) { + U64 sec_offset = dw_interp_sec_offset(attrib->form.kind, attrib->form); + u64_list_push(scratch.arena, &loc_lists[cu_idx], attrib->value.v[0]); + } else if (is_sect_index) { + // TODO: support for section indexing + } + } + } + } + + void *base = dw_base_from_sec(input, DW_Section_Loc); + Rng1U64 range = dw_range_from_sec(input, DW_Section_Loc); + + dw_printf(".debug_loc"); + dw_indent(); + dw_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, "%08I64x", 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, ""); + } 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, "%08I64x %08I64x %S", min, max, expression); + } + + // print entry + String8 print = str8_list_join(range_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + dw_printf("%S", print); + + // cleanup temp + temp_end(range_temp); + + // exit check + if (is_list_end) { + break; + } + } + } + + temp_end(locs_temp); + } + dw_unindent(); + + dw_unindent(); + scratch_end(scratch); +} +#endif + +#if 0 +internal void +dw_print_debug_ranges(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *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; + } + } + } + + dw_printf("# %S", sections->v[DW_Section_Ranges].name); + dw_indent(); + dw_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, "%08I64x", 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, ""); + } 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, "%08I64x %08I64x", min, max); + } + + // print entry + String8 print = str8_list_join(range_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + dw_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 g_dw_indent, DW_Raw *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); + + dw_printf("# %S", sections->v[DW_Section_ARanges].name); + dw_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; + } + + dw_printf("Unit length: %I64u", unit_length); + dw_printf("Version: %u", version); + dw_printf("Debug info offset: %#I64x", debug_info_offset); + dw_printf("Address size: %u", address_size); + dw_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)"); + } + + dw_indent(); + dw_printf("%-8s %-8s", "Offset", "Range"); + for (; cursor < unit_opl; ) { + Temp temp = temp_begin(arena); + + String8List list = {0}; + + str8_list_pushf(temp.arena, &list, "%08I64x", 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, ""); + } else { + if (segment_selector != 0) { + str8_list_pushf(temp.arena, &list, "%02I64u:", segment_selector); + } + str8_list_pushf(temp.arena, &list, "%I64x-%I64x", address, address+length); + } + + String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ") }); + dw_printf("%S", print); + + temp_end(temp); + } + dw_unindent(); + rd_newline(); + } + dw_unindent(); + + scratch_end(scratch); +#endif +} + +internal void +dw_print_debug_addr(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *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); + + dw_printf("# %S", sections->v[DW_Section_Addr].name); + dw_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; + } + + dw_printf("Unit @ %#I64x, length %I64u", unit_offset, unit_length); + dw_printf("Version: %u", version); + dw_printf("Address size: %u", address_size); + dw_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)"); + } + + dw_indent(); + dw_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, ""); + } else { + if (segment_selector != 0) { + str8_list_pushf(temp.arena, &list, "%02u:", segment_selector); + } + str8_list_pushf(temp.arena, &list, "%I64x", address); + } + + String8 print = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + dw_printf("%S", print); + + temp_end(temp); + } + dw_unindent(); + rd_newline(); + } + dw_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 g_dw_indent, DW_Raw *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); + + dw_printf("# %S", sections->v[DW_Section_LocLists].name); + dw_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); + + dw_printf("Unit @ %#I64x, length %I64u", unit_offset, unit_length); + dw_printf("Version: %u", version); + dw_printf("Address size: %u", address_size); + dw_printf("Segment selector size: %u", segment_selector_size); + dw_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) { + dw_printf("Offsets:"); + dw_indent(); + dw_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); + dw_printf("%-8I64u %I64x", offset_idx, offset+past_header_offset); + } + dw_unindent(); + } + + dw_printf("Locations:"); + dw_indent(); + dw_printf("%-8s %-8s", "Offset", "Location"); + for (; cursor < unit_opl; ) { + Temp temp = temp_begin(arena); + + String8List list = {0}; + + str8_list_pushf(temp.arena, &list, "%08I64x", 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, "%I64x", 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, "%I64x, %I64x", 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, "%I64x, %I64x", 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, "%I64x", 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, "%I64x, %I64x", 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, "%I64x, %I64x", 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(" ")}); + dw_printf("%S", print); + + temp_end(temp); + } + dw_unindent(); + rd_newline(); + } + dw_unindent(); + + scratch_end(scratch); +#endif +} + +internal void +dw_print_debug_rnglists(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *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); + + dw_printf("# %S", sections->v[DW_Section_RngLists].name); + dw_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); + + dw_printf("Unit @ %#I64x, length %I64u", unit_offset, unit_length); + dw_printf("Version: %u", version); + dw_printf("Address size: %u", address_size); + dw_printf("Segment selector size: %u", segment_selector_size); + dw_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) { + dw_printf("Offsets:"); + dw_indent(); + dw_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); + dw_printf("%-8I64u %I64x", offset_idx, offset+past_header_offset); + } + dw_unindent(); + } + + dw_printf("Ranges:"); + dw_indent(); + dw_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, "%08I64x", 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, "%I64x", 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, "%I64x", 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, "%I64x, %I64x", 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, "%I64x, %I64x", 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, "%I64x, %I64x", 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, "%I64x, %I64x", 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, "%I64x, %I64x", start, length); + } break; + } + + // output row + String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); + dw_printf("%S", print); + + temp_end(temp); + } + dw_unindent(); + rd_newline(); + } + dw_unindent(); + + scratch_end(scratch); +#endif +} + +internal void +dw_format_string_table(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *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); + + dw_printf("# %S", sections->v[sec].name); + dw_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); + + dw_printf("Unit @ %#I64x, length %I64u", unit_offset, unit_length); + dw_printf("Version: %u", version); + dw_printf("Debug info offset: %#I64x", debug_info_offset); + dw_printf("Debug info length: %#I64x", debug_info_length); + + dw_printf("Entries:"); + dw_indent(); + dw_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); + + dw_printf("%08I64x %S", info_offset, string); + } + dw_unindent(); + rd_newline(); + } + dw_unindent(); + + scratch_end(scratch); +#endif +} + +internal void +dw_print_debug_pubnames(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *input) +{ + dw_format_string_table(arena, out, g_dw_indent, input, DW_Section_PubNames); +} + +internal void +dw_print_debug_pubtypes(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *input) +{ + dw_format_string_table(arena, out, g_dw_indent, input, DW_Section_PubTypes); +} + +internal void +dw_print_debug_line_str(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *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); + + dw_printf("# %S", sections->v[DW_Section_LineStr].name); + dw_indent(); + + dw_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); + dw_printf("%08llX %S", offset, string); + } + dw_unindent(); + + scratch_end(scratch); +#endif +} + +internal void +dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *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); + + dw_printf("# %S", sections->v[DW_Section_StrOffsets].name); + dw_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); + + dw_printf("Unit @ %#llX, length %I64d", unit_offset, unit_length); + dw_printf("Version: %d", version); + dw_printf("Padding: %d", padding); + dw_indent(); + dw_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); + dw_printf("%08I64x %08I64x", read_at, offset); + if (dim_1u64(debug_str_range) > 0) { + String8 string = dw_based_range_read_string(debug_str_base, debug_str_range, offset); + dw_printf(" %S", string); + } + rd_newline(); + } + dw_unindent(); + rd_newline(); + } + dw_unindent(); + + scratch_end(scratch); +#endif +} + +#endif + +//////////////////////////////// +//~ rjf: Dump Entry Point + +read_only struct { + DW_Printer *printer; + DW_SectionKind kind; +} g_dw_printers[] = { + { dw_print_abbrev, DW_Section_Abbrev }, + { dw_print_info, DW_Section_Info }, + { dw_print_strings, DW_Section_Str }, + { dw_print_frame, DW_Section_Frame }, + { dw_print_line, DW_Section_Line }, +}; + +internal String8List +dw_dump_list_from_sections(Arena *arena, + DW_Raw *input, + Arch arch, + DW_SectionFlags subset_flags, + B32 is_verbose) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List *strings = push_array(scratch.arena, String8List, 1); + int indent = 0; + + DW_Dumper dumper = {0}; + dumper.arena = arena_alloc(); + dumper.arch = arch; + dumper.is_verbose = is_verbose; + dumper.input = input; + dumper.is_relaxed = 1; + + for EachElement(i, g_dw_printers) { + if (((1 << g_dw_printers[i].kind) & subset_flags) != 0) { + String8List s = {0}; + g_dw_printers[i].printer(arena, &s, indent + 1, &dumper); + + if (s.total_size > 0) { + dw_printf("%S:\n", str8_skip(dw_name_string_from_section_kind(g_dw_printers[i].kind), 1)); + dw_printf("{\n"); + dw_indent(); + str8_list_concat_in_place(strings, &s); + dw_unindent(); + dw_printf("}\n"); + } + } + } + + String8List result = *strings; + arena_release(dumper.arena); + scratch_end(scratch); + return result; +} + diff --git a/obsolete/dwarf/dwarf_dump_old.h b/obsolete/dwarf/dwarf_dump_old.h new file mode 100644 index 00000000..6a015952 --- /dev/null +++ b/obsolete/dwarf/dwarf_dump_old.h @@ -0,0 +1,73 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DWARF_DUMP_H +#define DWARF_DUMP_H + +typedef enum +{ + DW_DumperCacheFlag_InfoRanges = (1 << 0), + DW_DumperCacheFlag_CuArr = (1 << 1), + DW_DumperCacheFlag_LineVmMap = (1 << 2), + DW_DumperCacheFlag_TagTrees = (1 << 3), +} DW_DumperCacheFlags; + +typedef struct DW_Dumper +{ + Arena *arena; + Arch arch; + B32 is_relaxed; + B32 is_verbose; + DW_Raw *input; + DW_DumperCacheFlags cache_flags; + struct { + Rng1U64Array info_ranges; + DW_CompUnit *cu_arr; + HashTable *line_vm_map; + DW_TagTree *tag_trees; + } cache; +} DW_Dumper; + +#define DW_PRINTER(name) void name(Arena *arena, String8List *strings, int indent, DW_Dumper *dumper) +typedef DW_PRINTER(DW_Printer); + +//////////////////////////////// + +// cache +internal Rng1U64Array dw_get_info_ranges(DW_Dumper *dumper); +internal DW_CompUnit * dw_get_cu_arr(DW_Dumper *dumper); +internal HashTable * dw_get_line_vm_map(DW_Dumper *dumper); +internal DW_TagTree * dw_get_tag_trees(DW_Dumper *dumper); + +//////////////////////////////// +//~ rjf: Stringification Helpers + +internal String8List dw_string_list_from_cfi_program(Arena *arena, U64 cu_base, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format, U64 pc_begin, DW_CIE *cie, DW_DecodePtr *decode_ptr_func, void *deocde_ptr_ud, String8 program); +internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); + +internal String8 dw_string_from_reg_off (Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off); +internal String8 dw_string_from_attrib_value(Arena *arena, DW_Raw *input, Arch arch, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib); +internal String8 dw_string_from_expression (Arena *arena, String8 expr, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); +internal String8 dw_string_from_cfa (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFA cfa); +internal String8 dw_string_from_cfi_row (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFI_Row *row); + +#if 0 +internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx); +internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed); +internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed); +internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input); +internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_Raw *input); +internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges, Arch arch); +internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges); +internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_Raw *input); +internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_Raw *input); +internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_Raw *input); +internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Raw *input); +#endif + +//////////////////////////////// +//~ rjf: Dump Entry Point + +internal String8List dw_dump_list_from_sections(Arena *arena, DW_Raw *input, Arch arch, DW_SectionFlags dump_sections, B32 is_verbose); + +#endif // DWARF_DUMP_H diff --git a/obsolete/dwarf/dwarf_expr_old.c b/obsolete/dwarf/dwarf_expr_old.c new file mode 100644 index 00000000..8f8e23ac --- /dev/null +++ b/obsolete/dwarf/dwarf_expr_old.c @@ -0,0 +1,1580 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal DW_PieceNode * +dw_piece_list_push(Arena *arena, DW_PieceList *list, DW_Piece v) +{ + DW_PieceNode *n = push_array(arena, DW_PieceNode, 1); + n->v = v; + SLLQueuePush(list->first, list->last, n); + list->count += 1; + return n; +} + +internal DW_ExprValueType +dw_expr_unsigned_value_type_from_bit_size(U64 bit_size) +{ + switch (bit_size) { + case 8: return DW_ExprValueType_U8; + case 16: return DW_ExprValueType_U16; + case 32: return DW_ExprValueType_U32; + case 64: return DW_ExprValueType_U64; + case 128: return DW_ExprValueType_U128; + case 256: return DW_ExprValueType_U256; + case 512: return DW_ExprValueType_U512; + } + AssertAlways(0 && "no suitable unsigned type was found for the specified size"); + return DW_ExprValueType_Generic; +} + +internal DW_ExprValueType +dw_expr_signed_value_type_from_bit_size(U64 bit_size) +{ + switch (bit_size) { + case 8: return DW_ExprValueType_S8; + case 16: return DW_ExprValueType_S16; + case 32: return DW_ExprValueType_S32; + case 64: return DW_ExprValueType_S64; + case 128: return DW_ExprValueType_S128; + case 256: return DW_ExprValueType_S256; + case 512: return DW_ExprValueType_S512; + } + AssertAlways(0 && "no suitable signed type was found for the specified size"); + return DW_ExprValueType_Generic; +} + +internal DW_ExprValueType +dw_expr_float_type_from_bit_size(U64 bit_size) +{ + switch (bit_size) { + case 4: return DW_ExprValueType_F32; + case 8: return DW_ExprValueType_F64; + } + AssertAlways(0 && "no suitable type was found for the specified size"); + return DW_ExprValueType_Generic; +} + +internal U64 +dw_expr_byte_size_from_value_type(U64 addr_size, DW_ExprValueType k) +{ + switch (k) { + default: { InvalidPath; } + case DW_ExprValueType_Generic: return 0; + case DW_ExprValueType_Addr: return addr_size; + case DW_ExprValueType_U8: return 1; + case DW_ExprValueType_U16: return 2; + case DW_ExprValueType_U32: return 4; + case DW_ExprValueType_U64: return 8; + case DW_ExprValueType_U128: return 16; + case DW_ExprValueType_U256: return 32; + case DW_ExprValueType_U512: return 64; + case DW_ExprValueType_S8: return 1; + case DW_ExprValueType_S16: return 2; + case DW_ExprValueType_S32: return 4; + case DW_ExprValueType_S64: return 8; + case DW_ExprValueType_S128: return 16; + case DW_ExprValueType_S256: return 32; + case DW_ExprValueType_S512: return 64; + case DW_ExprValueType_F32: return 4; + case DW_ExprValueType_F64: return 8; + } +} + +internal DW_ExprValueType +dw_expr_pick_common_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs) +{ + if (lhs == rhs) { + return lhs; + } + // unsigned vs unsigned + else if (DW_ExprValueType_IsUnsigned(lhs) && DW_ExprValueType_IsUnsigned(rhs)) { + return Max(lhs, rhs); + } + // signed vs signed + else if (DW_ExprValueType_IsSigned(lhs) && DW_ExprValueType_IsSigned(rhs)) { + return Max(lhs, rhs); + } + // (unsigned vs signed) || (signed vs unsigned) + else if ((DW_ExprValueType_IsUnsigned(lhs) && DW_ExprValueType_IsSigned(rhs)) || + (DW_ExprValueType_IsSigned(lhs) && DW_ExprValueType_IsUnsigned(rhs))) { + U64 lhs_size = dw_expr_byte_size_from_value_type(0, lhs); + U64 rhs_size = dw_expr_byte_size_from_value_type(0, rhs); + if (lhs_size < rhs_size) { + return rhs; + } else if (lhs > rhs_size) { + return lhs; + } else { + return dw_expr_unsigned_value_type_from_bit_size(lhs_size * 8); + } + } + // float vs int + else if (DW_ExprValueType_IsFloat(lhs) && DW_ExprValueType_IsInt(rhs)) { + return lhs; + } + // int vs float + else if (DW_ExprValueType_IsInt(lhs) && DW_ExprValueType_IsFloat(rhs)) { + return rhs; + } + // float vs float + else if (DW_ExprValueType_IsFloat(lhs) && DW_ExprValueType_IsFloat(rhs)) { + return Max(lhs, rhs); + } + // address vs int + else if (lhs == DW_ExprValueType_Addr && DW_ExprValueType_IsInt(rhs)) { + return DW_ExprValueType_Addr; + } + // int vs address + else if (DW_ExprValueType_IsInt(lhs) && rhs == DW_ExprValueType_Addr) { + return DW_ExprValueType_Addr; + } + // address vs float + else if (lhs == DW_ExprValueType_Addr && DW_ExprValueType_IsFloat(rhs)) { + return DW_ExprValueType_Generic; + } + // float vs address + else if (DW_ExprValueType_IsFloat(lhs) && rhs == DW_ExprValueType_Addr) { + return DW_ExprValueType_Generic; + } + // no conversion for implicit value + else if (lhs == DW_ExprValueType_Implicit || rhs == DW_ExprValueType_Implicit) { + return DW_ExprValueType_Generic; + } + AssertAlways(!"undefined conversion case"); + return DW_ExprValueType_Generic; +} + +internal DW_ExprValueType +dw_expr_pick_common_compar_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs) +{ + DW_ExprValueType result; + if (lhs == DW_ExprValueType_Generic || rhs == DW_ExprValueType_Generic) { + result = DW_ExprValueType_S64; + } else { + result = dw_expr_pick_common_value_type(lhs, rhs); + } + return result; +} + +internal DW_ExprValue +dw_expr_cast(DW_ExprValue value, DW_ExprValueType type) +{ + DW_ExprValue result = { type }; + +#define CastTable(f, t) \ +switch (value.type) { \ +case DW_ExprValueType_Generic: { MemoryCopy(&result.f, value.generic.str, Min(sizeof(t), value.generic.size)); } break; \ +case DW_ExprValueType_U8: { result.f = (t)value.u8; } break; \ +case DW_ExprValueType_U16: { result.f = (t)value.u16; } break; \ +case DW_ExprValueType_U32: { result.f = (t)value.u32; } break; \ +case DW_ExprValueType_U64: { result.f = (t)value.u64; } break; \ +case DW_ExprValueType_U128: { NotImplemented; } break; \ +case DW_ExprValueType_U256: { NotImplemented; } break; \ +case DW_ExprValueType_U512: { NotImplemented; } break; \ +case DW_ExprValueType_S8: { result.f = (t)value.s8; } break; \ +case DW_ExprValueType_S16: { result.f = (t)value.s16; } break; \ +case DW_ExprValueType_S32: { result.f = (t)value.s32; } break; \ +case DW_ExprValueType_S64: { result.f = (t)value.s64; } break; \ +case DW_ExprValueType_S128: { NotImplemented; } break; \ +case DW_ExprValueType_S256: { NotImplemented; } break; \ +case DW_ExprValueType_S512: { NotImplemented; } break; \ +case DW_ExprValueType_F32: { result.f = (t)value.f32; } break; \ +case DW_ExprValueType_F64: { result.f = (t)value.f64; } break; \ +case DW_ExprValueType_Addr: { result.f = (t)value.addr; } break; \ +case DW_ExprValueType_Implicit: { InvalidPath; } break; \ +case DW_ExprValueType_Bool: { result.f = (t)value.boolean; } break; \ +default: { InvalidPath; } break; \ +} + + switch (type) { + case DW_ExprValueType_Generic: {} break; + case DW_ExprValueType_U8: { CastTable(u8, U8); } break; + case DW_ExprValueType_U16: { CastTable(u16, U16); } break; + case DW_ExprValueType_U32: { CastTable(u32, U32); } break; + case DW_ExprValueType_U64: { CastTable(u64, U64); } break; + case DW_ExprValueType_U128: { NotImplemented; } break; + case DW_ExprValueType_U256: { NotImplemented; } break; + case DW_ExprValueType_U512: { NotImplemented; } break; + case DW_ExprValueType_S8: { CastTable(s8, S8); } break; + case DW_ExprValueType_S16: { CastTable(s16, S16); } break; + case DW_ExprValueType_S32: { CastTable(s32, S32); } break; + case DW_ExprValueType_S64: { CastTable(s64, S64); } break; + case DW_ExprValueType_S128: { NotImplemented; } break; + case DW_ExprValueType_S256: { NotImplemented; } break; + case DW_ExprValueType_S512: { NotImplemented; } break; + case DW_ExprValueType_F32: { CastTable(f32, F32); } break; + case DW_ExprValueType_F64: { CastTable(f64, F64); } break; + case DW_ExprValueType_Addr: { CastTable(addr, U64); } break; + case DW_ExprValueType_Implicit: { NotImplemented; } break; + case DW_ExprValueType_Bool: { CastTable(boolean, DW_ExprBool); } break; + } + +#undef CastTable + return result; +} + +internal DW_ExprValue +dw_expr_add(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 + common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 + common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 + common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 + common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 + common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 + common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 + common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 + common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 + common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 + common_rhs.f32; } break; + case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 + common_rhs.f64; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr + common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + return result; +} + +internal DW_ExprValue +dw_expr_minus(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 - common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 - common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 - common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 - common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 - common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 - common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 - common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 - common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 - common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 - common_rhs.f32; } break; + case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 - common_rhs.f64; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr - common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + return result; +} + +internal DW_ExprValue +dw_expr_mul(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 * common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 * common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 * common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 * common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 * common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 * common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 * common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 * common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 * common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 * common_rhs.f32; } break; + case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 * common_rhs.f64; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr * common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + return result; +} + +internal DW_ExprValue +dw_expr_div(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 / common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 / common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 / common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 / common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 / common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 / common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 / common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 / common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 / common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 / common_rhs.f32; } break; + case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 / common_rhs.f64; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr / common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + return result; +} + +internal DW_ExprValue +dw_expr_mod(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 % common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 % common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 % common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 % common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 % common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 % common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 % common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 % common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 % common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { InvalidPath; } break; + case DW_ExprValueType_F64: { InvalidPath; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr % common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + return result; +} + +internal DW_ExprValue +dw_expr_eq(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 == common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 == common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 == common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 == common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 == common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 == common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 == common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 == common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 == common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 == common_rhs.f32; } break; + case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 == common_rhs.f64; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr == common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_ge(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 >= common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 >= common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 >= common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 >= common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 >= common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 >= common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 >= common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 >= common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 >= common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 >= common_rhs.f32; } break; + case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 >= common_rhs.f64; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr >= common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_gt(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 > common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 > common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 > common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 > common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 > common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 > common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 > common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 > common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 > common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 > common_rhs.f32; } break; + case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 > common_rhs.f64; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr > common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_le(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 <= common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 <= common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 <= common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 <= common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 <= common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 <= common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 <= common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 <= common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 <= common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 <= common_rhs.f32; } break; + case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 <= common_rhs.f64; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr <= common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_lt(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 < common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 < common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 < common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 < common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 < common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 < common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 < common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 < common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 < common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 < common_rhs.f32; } break; + case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 < common_rhs.f64; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr < common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_ne(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 != common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 != common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 != common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 != common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 != common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 != common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 != common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 != common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 != common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 != common_rhs.f32; } break; + case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 != common_rhs.f64; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr != common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_xor(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 ^ common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 ^ common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 ^ common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 ^ common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 ^ common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 ^ common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 ^ common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 ^ common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 ^ common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { InvalidPath; } break; + case DW_ExprValueType_F64: { InvalidPath; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr ^ common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_and(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 & common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 & common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 & common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 & common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 & common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 & common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 & common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 & common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 & common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { InvalidPath; } break; + case DW_ExprValueType_F64: { InvalidPath; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr & common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_or(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 | common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 | common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 | common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 | common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 | common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 | common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 | common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 | common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 | common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { InvalidPath; } break; + case DW_ExprValueType_F64: { InvalidPath; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr | common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_shl(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 << common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 << common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 << common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 << common_rhs.u64; } break; + + case DW_ExprValueType_U128: + case DW_ExprValueType_U256: + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 << common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 << common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 << common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 << common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 << common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { InvalidPath; } break; + case DW_ExprValueType_F64: { InvalidPath; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr << common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_shr(DW_ExprValue rhs, DW_ExprValue lhs) +{ + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 >> common_rhs.u8; } break; + case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 >> common_rhs.u16; } break; + case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 >> common_rhs.u32; } break; + case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 >> common_rhs.u64; } break; + + case DW_ExprValueType_U128: { NotImplemented; } break; + case DW_ExprValueType_U256: { NotImplemented; } break; + case DW_ExprValueType_U512: { NotImplemented; } break; + + case DW_ExprValueType_Bool: { InvalidPath; } break; + case DW_ExprValueType_S8: { InvalidPath; } break; + case DW_ExprValueType_S16: { InvalidPath; } break; + case DW_ExprValueType_S32: { InvalidPath; } break; + case DW_ExprValueType_S64: { InvalidPath; } break; + case DW_ExprValueType_S128: { InvalidPath; } break; + case DW_ExprValueType_S256: { InvalidPath; } break; + case DW_ExprValueType_S512: { InvalidPath; } break; + + case DW_ExprValueType_F32: { InvalidPath; } break; + case DW_ExprValueType_F64: { InvalidPath; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr >> common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_shra(DW_ExprValue rhs, DW_ExprValue lhs) +{ + if (DW_ExprValueType_IsUnsigned(lhs.type)) { + DW_ExprValueType new_type = dw_expr_signed_value_type_from_bit_size(dw_expr_byte_size_from_value_type(0, lhs.type) * 8); + lhs = dw_expr_cast(lhs, new_type); + } + + if (DW_ExprValueType_IsUnsigned(rhs.type)) { + DW_ExprValueType new_type = dw_expr_signed_value_type_from_bit_size(dw_expr_byte_size_from_value_type(0, rhs.type) * 8); + rhs = dw_expr_cast(rhs, new_type); + } + + DW_ExprValue result = {0}; + result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); + + DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); + DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); + + switch (result.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { InvalidPath; } break; + case DW_ExprValueType_U16: { InvalidPath; } break; + case DW_ExprValueType_U32: { InvalidPath; } break; + case DW_ExprValueType_U64: { InvalidPath; } break; + case DW_ExprValueType_U128: { InvalidPath; } break; + case DW_ExprValueType_U256: { InvalidPath; } break; + case DW_ExprValueType_U512: { InvalidPath; } break; + + case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 >> common_rhs.s8; } break; + case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 >> common_rhs.s8; } break; + case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 >> common_rhs.s16; } break; + case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 >> common_rhs.s32; } break; + case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 >> common_rhs.s64; } break; + + case DW_ExprValueType_S128: + case DW_ExprValueType_S256: + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { InvalidPath; } break; + case DW_ExprValueType_F64: { InvalidPath; } break; + case DW_ExprValueType_Addr: { result.addr = common_lhs.addr >> common_rhs.addr; } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + + default: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_abs(DW_ExprValue value) +{ + DW_ExprValue result = value; + + switch (value.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: {}; break; + case DW_ExprValueType_U16: {}; break; + case DW_ExprValueType_U32: {}; break; + case DW_ExprValueType_U64: {}; break; + case DW_ExprValueType_U128: {}; break; + case DW_ExprValueType_U256: {}; break; + case DW_ExprValueType_U512: {}; break; + + case DW_ExprValueType_S8: { result.s8 = abs_s64(result.s8); } break; + case DW_ExprValueType_S16: { result.s16 = abs_s64(result.s16); } break; + case DW_ExprValueType_S32: { result.s32 = abs_s64(result.s32); } break; + case DW_ExprValueType_S64: { result.s64 = abs_s64(result.s64); } break; + case DW_ExprValueType_S128: { NotImplemented; } break; + case DW_ExprValueType_S256: { NotImplemented; } break; + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = abs_f32(result.f32); } break; + case DW_ExprValueType_F64: { result.f64 = abs_f64(result.f64); } break; + + case DW_ExprValueType_Addr: {} break; + case DW_ExprValueType_Bool: { result.boolean = abs_s64(result.boolean); } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_neg(DW_ExprValue value) +{ + DW_ExprValue result = value; + + switch (value.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = -result.u8; }; break; + case DW_ExprValueType_U16: { result.u16 = -result.u16; }; break; + case DW_ExprValueType_U32: { result.u32 = -result.u32; }; break; + case DW_ExprValueType_U64: { result.u64 = -result.u64; }; break; + case DW_ExprValueType_U128: { NotImplemented; }; break; + case DW_ExprValueType_U256: { NotImplemented; }; break; + case DW_ExprValueType_U512: { NotImplemented; }; break; + + case DW_ExprValueType_S8: { result.s8 = -result.s8; } break; + case DW_ExprValueType_S16: { result.s16 = -result.s16; } break; + case DW_ExprValueType_S32: { result.s32 = -result.s32; } break; + case DW_ExprValueType_S64: { result.s64 = -result.s64; } break; + case DW_ExprValueType_S128: { NotImplemented; } break; + case DW_ExprValueType_S256: { NotImplemented; } break; + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = -result.f32; } break; + case DW_ExprValueType_F64: { result.f64 = -result.f64; } break; + + case DW_ExprValueType_Addr: { result.addr = -result.addr; } break; + case DW_ExprValueType_Bool: { result.boolean = abs_s64(result.boolean); } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + } + + return result; +} + +internal DW_ExprValue +dw_expr_not(DW_ExprValue value) +{ + DW_ExprValue result = value; + + switch (value.type) { + case DW_ExprValueType_Generic: { InvalidPath; } break; + + case DW_ExprValueType_U8: { result.u8 = !result.u8; }; break; + case DW_ExprValueType_U16: { result.u16 = !result.u16; }; break; + case DW_ExprValueType_U32: { result.u32 = !result.u32; }; break; + case DW_ExprValueType_U64: { result.u64 = !result.u64; }; break; + case DW_ExprValueType_U128: { NotImplemented; }; break; + case DW_ExprValueType_U256: { NotImplemented; }; break; + case DW_ExprValueType_U512: { NotImplemented; }; break; + + case DW_ExprValueType_S8: { result.s8 = !result.s8; } break; + case DW_ExprValueType_S16: { result.s16 = !result.s16; } break; + case DW_ExprValueType_S32: { result.s32 = !result.s32; } break; + case DW_ExprValueType_S64: { result.s64 = !result.s64; } break; + case DW_ExprValueType_S128: { NotImplemented; } break; + case DW_ExprValueType_S256: { NotImplemented; } break; + case DW_ExprValueType_S512: { NotImplemented; } break; + + case DW_ExprValueType_F32: { result.f32 = !result.f32; } break; + case DW_ExprValueType_F64: { result.f64 = !result.f64; } break; + + case DW_ExprValueType_Addr: { result.addr = !result.addr; } break; + case DW_ExprValueType_Bool: { result.boolean = abs_s64(result.boolean); } break; + case DW_ExprValueType_Implicit: { InvalidPath; } break; + } + + return result; +} + +internal String8 +dw_string_from_expr_value(Arena *arena, U64 addr_size, DW_ExprValue v) +{ + String8 s = {0}; + switch (v.type) { + case DW_ExprValueType_Generic: { } break; + case DW_ExprValueType_U8: { s = str8_struct(&v.u8); } break; + case DW_ExprValueType_U16: { s = str8_struct(&v.u16); } break; + case DW_ExprValueType_U32: { s = str8_struct(&v.u32); } break; + case DW_ExprValueType_U64: { s = str8_struct(&v.u64); } break; + case DW_ExprValueType_U128: { s = str8_struct(&v.u128); } break; + case DW_ExprValueType_U256: { s = str8_struct(&v.u256); } break; + case DW_ExprValueType_U512: { s = str8_struct(&v.u512); } break; + case DW_ExprValueType_S8: { s = str8_struct(&v.s8); } break; + case DW_ExprValueType_S16: { s = str8_struct(&v.s16); } break; + case DW_ExprValueType_S32: { s = str8_struct(&v.s32); } break; + case DW_ExprValueType_S64: { s = str8_struct(&v.s64); } break; + case DW_ExprValueType_F32: { s = str8_struct(&v.f32); } break; + case DW_ExprValueType_F64: { s = str8_struct(&v.f64); } break; + case DW_ExprValueType_Addr: { s = str8((U8 *)&v.addr, addr_size); } break; + case DW_ExprValueType_Implicit: { s = v.implicit; } break; + default: { NotImplemented; } break; + } + return str8_copy(arena, s); +} + +internal DW_ExprValueNode * +dw_expr_stack_push(Arena *arena, DW_ExprStack *stack, DW_ExprValue value) +{ + DW_ExprValueNode *n = push_array(arena, DW_ExprValueNode, 1); + n->v = value; + SLLStackPush(stack->top, n); + stack->count += 1; + return n; +} + +internal DW_ExprValueNode * +dw_expr_stack_push_unsigned(Arena *arena, DW_ExprStack *stack, void *value, U64 value_size) +{ + DW_ExprValueNode *n = 0; + switch (value_size) { + case 0: {} break; + case 1: { n = dw_expr_stack_push(arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U8, .u8 = *(U8 *)value }); } break; + case 2: { n = dw_expr_stack_push(arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U16, .u16 = *(U16 *)value }); } break; + case 4: { n = dw_expr_stack_push(arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U32, .u32 = *(U32 *)value }); } break; + case 8: { n = dw_expr_stack_push(arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U64, .u64 = *(U64 *)value }); } break; + default: { NotImplemented; } break; + } + return n; +} + +internal DW_ExprValue +dw_expr_stack_pop(DW_ExprStack *stack) +{ + DW_ExprValueNode *n = stack->top; + DW_ExprValue v = n->v; + SLLStackPop(stack->top); + return v; +} + +internal DW_ExprValue +dw_expr_stack_peek(DW_ExprStack *stack) +{ + return stack->top->v; +} + +internal DW_ExprValueNode * +dw_expr_stack_pick(DW_ExprStack *stack, U64 idx) +{ + DW_ExprValueNode *n = 0; + if (idx < stack->count) { + U64 c = idx; + for (n = stack->top; n != 0 && c > 0; n = n->next, c -= 1); + } + return n; +} + +internal DW_ExprInst * +dw_expr_inst_from_delta(DW_ExprInst *inst, S16 delta) +{ + B32 skip_fwd = inst->operands[0].s16 >= 0; + DW_ExprInst *i = inst; + U16 u_delta = abs_s64(inst->operands[0].s16); + U64 cursor = 0; + for (i = skip_fwd ? inst : inst->prev; i != 0 && cursor < u_delta; i = skip_fwd ? inst->next : inst->prev) { + cursor += inst->size; + } + if (cursor != u_delta) { + i = 0; + } + return i; +} + +internal DW_ExprEvalResult +dw_eval_expr(Arena *arena, Arch arch, DW_Format format, U64 frame_base, U64 cfa, U64 tls, U64 exec_op_limit, DW_Expr expr, void *reg_block, MachineOp_MemRead *mem_read, void *mem_read_ud, DW_ExprValue *value_out) +{ + Temp scratch = scratch_begin(&arena, 1); + + ARCH_Info *arch_info = arch_info_from_arch(arch); + + DW_ExprEvalResult result = DW_ExprEvalResult_Fail; + DW_PieceList pieces = {0}; + DW_ExprStack *stack = push_array(scratch.arena, DW_ExprStack, 1); + U64 exec_op_count = 0; + + for EachNode(inst, DW_ExprInst, expr.first) { + again:; + + exec_op_count += 1; + if (exec_op_count > exec_op_limit) { + Assert(0 && "reached opcode exec limit on the expression"); + result = DW_ExprEvalResult_ExecOpLimitReached; + goto exit; + } + + U64 pop_count = dw_pop_count_from_expr_op(inst->opcode); + if (pop_count > stack->count) { + Assert(0 && "not enough values on the stack to evaluate the instruction"); + goto exit; + } + + switch (inst->opcode) { + case DW_ExprOp_Nop: {} break; + + 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: { + dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U8, .u8 = inst->opcode - DW_ExprOp_Lit0 }); + } break; + + case DW_ExprOp_Const1U: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U8, .u8 = inst->operands[0].u8 }); } break; + case DW_ExprOp_Const2U: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U16, .u16 = inst->operands[0].u16 }); } break; + case DW_ExprOp_Const4U: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U32, .u32 = inst->operands[0].u32 }); } break; + case DW_ExprOp_Const8U: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U64, .u64 = inst->operands[0].u64 }); } break; + case DW_ExprOp_Const1S: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_S8, .s8 = inst->operands[0].s8 }); } break; + case DW_ExprOp_Const2S: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_S16, .s16 = inst->operands[0].s16 }); } break; + case DW_ExprOp_Const4S: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_S32, .s32 = inst->operands[0].s32 }); } break; + case DW_ExprOp_Const8S: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_S64, .s64 = inst->operands[0].s64 }); } break; + case DW_ExprOp_ConstU: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U64, .u64 = inst->operands[0].u64 }); } break; + case DW_ExprOp_ConstS: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_S64, .s64 = inst->operands[0].s64 }); } break; + case DW_ExprOp_Addr: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_Addr, .addr = inst->operands[0].u64 }); } 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: + { + DW_Reg reg_dw_id = inst->opcode - DW_ExprOp_Reg0; + U64 reg_size = dw_reg_size_from_code(arch, reg_dw_id); + ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_dw_id); + Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code]; + U8 *reg_value = push_array(scratch.arena, U8, reg_size); + if(!arch_reg_block_read_range(arch_info, reg_block, r1u16(reg_rng.min, reg_rng.min + reg_size), reg_value)) + { + goto exit; + } + dw_expr_stack_push_unsigned(scratch.arena, stack, reg_value, reg_size); + }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: + { + DW_Reg reg_dw_id = inst->opcode - DW_ExprOp_BReg0; + U64 reg_size = dw_reg_size_from_code(arch, reg_dw_id); + ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_dw_id); + Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code]; + AssertAlways(reg_size <= byte_size_from_arch(arch)); + + U64 reg_value = 0; + if(!arch_reg_block_read_range(arch_info, reg_block, r1u16(reg_rng.min, reg_rng.min + reg_size), ®_value)) + { + goto exit; + } + + U64 addr = (U64)((S64)reg_value + inst->operands[0].s64); + dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_Addr, .addr = addr}); + }break; + + case DW_ExprOp_RegX: + { + DW_Reg reg_dw_id = inst->operands[0].u64; + U64 reg_size = dw_reg_size_from_code(arch, reg_dw_id); + U8 *reg_value = push_array(scratch.arena, U8, reg_size); + ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_dw_id); + Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code]; + if(!arch_reg_block_read_range(arch_info, reg_block, r1u16(reg_rng.min, reg_rng.min + reg_size), reg_value)) + { + goto exit; + } + dw_expr_stack_push_unsigned(scratch.arena, stack, reg_value, reg_size); + }break; + + case DW_ExprOp_BRegX: + { + DW_Reg reg_dw_id = (DW_Reg)inst->operands[0].u64; + U64 reg_size = dw_reg_size_from_code(arch, reg_dw_id); + AssertAlways(reg_size <= byte_size_from_arch(arch)); + ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_dw_id); + Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code]; + + U64 reg_value = 0; + if(!arch_reg_block_read_range(arch_info, reg_block, r1u16(reg_rng.min, reg_rng.min + reg_size), ®_value)) + { + goto exit; + } + + U64 addr = (U64)((S64)reg_value + inst->operands[1].s64); + dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_Addr, .addr = addr}); + }break; + + case DW_ExprOp_FBReg: { + U64 addr = frame_base + inst->operands[0].s64; + dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_Addr, .addr = addr}); + } break; + + case DW_ExprOp_ImplicitValue: { + if (inst->operands[0].block.size <= sizeof(U512)) { + dw_expr_stack_push_unsigned(scratch.arena, stack, inst->operands[0].block.str, inst->operands[0].block.size); + } else { + NotImplemented; + } + } break; + + case DW_ExprOp_Piece: { + B32 is_undefined = stack->count == 0 || (inst->prev && inst->prev->opcode == DW_ExprOp_Piece); + if (is_undefined) { + dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Undefined, .bit_size = inst->operands[0].u64 * 8 }); + } else { + DW_ExprValue top = dw_expr_stack_pop(stack); + + String8 value; + + // piece is a memory reference + if (top.type == DW_ExprValueType_Addr) { + U64 value_size = inst->operands[0].u64; + U8 *value_buffer = push_array(arena, U8, value_size); + MachineOpResult read_result = mem_read(top.addr, value_buffer, value_size, mem_read_ud); + if (read_result != MachineOpResult_Ok) { Assert(0 && "failed to read piece memory referece"); goto exit; } + } + // piece is a value + else { + value = dw_string_from_expr_value(arena, arch, top); + } + + if (inst->operands[0].u64 > value.size) { Assert(0 && "out of bounds size in the piece opcode"); goto exit; } + dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Value, .bit_size = inst->operands[0].u64 * 8, .value = value.str }); + } + } break; + + case DW_ExprOp_BitPiece: { + B32 is_undefined = stack->count == 0 || (inst->prev && inst->prev->opcode == DW_ExprOp_Piece); + if (is_undefined) { + dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Undefined, .bit_size = inst->operands[0].u64 }); + } else { + String8 value; + if (dw_expr_stack_peek(stack).type == DW_ExprValueType_Addr) { + NotImplemented; + } else { + value = dw_string_from_expr_value(arena, arch, dw_expr_stack_pop(stack)); + } + if (inst->operands[0].u64 > value.size * 8) { Assert(0 && "out of bounds size in piece opcode"); goto exit; } + dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Value, .bit_size = inst->operands[0].u64, .value = value.str }); + } + } break; + + case DW_ExprOp_Pick: { + DW_ExprValueNode *src = dw_expr_stack_pick(stack, inst->operands[0].u8); + if (src) { + dw_expr_stack_push(scratch.arena, stack, src->v); + } else { + Assert(0 && "out of bounds stack index"); + goto exit; + } + } break; + + case DW_ExprOp_Over: { + DW_ExprValueNode *src = dw_expr_stack_pick(stack, 1); + if (src) { + dw_expr_stack_push(scratch.arena, stack, src->v); + } else { + Assert(0 && "out of bounds stack index"); + goto exit; + } + } break; + + case DW_ExprOp_PlusUConst: { + DW_ExprValue lhs = dw_expr_stack_pop(stack); + DW_ExprValue rhs = { .type = DW_ExprValueType_U64, .u64 = inst->operands[0].u64 }; + DW_ExprValue sum = dw_expr_add(lhs, rhs); + dw_expr_stack_push(scratch.arena, stack, sum); + } break; + + case DW_ExprOp_Skip: { + DW_ExprInst *i = dw_expr_inst_from_delta(inst, inst->operands[0].s16); + + if (i == 0) { + Assert(0 && "seeking to an invalid offset"); + goto exit; + } + + inst = i; + goto again; + } + + case DW_ExprOp_Bra: { + DW_ExprValue cond = dw_expr_stack_pop(stack); + + if (cond.type != DW_ExprValueType_S16) { + Assert(0 && "unexpected value"); + goto exit; + } + + DW_ExprInst *i = dw_expr_inst_from_delta(inst, inst->operands[0].s16); + + if (i == 0) { + Assert(0 && "seeking to an invalid offset"); + goto exit; + } + + inst = i; + goto again; + } + + case DW_ExprOp_Call2: + case DW_ExprOp_Call4: + case DW_ExprOp_CallRef: { + NotImplemented; + } break; + + case DW_ExprOp_GNU_Convert: + case DW_ExprOp_Convert: { + if (inst->operands[0].u64 == 0) { + DW_ExprValue value = dw_expr_stack_pop(stack); + DW_ExprValue new_value = dw_expr_cast(value, DW_ExprValueType_Generic); + dw_expr_stack_push(scratch.arena, stack, new_value); + } else { + NotImplemented; + } + } break; + + case DW_ExprOp_Reinterpret: { + if (inst->operands[0].u64 == 0) { + DW_ExprValue value = dw_expr_stack_pop(stack); + DW_ExprValue new_value = dw_expr_cast(value, DW_ExprValueType_Generic); + dw_expr_stack_push(scratch.arena, stack, new_value); + } else { + NotImplemented; + } + } break; + + case DW_ExprOp_GNU_ParameterRef: { NotImplemented; } break; + case DW_ExprOp_GNU_DerefType: { NotImplemented; } break; + case DW_ExprOp_DerefType: { NotImplemented; } break; + case DW_ExprOp_ConstType: { NotImplemented; } break; + case DW_ExprOp_GNU_ConstType: { NotImplemented; } break; + case DW_ExprOp_RegvalType: { NotImplemented; } break; + + case DW_ExprOp_EntryValue: + case DW_ExprOp_GNU_EntryValue: + { + DW_Expr entry_value_expr = dw_expr_from_data(scratch.arena, format, byte_size_from_arch(arch), inst->operands[0].block); + DW_ExprValue entry_value; + result = dw_eval_expr(scratch.arena, arch, format, frame_base, cfa, tls, exec_op_limit, entry_value_expr, reg_block, mem_read, mem_read_ud, &entry_value); + if (result != DW_ExprEvalResult_Ok) { goto exit; } + dw_expr_stack_push(scratch.arena, stack, entry_value); + } break; + + case DW_ExprOp_Addrx: { NotImplemented; } break; + + case DW_ExprOp_CallFrameCfa: { + dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U64, .u64 = cfa }); + } break; + + case DW_ExprOp_PushObjectAddress: { NotImplemented; } break; + + case DW_ExprOp_Plus: { dw_expr_stack_push(scratch.arena, stack, dw_expr_add(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Minus: { dw_expr_stack_push(scratch.arena, stack, dw_expr_minus(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Div: { dw_expr_stack_push(scratch.arena, stack, dw_expr_div(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Mul: { dw_expr_stack_push(scratch.arena, stack, dw_expr_mul(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Mod: { dw_expr_stack_push(scratch.arena, stack, dw_expr_mod(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + + case DW_ExprOp_Eq: { dw_expr_stack_push(scratch.arena, stack, dw_expr_eq(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Ge: { dw_expr_stack_push(scratch.arena, stack, dw_expr_ge(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Gt: { dw_expr_stack_push(scratch.arena, stack, dw_expr_gt(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Le: { dw_expr_stack_push(scratch.arena, stack, dw_expr_le(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Lt: { dw_expr_stack_push(scratch.arena, stack, dw_expr_lt(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Ne: { dw_expr_stack_push(scratch.arena, stack, dw_expr_ne(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + + case DW_ExprOp_Xor: { dw_expr_stack_push(scratch.arena, stack, dw_expr_xor(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_And: { dw_expr_stack_push(scratch.arena, stack, dw_expr_and(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Or: { dw_expr_stack_push(scratch.arena, stack, dw_expr_or(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Shl: { dw_expr_stack_push(scratch.arena, stack, dw_expr_shl(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Shr: { dw_expr_stack_push(scratch.arena, stack, dw_expr_shr(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Shra: { dw_expr_stack_push(scratch.arena, stack, dw_expr_shra(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; + + case DW_ExprOp_Abs: { dw_expr_stack_push(scratch.arena, stack, dw_expr_abs(dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Neg: { dw_expr_stack_push(scratch.arena, stack, dw_expr_neg(dw_expr_stack_pop(stack))); } break; + case DW_ExprOp_Not: { dw_expr_stack_push(scratch.arena, stack, dw_expr_not(dw_expr_stack_pop(stack))); } break; + + case DW_ExprOp_Dup: { + dw_expr_stack_push(scratch.arena, stack, dw_expr_stack_peek(stack)); + } break; + + case DW_ExprOp_Rot: { + DW_ExprValue first = dw_expr_stack_pop(stack); + DW_ExprValue second = dw_expr_stack_pop(stack); + DW_ExprValue third = dw_expr_stack_pop(stack); + dw_expr_stack_push(scratch.arena, stack, first); // -> third + dw_expr_stack_push(scratch.arena, stack, third); // -> second + dw_expr_stack_push(scratch.arena, stack, second); // -> first + } break; + + case DW_ExprOp_Swap: { + DW_ExprValue first = dw_expr_stack_pop(stack); + DW_ExprValue second = dw_expr_stack_pop(stack); + dw_expr_stack_push(scratch.arena, stack, first); // -> second + dw_expr_stack_push(scratch.arena, stack, second); // -> first + } break; + + case DW_ExprOp_Drop: { + dw_expr_stack_pop(stack); + } break; + + case DW_ExprOp_Deref: { + DW_ExprValue value = dw_expr_stack_pop(stack); + + // expression must be of an integral type + if (!DW_ExprValueType_IsInt(value.type)) { goto exit; } + + // treat value as an address + DW_ExprValue addr = dw_expr_cast(value, DW_ExprValueType_Addr); + + // read pointer size from the address + U64 addr_size = byte_size_from_arch(arch); + U8 *generic_value = push_array(scratch.arena, U8, addr_size); + MachineOpResult read_result = mem_read(addr.addr, generic_value, addr_size, mem_read_ud); + if (read_result != MachineOpResult_Ok) { goto exit; } + + // push generic data + dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_Generic, .generic = str8(generic_value, addr_size) }); + } break; + + case DW_ExprOp_StackValue: { + stack->top->v.type = dw_expr_unsigned_value_type_from_bit_size(bit_size_from_arch(arch)); + } break; + + case DW_ExprOp_GNU_PushTlsAddress: + case DW_ExprOp_FormTlsAddress: { + DW_ExprValue tls_off = dw_expr_stack_pop(stack); + DW_ExprValue tls_base = { .type = DW_ExprValueType_Addr, .addr = tls }; + DW_ExprValue tls_addr = dw_expr_add(tls_base, tls_off); + dw_expr_stack_push(scratch.arena, stack, tls_addr); + } break; + } + } + + // composite value + if (pieces.count > 0) { +#if 0 + U64 total_bit_size = 0; + for EachNode (n, DW_PieceNode, pieces.first) { + total_bit_size += n->v.bit_size; + } + + U64 value_size = CeilIntegerDiv(total_bit_size, 8); + U8 *value = push_array(arena, U8, value_size); + Rng1U64 *ranges = push_array(arena, Rng1U64, pieces.count); + U64 *offsets = push_array(arena, U64, pieces.count); + U64 value_idx = 0; + U64 value_cursor = 0; + U64 piece_cursor = 0; + for EachNode(n, DW_PieceNode, pieces.first) { + if (n->v.kind == DW_PieceKind_Value) { + ranges[value_idx] = r1u64(piece_cursor, piece_cursor + n->v.bit_size); + offsets[value_idx] = value_cursor; + for (U64 i = 0; i < n->v.bit_size; i += 8) { + U64 to_copy = Min(8, n->v.bit_size - i); + if (value_cursor % 8 == 0) { + value[value_cursor / 8] = n->v.value[i]; + } else { + value[value_cursor / 8] |= n->v.value[i] << (value_cursor % 8); + value[AlignPow2(value_cursor / 8, 8)] |= n->v.value[i] >> (value_cursor % 8); + } + value_cursor += to_copy; + } + value_idx += 1; + } + piece_cursor += n->v.bit_size; + } + + value_out->type = DW_ExprValueType_Generic; + value_out->ranges = (Rng1U64Array){ .count = pieces.count, .v = ranges }; + value_out->offsets = offsets; + value_out->generic = str8(value, value_size); +#else + NotImplemented; +#endif + } + // scalar + else { + if (stack->top) { + *value_out = stack->top->v; + if (value_out->type == DW_ExprValueType_Generic) { + value_out->generic = push_str8_copy(arena, value_out->generic); + } + + Rng1U64 *range = push_array(arena, Rng1U64, 1); + *range = r1u64(0, max_U64); + value_out->ranges = (Rng1U64Array){ .count = 1, .v = range }; + value_out->offsets = push_array(arena, U64, 1); + } else { + MemoryZeroStruct(value_out); + } + } + + result = DW_ExprEvalResult_Ok; + exit:; + scratch_end(scratch); + return result; +} diff --git a/obsolete/dwarf/dwarf_expr_old.h b/obsolete/dwarf/dwarf_expr_old.h new file mode 100644 index 00000000..432b5b22 --- /dev/null +++ b/obsolete/dwarf/dwarf_expr_old.h @@ -0,0 +1,233 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DWARF_EXPR_H +#define DWARF_EXPR_H + +//////////////////////////////// +// evaluator + +#define DW_ExprValueType_IsSigned(x) ((x) == DW_ExprValueType_S8 || (x) == DW_ExprValueType_S16 || (x) == DW_ExprValueType_S32 || (x) == DW_ExprValueType_S64 || (x) == DW_ExprValueType_S128 || (x) == DW_ExprValueType_S256 || (x) == DW_ExprValueType_S512) +#define DW_ExprValueType_IsUnsigned(x) ((x) == DW_ExprValueType_U8 || (x) == DW_ExprValueType_U16 || (x) == DW_ExprValueType_U32 || (x) == DW_ExprValueType_U64 || (x) == DW_ExprValueType_U128 || (x) == DW_ExprValueType_U256 || (x) == DW_ExprValueType_U512) +#define DW_ExprValueType_IsFloat(x) ((x) == DW_ExprValueType_F32 || (x) == DW_ExprValueType_F64) +#define DW_ExprValueType_IsInt(x) (DW_ExprValueType_IsSigned(x) || DW_ExprValueType_IsUnsigned(x) || (x) == DW_ExprValueType_Addr) +typedef enum +{ + DW_ExprValueType_Generic, + DW_ExprValueType_U8, + DW_ExprValueType_U16, + DW_ExprValueType_U32, + DW_ExprValueType_U64, + DW_ExprValueType_U128, + DW_ExprValueType_U256, + DW_ExprValueType_U512, + DW_ExprValueType_S8, + DW_ExprValueType_S16, + DW_ExprValueType_S32, + DW_ExprValueType_S64, + DW_ExprValueType_S128, + DW_ExprValueType_S256, + DW_ExprValueType_S512, + DW_ExprValueType_F32, + DW_ExprValueType_F64, + DW_ExprValueType_Addr, + DW_ExprValueType_Implicit, + DW_ExprValueType_Bool, +} DW_ExprValueType; + +typedef S8 DW_ExprBool; + +typedef struct DW_ExprValue +{ + DW_ExprValueType type; + Rng1U64Array ranges; + U64 *offsets; + union { + U8 u8; + U16 u16; + U32 u32; + U64 u64; + U128 u128; + U256 u256; + U512 u512; + S8 s8; + S16 s16; + S32 s32; + S64 s64; + F32 f32; + F64 f64; + U64 addr; + DW_ExprBool boolean; + String8 implicit; + String8 generic; + }; +} DW_ExprValue; + +typedef struct DW_ExprValueNode +{ + DW_ExprValue v; + struct DW_ExprValueNode *next; +} DW_ExprValueNode; + +typedef enum +{ + DW_PieceKind_Null, + DW_PieceKind_Value, + DW_PieceKind_Undefined, +} DW_PieceKind; + +typedef struct DW_Piece +{ + DW_PieceKind kind; + U64 bit_size; + U8 *value; +} DW_Piece; + +typedef struct DW_PieceNode +{ + DW_Piece v; + struct DW_PieceNode *next; +} DW_PieceNode; + +typedef struct DW_PieceList +{ + U64 count; + DW_PieceNode *first; + DW_PieceNode *last; +} DW_PieceList; + +typedef struct DW_ExprStack +{ + U64 count; + DW_ExprValueNode *top; +} DW_ExprStack; + +typedef enum +{ + DW_ExprEvalResult_Fail, + DW_ExprEvalResult_Ok, + DW_ExprEvalResult_Maybe, + DW_ExprEvalResult_ExecOpLimitReached, +} DW_ExprEvalResult; + +//////////////////////////////// +// encoder + +typedef enum +{ + DW_ExprEncType_Null, + DW_ExprEncType_Op, + DW_ExprEncType_U8, + DW_ExprEncType_U16, + DW_ExprEncType_U32, + DW_ExprEncType_U64, + DW_ExprEncType_S8, + DW_ExprEncType_S16, + DW_ExprEncType_S32, + DW_ExprEncType_S64, + DW_ExprEncType_ULEB128, + DW_ExprEncType_SLEB128, + DW_ExprEncType_Addr, + DW_ExprEncType_Block, + DW_ExprEncType_DwarfUInt, + DW_ExprEncType_Label, + DW_ExprEncType_DeclLabel, +} DW_ExprEncType; + +typedef struct DW_ExprEnc +{ + DW_ExprEncType type; + union { + DW_ExprOp op; + U8 u8; + U16 u16; + U32 u32; + U64 u64; + S8 s8; + S16 s16; + S32 s32; + S64 s64; + U64 addr; + String8 block; + String8 label; + }; +} DW_ExprEnc; + +#define DW_ExprEnc_Op(v) { .type = DW_ExprEncType_Op, .op = DW_ExprOp_##v } +#define DW_ExprEnc_U8(v) { .type = DW_ExprEncType_U8, .u8 = v } +#define DW_ExprEnc_U16(v) { .type = DW_ExprEncType_U16, .u16 = v } +#define DW_ExprEnc_U32(v) { .type = DW_ExprEncType_U32, .u32 = v } +#define DW_ExprEnc_U64(v) { .type = DW_ExprEncType_U64, .u64 = v } +#define DW_ExprEnc_S8(v) { .type = DW_ExprEncType_S8, .s8 = v } +#define DW_ExprEnc_S16(v) { .type = DW_ExprEncType_S16, .s16 = v } +#define DW_ExprEnc_S32(v) { .type = DW_ExprEncType_S32, .s32 = v } +#define DW_ExprEnc_S64(v) { .type = DW_ExprEncType_S64, .s64 = v } +#define DW_ExprEnc_ULEB128(v) { .type = DW_ExprEncType_ULEB128, .u64 = v } +#define DW_ExprEnc_SLEB128(v) { .type = DW_ExprEncType_SLEB128, .s64 = v } +#define DW_ExprEnc_Addr(v) { .type = DW_ExprEncType_Addr, .addr = v } +#define DW_ExprEnc_Block(v) { .type = DW_ExprEncType_Block, .block = v } +#define DW_ExprEnc_UInt(v) { .type = DW_ExprEncType_DwarfUInt, .u64 = v } +#define DW_ExprEnc_Label(v) { .type = DW_ExprEncType_Label, .label = str8_lit_comp(v) } +#define DW_ExprEnc_DeclLabel(v) { .type = DW_ExprEncType_DeclLabel, .label = str8_lit_comp(v) } + +//////////////////////////////// + +// pieces +internal DW_PieceNode * dw_piece_list_push(Arena *arena, DW_PieceList *list, DW_Piece v); + +// size -> type +internal DW_ExprValueType dw_expr_unsigned_value_type_from_bit_size(U64 bit_size); +internal DW_ExprValueType dw_expr_signed_value_type_from_bit_size(U64 bit_size); +internal DW_ExprValueType dw_expr_float_type_from_bit_size(U64 bit_size); + +// type -> size +internal U64 dw_expr_byte_size_from_value_type(U64 addr_size, DW_ExprValueType k); + +// typer +internal DW_ExprValueType dw_expr_pick_common_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs); +internal DW_ExprValueType dw_expr_pick_common_compar_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs); +internal DW_ExprValue dw_expr_cast(DW_ExprValue value, DW_ExprValueType type); + +// arithmetic operators +internal DW_ExprValue dw_expr_add (DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_minus(DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_mul (DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_div (DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_mod (DW_ExprValue rhs, DW_ExprValue lhs); + +// comparison operators +internal DW_ExprValue dw_expr_eq(DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_ge(DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_gt(DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_le(DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_lt(DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_ne(DW_ExprValue rhs, DW_ExprValue lhs); + +// bitwise operators +internal DW_ExprValue dw_expr_xor (DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_and (DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_or (DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_shl (DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_shr (DW_ExprValue rhs, DW_ExprValue lhs); +internal DW_ExprValue dw_expr_shra(DW_ExprValue rhs, DW_ExprValue lhs); + +// unary operators +internal DW_ExprValue dw_expr_abs(DW_ExprValue value); +internal DW_ExprValue dw_expr_neg(DW_ExprValue value); +internal DW_ExprValue dw_expr_not(DW_ExprValue value); + +// stack +internal DW_ExprValueNode * dw_expr_stack_push(Arena *arena, DW_ExprStack *stack, DW_ExprValue value); +internal DW_ExprValueNode * dw_expr_stack_push_unsigned(Arena *arena, DW_ExprStack *stack, void *value, U64 value_size); +internal DW_ExprValue dw_expr_stack_pop(DW_ExprStack *stack); +internal DW_ExprValue dw_expr_stack_peek(DW_ExprStack *stack); +internal DW_ExprValueNode * dw_expr_stack_pick(DW_ExprStack *stack, U64 idx); + +// value helpers +internal String8 dw_string_from_expr_value(Arena *arena, U64 addr_size, DW_ExprValue v); + +// 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); + +#endif //DWARF_EXPR_H + diff --git a/obsolete/dwarf/dwarf_parse_old.c b/obsolete/dwarf/dwarf_parse_old.c new file mode 100644 index 00000000..a8898477 --- /dev/null +++ b/obsolete/dwarf/dwarf_parse_old.c @@ -0,0 +1,3331 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal U64 +dw_hash_from_string(String8 string) +{ + XXH64_hash_t hash64 = XXH3_64bits(string.str, string.size); + return hash64; +} + +internal U64 +str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_out) +{ + U64 bytes_read = 0; + U32 first_four_bytes; + if (str8_deserial_read_struct(string, off, &first_four_bytes) == sizeof(first_four_bytes)) { + if (first_four_bytes == max_U32) { + if (str8_deserial_read_struct(string, off+sizeof(U32), size_out) == sizeof(U64)) { + bytes_read = sizeof(U32) + sizeof(U64); + } + } else { + *size_out = first_four_bytes; + bytes_read = sizeof(U32); + } + } + return bytes_read; +} + +internal U64 +str8_deserial_read_dwarf_uint(String8 string, U64 off, DW_Format format, U64 *uint_out) +{ + U64 bytes_read = 0; + switch (format) { + case DW_Format_Null: break; + case DW_Format_32Bit: { + *uint_out &= (U64)max_U32; + bytes_read = str8_deserial_read(string, off, uint_out, sizeof(U32), sizeof(U32)); + } break; + case DW_Format_64Bit: { + bytes_read = str8_deserial_read_struct(string, off, uint_out); + } break; + } + return bytes_read; +} + +internal U64 +str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out) +{ + U64 value = 0; + U64 shift = 0; + U64 cursor = off; + for(;;) + { + 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; + } + } + if(value_out != 0) + { + *value_out = value; + } + U64 bytes_read = cursor - off; + return bytes_read; +} + +internal U64 +str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out) +{ + U64 value = 0; + U64 shift = 0; + U64 cursor = off; + for(;;) + { + U8 byte; + 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) + { + if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0) + { + value |= -(S64)(1ull << shift); + } + break; + } + } + if(value_out != 0) + { + *value_out = value; + } + U64 bytes_read = cursor - off; + return bytes_read; +} + +internal U64 +str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_out) +{ + Temp temp = temp_begin(arena); + + U64 *arr = push_array(arena, U64, count); + U64 i, cursor; + for (i = 0, cursor = off; i < count; ++i) { + U64 read_size = str8_deserial_read_uleb128(string, cursor, &arr[i]); + if (read_size == 0) { + break; + } + cursor += read_size; + } + + U64 bytes_read = 0; + if (i == count) { + *arr_out = arr; + bytes_read = cursor - off; + } else { + temp_end(temp); + *arr_out = 0; + } + + return bytes_read; +} + +internal U64 +str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out) +{ + Temp temp = temp_begin(arena); + + S64 *arr = push_array(arena, S64, count); + U64 i, cursor; + for (i = 0, cursor = off; i < count; ++i) { + U64 read_size = str8_deserial_read_sleb128(string, cursor, &arr[i]); + if (read_size == 0) { + break; + } + cursor += read_size; + } + + U64 bytes_read = 0; + if (i == count) { + *arr_out = arr; + bytes_read = cursor - off; + } else { + temp_end(temp); + *arr_out = 0; + } + + return bytes_read; +} + +internal DW_SectionKind +dw_section_kind_from_string(String8 string) +{ + DW_SectionKind s = DW_Section_Null; +#define X(_K,_L,_M,_W) \ +if (str8_match_lit(_L, string, 0)) { s = DW_Section_##_K; } \ +if (str8_match_lit(_M, string, 0)) { s = DW_Section_##_K; } + DW_SectionKind_XList +#undef X + return s; +} + +internal DW_SectionKind +dw_section_dwo_kind_from_string(String8 string) +{ + DW_SectionKind s = DW_Section_Null; +#define X(_K,_L,_M,_W) if (str8_match_lit(_W, string, 0)) { s = DW_Section_##_K; } + DW_SectionKind_XList +#undef X + return s; +} + +internal Rng1U64List +dw_unit_ranges_from_data(Arena *arena, String8 data) +{ + Rng1U64List result = {0}; + + for (U64 cursor = 0; cursor < data.size; ) { + U64 start = cursor; + + // read unit size + U64 size; + U64 size_size = str8_deserial_read_dwarf_packed_size(data, cursor, &size); + if (size_size == 0) { break; } + cursor += size_size; + + // is unit size valid? + if (cursor + size > data.size) { break; } + cursor += size; + + // push unit range + if (size > 0) { + rng1u64_list_push(arena, &result, rng_1u64(start, cursor)); + } + } + + return result; +} + +internal Rng1U64Array +dw_unit_ranges_from_data_arr(Arena *arena, String8 data) +{ + Temp scratch = scratch_begin(&arena, 1); + Rng1U64List list = dw_unit_ranges_from_data(scratch.arena, data); + Rng1U64Array arr = rng1u64_array_from_list(arena, &list); + scratch_end(scratch); + return arr; +} + +internal U64 +dw_read_list_unit_header_addr(String8 unit_data, DW_ListUnit *lu_out) +{ + U64 header_size = 0; + + U64 unit_length = 0; + U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, 0, &unit_length); + + if (unit_length_size) { + DW_Version version = DW_Version_Null; + U64 version_size = str8_deserial_read_struct(unit_data, unit_length_size, &version); + + if (version_size) { + if (version >= DW_Version_5) { + U8 address_size = 0; + U64 address_size_size = str8_deserial_read_struct(unit_data, + unit_length_size + version_size, + &address_size); + + if (address_size_size && address_size) { + U8 segment_selector_size = 0; + U64 segment_selector_size_size = str8_deserial_read_struct(unit_data, + unit_length_size + version_size + address_size_size, + &segment_selector_size); + if (segment_selector_size_size) { + header_size = unit_length_size + version_size + address_size_size + segment_selector_size_size; + + lu_out->version = version; + lu_out->segment_selector_size = segment_selector_size; + lu_out->address_size = address_size; + lu_out->entry_size = segment_selector_size + address_size; + lu_out->entries = str8_skip(unit_data, header_size); + } + } + } + } + } + + return header_size; +} + +internal U64 +dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out) +{ + U64 header_size = 0; + + U32 first_four_bytes = 0; + if (str8_deserial_read_struct(unit_data, 0, &first_four_bytes) != sizeof(first_four_bytes)) { goto exit; } + DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit; + + U64 unit_length = 0; + U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, 0, &unit_length); + + if (unit_length_size) { + DW_Version version = DW_Version_Null; + U64 version_size = str8_deserial_read_struct(unit_data, unit_length_size, &version); + + if (version >= DW_Version_5) { + U16 padding = 0; + U64 padding_size = str8_deserial_read_struct(unit_data, unit_length_size + version_size, &padding); + + if (padding_size && padding == 0) { + header_size = unit_length_size + version_size + padding_size; + + lu_out->version = version; + lu_out->address_size = 0; + lu_out->segment_selector_size = 0; + lu_out->entry_size = dw_size_from_format(format); + lu_out->entries = str8_skip(unit_data, header_size); + } + } + } + + exit:; + return header_size; +} + +internal U64 +dw_read_list_unit_header_list(String8 unit_data, DW_ListUnit *lu_out) +{ + U64 header_size = 0; + + U32 first_four_bytes = 0; + if (str8_deserial_read_struct(unit_data, 0, &first_four_bytes) != sizeof(first_four_bytes)) { goto exit; } + DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit; + + U64 unit_length = 0; + U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, 0, &unit_length); + + if (unit_length_size) { + DW_Version version = DW_Version_Null; + U64 version_size = str8_deserial_read_struct(unit_data, unit_length_size, &version); + + if (version >= DW_Version_5) { + U8 address_size = 0; + U64 address_size_size = str8_deserial_read_struct(unit_data, unit_length_size + version_size, &address_size); + + if (address_size_size && address_size > 0) { + U8 segment_selector_size = 0; + U64 segment_selector_size_size = str8_deserial_read_struct(unit_data, unit_length_size + version_size + address_size_size, &segment_selector_size); + + if (segment_selector_size_size) { + U32 offset_entry_count = 0; + U64 offset_entry_count_size = str8_deserial_read_struct(unit_data, unit_length_size + version_size + address_size_size + segment_selector_size, &offset_entry_count); + + if (offset_entry_count_size) { + header_size = unit_length_size + version_size + address_size_size + segment_selector_size_size + offset_entry_count_size; + + lu_out->version = version; + lu_out->address_size = address_size; + lu_out->segment_selector_size = segment_selector_size; + lu_out->entry_size = dw_size_from_format(format); + lu_out->entries = str8_skip(unit_data, header_size); + } + } + } + } + } + + exit:; + return header_size; +} + +internal DW_ListUnitInput +dw_list_unit_input_from_input(Arena *arena, DW_Raw *input) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_ListUnitInput result = {0}; + + DW_Section debug_addr = input->sec[DW_Section_Addr]; + { + String8 data = debug_addr.data; + Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, data); + + result.addr_ranges = rng1u64_array_from_list(arena, &unit_ranges); + result.addr_count = unit_ranges.count; + result.addrs = push_array(arena, DW_ListUnit, unit_ranges.count); + + for (U64 unit_idx = 0; unit_idx < result.addr_ranges.count; ++unit_idx) { + String8 unit_data = str8_substr(debug_addr.data, result.addr_ranges.v[unit_idx]); + dw_read_list_unit_header_addr(unit_data, &result.addrs[unit_idx]); + } + } + + DW_Section debug_str_offsets = input->sec[DW_Section_StrOffsets]; + { + String8 data = debug_str_offsets.data; + Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, data); + + result.str_offset_ranges = rng1u64_array_from_list(arena, &unit_ranges); + result.str_offset_count = unit_ranges.count; + result.str_offsets = push_array(arena, DW_ListUnit, unit_ranges.count); + + for (U64 unit_idx = 0; unit_idx < result.str_offset_ranges.count; ++unit_idx) { + String8 unit_data = str8_substr(data, result.str_offset_ranges.v[unit_idx]); + dw_read_list_unit_header_str_offsets(unit_data, &result.str_offsets[unit_idx]); + } + } + + DW_Section debug_rnglists = input->sec[DW_Section_RngLists]; + { + String8 data = debug_rnglists.data; + Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, data); + + result.rnglist_ranges = rng1u64_array_from_list(arena, &unit_ranges); + result.rnglist_count = unit_ranges.count; + result.rnglists = push_array(arena, DW_ListUnit, unit_ranges.count); + + for (U64 unit_idx = 0; unit_idx < result.rnglist_ranges.count; ++unit_idx) { + String8 unit_data = str8_substr(data, result.rnglist_ranges.v[unit_idx]); + dw_read_list_unit_header_list(unit_data, &result.rnglists[unit_idx]); + } + } + + DW_Section debug_loclists = input->sec[DW_Section_LocLists]; + { + String8 data = debug_loclists.data; + Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, data); + + result.loclist_ranges = rng1u64_array_from_list(arena, &unit_ranges); + result.loclist_count = unit_ranges.count; + result.loclists = push_array(arena, DW_ListUnit, unit_ranges.count); + + for (U64 unit_idx = 0; unit_idx < result.loclist_ranges.count; ++unit_idx) { + String8 unit_data = str8_substr(data, result.loclist_ranges.v[unit_idx]); + dw_read_list_unit_header_list(unit_data, &result.loclists[unit_idx]); + } + } + + scratch_end(scratch); + return result; +} + +internal U64 +dw_offset_from_list_unit(DW_ListUnit *lu, U64 index) +{ + U64 offset; + U64 entry_off = index * lu->entry_size; + if (entry_off + lu->entry_size <= lu->entries.size) { + offset = 0; + MemoryCopy(&offset, lu->entries.str + entry_off, lu->entry_size); + } else { + offset = max_U64; + } + return offset; +} + +internal U64 +dw_addr_from_list_unit(DW_ListUnit *lu, U64 index) +{ + U64 seg = 0; + U64 addr = max_U64; + U64 entry_count = lu->entries.size / lu->entry_size; + if (index < entry_count) { + U64 seg_off = lu->entry_size * index; + U64 addr_off = seg_off + lu->segment_selector_size; + MemoryCopy(&seg, lu->entries.str + seg_off, lu->segment_selector_size); + MemoryCopy(&addr, lu->entries.str + addr_off, lu->address_size); + // TODO: segment-based addressing + AssertAlways(seg == 0); + } else { + Assert(!"out of bounds index"); + } + return addr; +} + +internal U64 +dw_read_abbrev_tag(String8 data, U64 offset, DW_Abbrev *out_abbrev) +{ + U64 total_bytes_read = 0; + U64 cursor = offset; + + // read tag ID and kind + U64 id = 0; + TryRead(str8_deserial_read_uleb128(data, cursor, &id), cursor, exit); + + // is this null terminator? + if (id == 0) { + total_bytes_read = cursor - offset; + MemoryZeroStruct(out_abbrev); + goto exit; + } + + U64 kind = 0; + TryRead(str8_deserial_read_uleb128(data, cursor, &kind), cursor, exit); + + // read child flag + U8 has_children = 0; + if (id != 0) { + TryRead(str8_deserial_read_struct(data, cursor, &has_children), cursor, exit); + } + + if (out_abbrev != 0) { + DW_Abbrev abbrev = { .kind = DW_Abbrev_Tag, .sub_kind = kind, .id = id}; + if (has_children) { + abbrev.flags |= DW_AbbrevFlag_HasChildren; + } + *out_abbrev = abbrev; + } + + total_bytes_read = cursor - offset; + exit:; + return total_bytes_read; +} + +internal U64 +dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev) +{ + U64 total_bytes_read = 0; + U64 cursor = offset; + + // read id and kind + U64 id, kind; + TryRead(str8_deserial_read_uleb128(data, cursor, &id), cursor, exit); + TryRead(str8_deserial_read_uleb128(data, cursor, &kind), cursor, exit); + + // read implicit const + S64 implicit_const = 0; + if (kind == DW_Form_ImplicitConst) { + TryRead(str8_deserial_read_sleb128(data, cursor, &implicit_const), cursor, exit); + } + + if (out_abbrev != 0) { + DW_Abbrev abbrev = { .kind = DW_Abbrev_Attrib, .sub_kind = kind, .id = id }; + if (kind == DW_Form_ImplicitConst) { + abbrev.flags |= DW_AbbrevFlag_HasImplicitConst; + abbrev.implicit_const = implicit_const; + } + *out_abbrev = abbrev; + } + + total_bytes_read = cursor - offset; + exit:; + return total_bytes_read; +} + +internal DW_AbbrevTable +dw_make_abbrev_table(Arena *arena, String8 abbrev_data, U64 abbrev_base) +{ + Temp temp = temp_begin(arena); + DW_AbbrevTable table = {0}; + B32 failed_to_make = 1; + + // count abbrev tags + for (U64 cursor = abbrev_base; cursor < abbrev_data.size; table.count += 1) { + DW_Abbrev tag; + TryRead(dw_read_abbrev_tag(abbrev_data, cursor, &tag), cursor, exit); + if (tag.id == 0) { break; } + + for (; cursor < abbrev_data.size; ) { + DW_Abbrev attrib; + TryRead(dw_read_abbrev_attrib(abbrev_data, cursor, &attrib), cursor, exit); + if(attrib.id == 0) { break; } + } + } + + // alloc entries + table.entries = push_array(arena, DW_AbbrevTableEntry, table.count); + table.count = 0; + + // fill out the table + for (U64 cursor = abbrev_base; cursor < abbrev_data.size;) { + U64 tag_abbrev_off = cursor; + + DW_Abbrev tag = {0}; + TryRead(dw_read_abbrev_tag(abbrev_data, cursor, &tag), cursor, exit); + if (tag.id == 0) { break; } + + // push new entry + table.entries[table.count].id = tag.id; + table.entries[table.count].off = tag_abbrev_off; + table.count += 1; + + for (; cursor < abbrev_data.size ;) { + DW_Abbrev attrib = {0}; + TryRead(dw_read_abbrev_attrib(abbrev_data, cursor, &attrib), cursor, exit); + if (attrib.id == 0) { break; } + } + } + + failed_to_make = 0; + exit:; + if (failed_to_make) { + MemoryZeroStruct(&table); + temp_end(temp); + } + return table; +} + +internal U64 +dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id) +{ + U64 abbrev_offset = max_U64; + if (table.count > 0) { + for (S64 l = 0, r = (S64)table.count - 1; l <= r; ) { + S64 m = l + (r - l) / 2; + if (abbrev_id > table.entries[m].id) { + l = m + 1; + } else if (abbrev_id < table.entries[m].id) { + r = m - 1; + } else { + abbrev_offset = table.entries[m].off; + break; + } + } + } + return abbrev_offset; +} + +internal B32 +dw_read_form(String8 data, + DW_Version version, + DW_Format unit_format, + U64 address_size, + DW_FormKind form_kind, + S64 implicit_const, + DW_Form *form_out, + U64 *bytes_read_out) +{ + B32 is_ok = 0; + U64 cursor = 0; + DW_Form form = {0}; + switch (form_kind) { + case DW_Form_Null: break; + case DW_Form_Addr: { + TryRead(str8_deserial_read_block(data, cursor, address_size, &form.addr), cursor, exit); + } break; + case DW_Form_Block2: { + U16 size = 0; + TryRead(str8_deserial_read_struct(data, cursor, &size), cursor, exit); + TryRead(str8_deserial_read_block(data, cursor, size, &form.block), cursor, exit); + } break; + case DW_Form_Block4: { + U32 size = 0; + TryRead(str8_deserial_read_struct(data, cursor, &size), cursor, exit); + TryRead(str8_deserial_read_block(data, cursor + cursor, size, &form.block), cursor, exit); + } break; + case DW_Form_Data2: { + TryRead(str8_deserial_read_block(data, cursor, sizeof(U16), &form.data), cursor, exit); + } break; + case DW_Form_Data4: { + TryRead(str8_deserial_read_block(data, cursor, sizeof(U32), &form.data), cursor, exit); + } break; + case DW_Form_Data8: { + TryRead(str8_deserial_read_block(data, cursor, sizeof(U64), &form.data), cursor, exit); + } break; + case DW_Form_String: { + TryRead(str8_deserial_read_cstr(data, cursor, &form.string), cursor, exit); + } break; + case DW_Form_Block: { + U64 size = 0; + TryRead(str8_deserial_read_uleb128(data, cursor, &size), cursor, exit); + TryRead(str8_deserial_read_block(data, cursor, size, &form.block), cursor, exit); + } break; + case DW_Form_Block1: { + U8 size = 0; + TryRead(str8_deserial_read_struct(data, cursor, &size), cursor, exit); + TryRead(str8_deserial_read_block(data, cursor, size, &form.block), cursor, exit); + } break; + case DW_Form_Data1: { + TryRead(str8_deserial_read_block(data, cursor, sizeof(U8), &form.data), cursor, exit); + } break; + case DW_Form_Flag: { + TryRead(str8_deserial_read_struct(data, cursor, &form.flag), cursor, exit); + } break; + case DW_Form_SData: { + TryRead(str8_deserial_read_sleb128(data, cursor, &form.sdata), cursor, exit); + } break; + case DW_Form_UData: { + TryRead(str8_deserial_read_uleb128(data, cursor, &form.udata), cursor, exit); + } break; + case DW_Form_RefAddr: { + if (version < DW_Version_3) { + TryRead(str8_deserial_read(data, cursor, &form.ref, address_size, address_size), cursor, exit); + } else { + TryRead(str8_deserial_read_dwarf_uint(data, cursor, unit_format, &form.ref), cursor, exit); + } + } break; + case DW_Form_GNU_RefAlt: { + TryRead(str8_deserial_read_dwarf_uint(data, cursor, unit_format, &form.ref), cursor, exit); + } break; + case DW_Form_Ref1: { + TryRead(str8_deserial_read(data, cursor, &form.ref, 1, 1), cursor, exit); + } break; + case DW_Form_Ref2: { + TryRead(str8_deserial_read(data, cursor, &form.ref, 2, 2), cursor, exit); + } break; + case DW_Form_Ref4: { + TryRead(str8_deserial_read(data, cursor, &form.ref, 4, 4), cursor, exit); + } break; + case DW_Form_Ref8: { + TryRead(str8_deserial_read(data, cursor, &form.ref, 8, 8), cursor, exit); + } break; + case DW_Form_RefUData: { + TryRead(str8_deserial_read_uleb128(data, cursor, &form.ref), cursor, exit); + } break; + case DW_Form_SecOffset: + case DW_Form_LineStrp: + case DW_Form_GNU_StrpAlt: + case DW_Form_Strp: { + TryRead(str8_deserial_read_dwarf_uint(data, cursor, unit_format, &form.sec_offset), cursor, exit); + } break; + case DW_Form_ExprLoc: { + U64 expr_size = 0; + TryRead(str8_deserial_read_uleb128(data, cursor, &expr_size), cursor, exit); + TryRead(str8_deserial_read_block(data, cursor, expr_size, &form.exprloc), cursor, exit); + } break; + case DW_Form_FlagPresent: { + form.flag = 1; + } break; + case DW_Form_RefSig8: { + //U64 ref = 0; + //cursor = str8_deserial_read_struct(data, cursor, &ref); + NotImplemented; + } break; + case DW_Form_Addrx: + case DW_Form_RngListx: + case DW_Form_Strx: { + TryRead(str8_deserial_read_uleb128(data, cursor, &form.xval), cursor, exit); + } break; + case DW_Form_RefSup4: { + //U32 ref_sup4 = 0; + //cursor = str8_deserial_read_struct(data, cursor, &ref_sup4); + NotImplemented; + } break; + case DW_Form_StrpSup: { + TryRead(str8_deserial_read_dwarf_uint(data, cursor, unit_format, &form.strp_sup), cursor, exit); + } break; + case DW_Form_Data16: { + cursor = str8_deserial_read_block(data, cursor, 16, &form.data); + } break; + case DW_Form_ImplicitConst: { + // Special case. + // Unlike other forms that have their values stored in the .debug_info section, + // This one defines it's value in the .debug_abbrev section. + form.implicit_const = implicit_const; + } break; + case DW_Form_LocListx: { + TryRead(str8_deserial_read_uleb128(data, cursor, &form.xval), cursor, exit); + } break; + case DW_Form_RefSup8: { + NotImplemented; + } break; + case DW_Form_Strx1: { + TryRead(str8_deserial_read(data, cursor, &form.xval, 1, 1), cursor, exit); + } break; + case DW_Form_Strx2: { + TryRead(str8_deserial_read(data, cursor, &form.xval, 2, 2), cursor, exit); + } break; + case DW_Form_Strx3: { + TryRead(str8_deserial_read(data, cursor, &form.xval, 3, 3), cursor, exit); + } break; + case DW_Form_Strx4: { + TryRead(str8_deserial_read(data, cursor, &form.xval, 4, 4), cursor, exit); + } break; + case DW_Form_Addrx1: { + TryRead(str8_deserial_read(data, cursor, &form.xval, 1, 1), cursor, exit); + } break; + case DW_Form_Addrx2: { + TryRead(str8_deserial_read(data, cursor, &form.xval, 2, 2), cursor, exit); + } break; + case DW_Form_Addrx3: { + TryRead(str8_deserial_read(data, cursor, &form.xval, 3, 3), cursor, exit); + } break; + case DW_Form_Addrx4: { + TryRead(str8_deserial_read(data, cursor, &form.xval, 4, 4), cursor, exit); + } break; + default: InvalidPath; break; + } + + if (form_out) { + form.kind = form_kind; + *form_out = form; + } + if (bytes_read_out) { + *bytes_read_out = cursor; + } + + is_ok = 1; + exit:; + Assert(is_ok); + return is_ok; +} + +internal U64 +dw_read_tag(Arena *arena, + DW_Raw *input, + DW_AbbrevTable abbrev_table, + DW_Version version, + DW_Format format, + U64 address_size, + Rng1U64 cu_info_range, + U64 tag_info_off, + DW_Tag *tag_out) +{ + U64 bytes_read = 0; + + String8 info_data = input->sec[DW_Section_Info].data; + String8 abbrev_data = input->sec[DW_Section_Abbrev].data; + + String8 tag_data = str8_substr(info_data, cu_info_range); + U64 tag_cursor = tag_info_off - cu_info_range.min; + + // read tag abbrev id + U64 tag_abbrev_id = 0; + TryRead(str8_deserial_read_uleb128(tag_data, tag_cursor, &tag_abbrev_id), tag_cursor, exit); + + B32 has_children = 0; + DW_TagKind tag_kind = DW_TagKind_Null; + DW_AttribList attribs = {0}; + if (tag_abbrev_id > 0) { + // map abbrev id -> .debug_abbrev offset + U64 abbrev_cursor = dw_abbrev_offset_from_abbrev_id(abbrev_table, tag_abbrev_id); + if (abbrev_cursor >= abbrev_data.size) { log_user_errorf("failed to find abbrev id 0x%I64x for tag 0x%I64x", tag_abbrev_id, tag_info_off); goto exit; } + + // read tag abbrev + DW_Abbrev tag_abbrev = {0}; + TryRead(dw_read_abbrev_tag(abbrev_data, abbrev_cursor, &tag_abbrev), abbrev_cursor, exit); + + has_children = !!(tag_abbrev.flags & DW_AbbrevFlag_HasChildren); + tag_kind = (DW_TagKind)tag_abbrev.sub_kind; + + // read attribs + for (; tag_cursor < tag_data.size && abbrev_cursor < abbrev_data.size; ) { + U64 attrib_tag_cursor = tag_cursor; + U64 attrib_abbrev_off = abbrev_cursor; + + // read attrib abbrev + DW_Abbrev attrib_abbrev = {0}; + TryRead(dw_read_abbrev_attrib(abbrev_data, abbrev_cursor, &attrib_abbrev), abbrev_cursor, exit); + + DW_AttribKind attrib_kind = (DW_AttribKind)attrib_abbrev.id; + DW_FormKind form_kind = (DW_FormKind)attrib_abbrev.sub_kind; + + // is this closing attrib? + if (attrib_kind == DW_AttribKind_Null) { break; } + + // special case, allows producer to embed form in .debug_info + if (form_kind == DW_Form_Indirect) { + TryRead(str8_deserial_read_uleb128(tag_data, tag_cursor, &form_kind), tag_cursor, exit); + } + + // read form value + DW_Form form = {0}; + U64 form_size = 0; + if (!dw_read_form(str8_skip(tag_data, tag_cursor), version, format, address_size, form_kind, attrib_abbrev.implicit_const, &form, &form_size)) { + goto exit; + } + tag_cursor += form_size; + + // fill out node + DW_AttribNode *attrib_n = push_array(arena, DW_AttribNode, 1); + attrib_n->v.info_off = cu_info_range.min + attrib_tag_cursor; + attrib_n->v.abbrev_off = attrib_abbrev_off; + attrib_n->v.abbrev_id = attrib_abbrev.id; + attrib_n->v.attrib_kind = attrib_kind; + attrib_n->v.form = form; + + // push node to list + SLLQueuePush(attribs.first, attribs.last, attrib_n); + attribs.count += 1; + } + } + + // fill out tag + tag_out->abbrev_id = tag_abbrev_id; + tag_out->has_children = has_children; + tag_out->kind = tag_kind; + tag_out->attribs = attribs; + tag_out->info_off = tag_info_off; + + bytes_read = tag_cursor - (tag_info_off - cu_info_range.min); + exit:; + return bytes_read; +} + +internal U64 +dw_read_tag_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out) +{ + return dw_read_tag(arena, + input, + cu->abbrev_table, + cu->version, + cu->format, + cu->address_size, + cu->info_range, + info_off, + tag_out); +} + +internal B32 +dw_try_u64_from_const_value(U64 type_byte_size, DW_ATE type_encoding, String8 const_value, U64 *value_out) +{ + B32 is_parsed = 0; + if (const_value.size <= type_byte_size) { + U64 value_size = Min(type_byte_size, const_value.size); + if (value_size <= sizeof(*value_out)) { + MemoryZeroStruct(value_out); + MemoryCopy(value_out, const_value.str, value_size); + if (type_encoding == DW_ATE_Signed || type_encoding == DW_ATE_SignedChar) { + *value_out = extend_sign64(*value_out, value_size); + } + is_parsed = 1; + } else { + Assert(!"out value overflow"); + } + } + return is_parsed; +} + +internal U64 +dw_u64_from_const_value(String8 const_value) +{ + U64 result = 0; + B32 is_converted = dw_try_u64_from_const_value(sizeof(U64), DW_ATE_Unsigned, const_value, &result); + Assert(is_converted); // TODO: error handling + return result; +} + +internal U64 +dw_interp_sec_offset(DW_Form form) +{ + U64 sec_offset = 0; + if (form.kind == DW_Form_SecOffset) { + sec_offset = form.sec_offset; + } else if (form.kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + return sec_offset; +} + +internal String8 +dw_interp_exprloc(DW_Form form) +{ + String8 expr = {0}; + if (form.kind == DW_Form_ExprLoc) { + expr = form.exprloc; + } else if (form.kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + return expr; +} + +internal U128 +dw_interp_const_u128(DW_Form form) +{ + AssertAlways(form.data.size <= sizeof(U128)); + U128 result = {0}; + MemoryCopy(&result.u64[0], form.data.str, form.data.size); + return result; +} + +internal U64 +dw_interp_const64(U64 type_byte_size, DW_ATE type_encoding, DW_Form form) +{ + U64 result = max_U64; + if (form.kind == DW_Form_Data1 || form.kind == DW_Form_Data2 || form.kind == DW_Form_Data4 || form.kind == DW_Form_Data8 || form.kind == DW_Form_Data16) { + if (form.data.size <= sizeof(result)) { + if (!dw_try_u64_from_const_value(type_byte_size, type_encoding, form.data, &result)) { + Assert(!"unable to decode data"); + } + } else { + Assert(!"unable to cast U128 to U64"); + } + } else if (form.kind == DW_Form_UData) { + result = form.udata; + } else if (form.kind == DW_Form_SData) { + result = form.sdata; + } else if (form.kind == DW_Form_ImplicitConst) { + result = form.implicit_const; + } else if (form.kind == DW_Form_Null) { + // skip + } else { + AssertAlways(!"unexpected form"); + } + return result; +} + +internal U64 +dw_interp_const_u64(DW_Form form) +{ + return dw_interp_const64(sizeof(U64), DW_ATE_Unsigned, form); +} + +internal U32 +dw_interp_const_u32(DW_Form form) +{ + U64 const64 = dw_interp_const_u64(form); + U32 const32 = safe_cast_u32(const64); + return const32; +} + +internal S64 +dw_interp_const_s64(DW_Form form) +{ + U64 const_u64 = dw_interp_const_u64(form); + S64 const_s64 = (S64)const_u64; + return const_s64; +} + +internal S32 +dw_interp_const_s32(DW_Form form) +{ + U32 const_u32 = dw_interp_const_u32(form); + S32 const_s32 = (S32)const_u32; + return const_s32; +} + +internal U64 +dw_interp_address(U64 address_size, U64 base_addr, DW_ListUnit *addr_lu, DW_Form form) +{ + U64 address = 0; + if (form.kind == DW_Form_Addr) { + if (!dw_try_u64_from_const_value(address_size, DW_ATE_Address, form.addr, &address)) { + AssertAlways(!"unable to decode address"); + } + } else if (form.kind == DW_Form_Addrx || form.kind == DW_Form_Addrx1 || form.kind == DW_Form_Addrx2 || + form.kind == DW_Form_Addrx3 || form.kind == DW_Form_Addrx4) { + address = dw_addr_from_list_unit(addr_lu, form.xval); + } else if (form.kind == DW_Form_SecOffset) { + if (addr_lu->segment_selector_size > 0) { + AssertAlways(!"TODO: support for segmented address space"); + } + if (form.sec_offset + addr_lu->segment_selector_size + addr_lu->address_size <= addr_lu->entries.size) { + MemoryCopy(&address, addr_lu->entries.str + form.sec_offset, addr_lu->address_size); + } else { + Assert(!"out of bounds .debug_addr offset"); + } + } else if (form.kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + return address; +} + +internal String8 +dw_interp_block(DW_Raw *input, DW_CompUnit *cu, DW_Form form) +{ + NotImplemented; + return str8_zero(); +} + +internal String8 +dw_interp_string(DW_Raw *input, + DW_Format unit_format, + DW_ListUnit *str_offsets, + DW_Form form) +{ + String8 string = {0}; + if (form.kind == DW_Form_String) { + string = form.string; + } else if (form.kind == DW_Form_Strp) { + U64 bytes_read = str8_deserial_read_cstr(input->sec[DW_Section_Str].data, form.sec_offset, &string); + Assert(bytes_read > 0); + } else if (form.kind == DW_Form_LineStrp) { + U64 bytes_read = str8_deserial_read_cstr(input->sec[DW_Section_LineStr].data, form.sec_offset, &string); + Assert(bytes_read > 0); + } else if (form.kind == DW_Form_StrpSup) { + U64 bytes_read = str8_deserial_read_cstr(input->sec[DW_Section_Str].data, form.strp_sup, &string); + Assert(bytes_read > 0); + } else if (form.kind == DW_Form_Strx || form.kind == DW_Form_Strx1 || + form.kind == DW_Form_Strx2 || form.kind == DW_Form_Strx3 || + form.kind == DW_Form_Strx4) { + U64 sec_offset = dw_offset_from_list_unit(str_offsets, form.xval); + if (sec_offset < input->sec[DW_Section_Str].data.size) { + U64 bytes_read = str8_deserial_read_cstr(input->sec[DW_Section_Str].data, sec_offset, &string); + Assert(bytes_read > 0); + } else { + AssertAlways(!"unable to translate index to offset"); + } + } else if (form.kind == DW_Form_GNU_StrpAlt) { + NotImplemented; + } else if (form.kind == DW_Form_GNU_StrIndex) { + NotImplemented; + } else if (form.kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + return string; +} + +internal String8 +dw_interp_line_ptr(DW_Raw *input, DW_Form form) +{ + String8 result = {0}; + if (form.kind == DW_Form_SecOffset) { + result = str8_skip(input->sec[DW_Section_Line].data, form.sec_offset); + } else if (form.kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + return result; +} + +internal DW_LineFile * +dw_interp_file(DW_LineVM *line_vm, DW_Form form) +{ + U64 file_idx = dw_interp_const_u64(form); + DW_LineFile *result = dw_line_vm_find_file(line_vm, file_idx); + return result; +} + +internal DW_Reference +dw_interp_ref(DW_Raw *input, DW_CompUnit *cu, DW_Form form) +{ + DW_Reference ref = {0}; + if (form.kind == DW_Form_Ref1 || form.kind == DW_Form_Ref2 || + form.kind == DW_Form_Ref4 || form.kind == DW_Form_Ref8 || + form.kind == DW_Form_RefUData) { + ref.cu = cu; + ref.info_off = cu->info_range.min + form.ref; + } else if (form.kind == DW_Form_RefAddr) { + NotImplemented; + } else if (form.kind == DW_Form_RefSig8) { + NotImplemented; + } else if (form.kind == DW_Form_RefSup4 || form.kind == DW_Form_RefSup8) { + NotImplemented; + } else if (form.kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + return ref; +} + +internal DW_LocList +dw_interp_loclist(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form) +{ + DW_LocList loclist = {0}; + + if (cu->version < DW_Version_5) { + if (form.kind == DW_Form_SecOffset) { + U64 sec_offset = max_U64; + if (form.kind == DW_Form_SecOffset) { + sec_offset = form.sec_offset; + } else if (form.kind == DW_Form_Data8 || form.kind == DW_Form_Data4 || + form.kind == DW_Form_Data2 || form.kind == DW_Form_Data1) { + if (!dw_try_u64_from_const_value(form.data.size, DW_ATE_Unsigned, form.data, &sec_offset)) { + Assert(!"unable to extract section offset"); + } + } else if (form.kind == DW_Form_Null) { + Assert(!"unexpected form"); + } + + String8 sec = str8_skip(input->sec[DW_Section_Loc].data, sec_offset); + U64 base_addr = cu->low_pc; + U64 base_sel = DW_SentinelFromSize(cu->address_size); + for (U64 cursor = 0; cursor < sec.size; ) { + U64 range_min = 0; + U64 range_min_off = cursor; + U64 range_min_size = str8_deserial_read(sec, range_min_off, &range_min, cu->address_size, cu->address_size); + if (range_min_size == 0) { + break; + } + U64 range_max = 0; + U64 range_max_off = cursor + cu->address_size; + U64 range_max_size = str8_deserial_read(sec, range_max_off, &range_max, cu->address_size, cu->address_size); + if (range_max_size == 0) { + break; + } + cursor += cu->address_size * 2; + + // series terminator + if (range_min == 0 && range_max == 0) { + break; + } + // set new base address + else if (range_min == base_sel) { + base_addr = range_max; + } + // location + else { + U16 expr_size = 0; + U64 expr_size_size = str8_deserial_read_struct(sec, cursor, &expr_size); + if (expr_size_size == 0) { + Assert(!"unable to read expression size"); + break; + } + cursor += expr_size_size; + + Assert(cursor + expr_size <= sec.size); + Rng1U64 expr_range = rng_1u64(cursor, ClampTop(cursor + expr_size, sec.size)); + + DW_LocNode *loc_n = push_array(arena, DW_LocNode, 1); + loc_n->v.range = rng_1u64(base_addr + range_min, base_addr + range_max); + loc_n->v.expr = str8_substr(sec, expr_range); + + SLLQueuePush(loclist.first, loclist.last, loc_n); + ++loclist.count; + + // advance past expression + cursor += expr_size; + } + } + } else if (form.kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + } else { + DW_Version version = DW_Version_Null; + String8 raw_lle = {0}; + if (form.kind == DW_Form_SecOffset) { + // offset is from beginning of the section + U64 sec_offset = form.sec_offset; + raw_lle = str8_skip(input->sec[DW_Section_LocLists].data, sec_offset); + } else if (form.kind == DW_Form_LocListx) { + // offset is from beginning of the entries + U64 entries_off = dw_offset_from_list_unit(cu->loclists_lu, form.xval); + raw_lle = str8_skip(cu->loclists_lu->entries, entries_off); + version = cu->loclists_lu->version; + } else if (form.kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + + for (U64 cursor = 0, keep_parsing = 1, base_addr = cu->low_pc; + cursor < raw_lle.size && keep_parsing; ) { + DW_LLE kind = DW_LLE_EndOfList; + cursor += str8_deserial_read_struct(raw_lle, cursor, &kind); + + Rng1U64 range = {0}; + switch (kind) { + default: + Assert(!"unknown kind"); + case DW_LLE_EndOfList: { + keep_parsing = 0; + } break; + case DW_LLE_BaseAddressx: { + if (!cu->addr_lu) { + keep_parsing = 0; + break; + } + + U64 addrx = 0; + U64 addrx_size = str8_deserial_read_uleb128(raw_lle, cursor, &addrx); + if (addrx_size == 0) { + keep_parsing = 0; + break; + } + + U64 base_addr_new = dw_addr_from_list_unit(cu->addr_lu, addrx); + if (base_addr_new == max_U64) { + InvalidPath; + break; + } + + base_addr = base_addr_new; + cursor += addrx_size; + } break; + case DW_LLE_StartxEndx: { + U64 start_addrx = 0; + U64 start_addrx_size = str8_deserial_read_uleb128(raw_lle, cursor, &start_addrx); + if (start_addrx_size == 0) { + keep_parsing = 0; + break; + } + U64 end_addrx = 0; + U64 end_addrx_size = str8_deserial_read_uleb128(raw_lle, cursor + start_addrx_size, &end_addrx); + if (end_addrx_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_addrx_size; + cursor += end_addrx_size; + + U64 start = dw_addr_from_list_unit(cu->addr_lu, start_addrx); + U64 end = dw_addr_from_list_unit(cu->addr_lu, end_addrx); + Assert(start != max_U64); + Assert(end != max_U64); + + range = rng_1u64(start, end); + } break; + case DW_LLE_StartxLength: { + U64 start_addrx = 0; + U64 start_addrx_size = str8_deserial_read_uleb128(raw_lle, cursor, &start_addrx); + if (start_addrx_size == 0) { + keep_parsing = 0; + break; + } + + // parse pre-standard & standard length + U64 length_off = cursor + start_addrx_size; + U64 length = 0; + U64 length_size = str8_deserial_read_uleb128(raw_lle, length_off, &length); + if (length_size == 0) { + keep_parsing = 0; + break; + } + + cursor += start_addrx_size; + cursor += length_size; + + if (cu->addr_lu) { + U64 start = dw_addr_from_list_unit(cu->addr_lu, start_addrx); + Assert(start < max_U64); + + range = rng_1u64(start, start + length); + } else { + Assert(!".debug_addr section is missing -- unable to interpret address index"); + } + } break; + case DW_LLE_OffsetPair: { + U64 start = 0; + U64 start_size = str8_deserial_read_uleb128(raw_lle, cursor, &start); + if (start_size == 0) { + keep_parsing = 0; + break; + } + U64 end = 0; + U64 end_size = str8_deserial_read_uleb128(raw_lle, cursor + start_size, &end); + if (end_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_size; + cursor += end_size; + + range = rng_1u64(base_addr + start, base_addr + end); + } break; + case DW_LLE_DefaultLocation: { + // no range + int x = 0; + } break; + case DW_LLE_BaseAddress: { + U64 base_addr_size = str8_deserial_read(raw_lle, cursor, &base_addr, cu->address_size, cu->address_size); + if (base_addr_size == 0) { + keep_parsing = 0; + break; + } + cursor += base_addr_size; + } break; + case DW_LLE_StartEnd: { + U64 start = 0; + U64 start_size = str8_deserial_read(raw_lle, cursor, &start, cu->address_size, cu->address_size); + if (start_size == 0) { + keep_parsing = 0; + break; + } + + U64 end = 0; + U64 end_size = str8_deserial_read(raw_lle, cursor + start_size, &end, cu->address_size, cu->address_size); + if (end_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_size; + cursor += end_size; + + range = rng_1u64(start, end); + } break; + case DW_LLE_StartLength: { + U64 start = 0; + U64 start_size = str8_deserial_read(raw_lle, cursor, &start, cu->address_size, cu->address_size); + if (start_size == 0) { + keep_parsing = 0; + break; + } + U64 length = 0; + U64 length_size = str8_deserial_read_uleb128(raw_lle, cursor + start_size, &length); + if (length_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_size; + cursor += length_size; + + range = rng_1u64(start, start + length); + } break; + } + + B32 has_expr = keep_parsing && kind != DW_LLE_BaseAddressx && kind != DW_LLE_BaseAddress; + if (has_expr) { + U64 expr_size = 0; + U64 expr_size_size = str8_deserial_read_uleb128(raw_lle, cursor, &expr_size); + if (expr_size_size == 0) { + keep_parsing = 0; + break; + } + + String8 expr = {0}; + U64 expr_read_size = str8_deserial_read_block(raw_lle, cursor + expr_size_size, expr_size, &expr); + if (expr_read_size != expr_size) { + keep_parsing = 0; + break; + } + + cursor += expr_size_size; + cursor += expr_size; + + DW_LocNode *loc_n = push_array(arena, DW_LocNode, 1); + loc_n->v.range = range; + loc_n->v.expr = expr; + + SLLQueuePush(loclist.first, loclist.last, loc_n); + ++loclist.count; + } + } + } + + return loclist; +} + +internal B32 +dw_interp_flag(DW_Form form) +{ + B32 flag = 0; + if (form.kind == DW_Form_Flag || form.kind == DW_Form_FlagPresent) { + flag = form.flag; + } else if (form.kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + return flag; +} + +internal Rng1U64List +dw_interp_rnglist(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form) +{ + Rng1U64List rnglist = {0}; + + if (cu->version < DW_Version_5) { + // decode section offset + U64 sec_offset = max_U64; + if (form.kind == DW_Form_SecOffset) { + sec_offset = form.sec_offset; + } else if (form.kind == DW_Form_Data8 || form.kind == DW_Form_Data4 || + form.kind == DW_Form_Data2 || form.kind == DW_Form_Data1) { + if (!dw_try_u64_from_const_value(form.data.size, DW_ATE_Unsigned, form.data, &sec_offset)) { + Assert(!"unable to extract section offset"); + } + } else if (form.kind != DW_Form_Null) { + Assert(!"unexpected form"); + } + + String8 sec = str8_skip(input->sec[DW_Section_Ranges].data, sec_offset); + U64 base_addr = cu->low_pc; + U64 base_sel = DW_SentinelFromSize(cu->address_size); + for (U64 cursor = 0; cursor < sec.size; ) { + U64 range_min = 0; + U64 range_min_off = cursor; + U64 range_min_size = str8_deserial_read(sec, range_min_off, &range_min, cu->address_size, cu->address_size); + if (range_min_size == 0) { + break; + } + U64 range_max = 0; + U64 range_max_off = cursor + cu->address_size; + U64 range_max_size = str8_deserial_read(sec, range_max_off, &range_max, cu->address_size, cu->address_size); + if (range_max_size == 0) { + break; + } + cursor += cu->address_size * 2; + + // series terminator + if (range_min == 0 && range_max == 0) { + break; + } + // set new base address + else if (range_min == base_sel) { + base_addr = range_max; + } + // range + else { + Rng1U64 range = rng_1u64(base_addr + range_min, base_addr + range_max); + rng1u64_list_push(arena, &rnglist, range); + } + } + } else { + String8 raw_rle = {0}; + if (form.kind == DW_Form_SecOffset) { + // offset is from beginning of the section + U64 sec_offset = form.sec_offset; + raw_rle = str8_skip(input->sec[DW_Section_RngLists].data, sec_offset); + } else if (form.kind == DW_Form_RngListx) { + // offset is from beginning of the entries + U64 sec_offset = dw_offset_from_list_unit(cu->rnglists_lu, form.xval); + raw_rle = str8_skip(cu->rnglists_lu->entries, sec_offset); + } else if (form.kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + + U64 rle_invalid_value = DW_SentinelFromSize(cu->address_size); + U64 base_addr = cu->low_pc; + for (U64 cursor = 0, keep_parsing = 1; cursor < raw_rle.size && keep_parsing; ) { + DW_RLE kind = DW_RLE_EndOfList; + cursor += str8_deserial_read_struct(raw_rle, cursor, &kind); + + Rng1U64 range = rng_1u64(rle_invalid_value, rle_invalid_value); + switch (kind) { + default: + case DW_RLE_EndOfList: { + keep_parsing = 0; + } break; + case DW_RLE_BaseAddressx: { + U64 addrx = 0; + U64 addrx_size = str8_deserial_read_uleb128(raw_rle, cursor, &addrx); + if (addrx_size == 0) { + keep_parsing = 0; + break; + } + if (cu->addr_lu == 0) { + keep_parsing = 0; + break; + } + U64 base_addr_new = dw_addr_from_list_unit(cu->addr_lu, addrx); + if (base_addr_new < max_U64) { + base_addr = base_addr_new; + cursor += addrx_size; + } else { + keep_parsing = 0; + Assert(!"invalid addrx"); + } + } break; + case DW_RLE_StartxLength: { + U64 start_addrx = 0; + U64 start_addrx_size = str8_deserial_read_uleb128(raw_rle, cursor, &start_addrx); + if (start_addrx_size == 0) { + keep_parsing = 0; + break; + } + U64 length = 0; + U64 length_size = str8_deserial_read_uleb128(raw_rle, cursor + start_addrx_size, &length); + if (length_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_addrx_size; + cursor += length_size; + + if (cu->addr_lu) { + U64 start = dw_addr_from_list_unit(cu->addr_lu, start_addrx); + AssertAlways(start < max_U64); + range = rng_1u64(start, start + length); + } + } break; + case DW_RLE_OffsetPair: { + U64 offset_start, offset_end = 0; + U64 offset_start_size = str8_deserial_read_uleb128(raw_rle, cursor, &offset_start); + if (offset_start_size == 0) { + keep_parsing = 0; + break; + } + U64 offset_end_size = str8_deserial_read_uleb128(raw_rle, cursor + offset_start_size, &offset_end); + if (offset_end_size == 0) { + keep_parsing = 0; + break; + } + cursor += offset_start_size; + cursor += offset_end_size; + + range = rng_1u64(base_addr + offset_start, base_addr + offset_end); + } break; + case DW_RLE_BaseAddress: { + U64 base_addr_size = str8_deserial_read(raw_rle, cursor, &base_addr, cu->address_size, cu->address_size); + if (base_addr_size == 0) { + keep_parsing = 0; + break; + } + cursor += base_addr_size; + } break; + case DW_RLE_StartEnd: { + U64 start = 0, end = 0; + + U64 start_size = str8_deserial_read(raw_rle, cursor, &start, cu->address_size, cu->address_size); + if (start_size == 0) { + keep_parsing = 0; + break; + } + U64 end_size = str8_deserial_read(raw_rle, cursor + start_size, &end, cu->address_size, cu->address_size); + if (end_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_size; + cursor += end_size; + + range = rng_1u64(start, end); + } break; + case DW_RLE_StartLength: { + U64 start = 0, length = 0; + + U64 start_size = str8_deserial_read(raw_rle, cursor, &start, cu->address_size, cu->address_size); + if (start_size == 0) { + keep_parsing = 0; + break; + } + U64 length_size = str8_deserial_read_uleb128(raw_rle, cursor + start_size, &length); + if (length_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_size; + cursor += length_size; + + range = rng_1u64(start, start + length); + } break; + } + + if (range.min != rle_invalid_value) { + rng1u64_list_push(arena, &rnglist, range); + } + } + } + + return rnglist; +} + +internal String8 +dw_interp_secptr(DW_Raw *input, DW_SectionKind section, DW_Form form) +{ + String8 secptr = {0}; + if (form.kind == DW_Form_SecOffset) { + String8 sect = input->sec[section].data; + Rng1U64 range = rng_1u64(form.sec_offset, sect.size); + secptr = str8_substr(sect, range); + } else if (form.kind != DW_Form_Null) { + Assert(!"unexpected form"); + } + return secptr; +} + +internal String8 +dw_interp_addrptr(DW_Raw *input, DW_Form form) +{ + return dw_interp_secptr(input, DW_Section_Addr, form); +} + +internal String8 +dw_interp_str_offsets_ptr(DW_Raw *input, DW_Form form) +{ + return dw_interp_secptr(input, DW_Section_StrOffsets, form); +} + +internal String8 +dw_interp_rnglists_ptr(DW_Raw *input, DW_Form form) +{ + return dw_interp_secptr(input, DW_Section_RngLists, form); +} + +internal String8 +dw_interp_loclists_ptr(DW_Raw *input, DW_Form form) +{ + return dw_interp_secptr(input, DW_Section_LocLists, form); +} + +internal DW_AttribClass +dw_value_class_from_attrib(DW_CompUnit *cu, DW_Attrib *attrib) +{ + return dw_pick_attrib_value_class(cu->version, cu->ext, cu->relaxed, attrib->attrib_kind, attrib->form.kind); +} + +internal String8 +dw_exprloc_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_ExprLoc || value_class == DW_AttribClass_Block); + return dw_interp_exprloc(attrib->form); +} + +internal U128 +dw_const_u128_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); + return dw_interp_const_u128(attrib->form); +} + +internal U64 +dw_const_u64_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); + return dw_interp_const_u64(attrib->form); +} + +internal U32 +dw_const_u32_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); + return dw_interp_const_u32(attrib->form); +} + +internal S64 +dw_const_s64_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); + return dw_interp_const_s64(attrib->form); +} + +internal S32 +dw_const_s32_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); + return dw_interp_const_s32(attrib->form); +} + +internal B32 +dw_flag_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Flag); + return dw_interp_flag(attrib->form); +} + +internal U64 +dw_address_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || + value_class == DW_AttribClass_Address || + value_class == DW_AttribClass_AddrPtr); + DW_Form form = attrib->form; + if (value_class == DW_AttribClass_AddrPtr) { + if (attrib->form.kind == DW_Form_SecOffset) { + NotImplemented; + } else { + AssertAlways(!"unexpected form"); + } + + form.kind = DW_Form_Addr; + form.addr = dw_interp_addrptr(input, attrib->form); + } + return dw_interp_address(cu->address_size, cu->low_pc, cu->addr_lu, form); +} + +internal String8 +dw_block_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Block); + return dw_interp_block(input, cu, attrib->form); +} + +internal String8 +dw_string_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_String || value_class == DW_AttribClass_StrOffsetsPtr); + return dw_interp_string(input, cu->format, cu->str_offsets_lu, attrib->form); +} + +internal String8 +dw_line_ptr_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_LinePtr); + return dw_interp_line_ptr(input, attrib->form); +} + +internal DW_LineFile * +dw_file_from_attrib(DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); + return dw_interp_file(line_vm, attrib->form); +} + +internal DW_Reference +dw_ref_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Reference); + return dw_interp_ref(input, cu, attrib->form); +} + +internal DW_LocList +dw_loclist_from_attrib(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || + value_class == DW_AttribClass_LocList || + value_class == DW_AttribClass_LocListPtr); + return dw_interp_loclist(arena, input, cu, attrib->form); +} + +internal Rng1U64List +dw_rnglist_from_attrib(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + Rng1U64List rnglist = {0}; + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + if (value_class == DW_AttribClass_RngListPtr || value_class == DW_AttribClass_RngList) { + rnglist = dw_interp_rnglist(arena, input, cu, attrib->form); + } else if (value_class != DW_AttribClass_Null) { + Assert(!"unexpected value class"); + } + return rnglist; +} + +internal DW_Attrib * +dw_attrib_from_tag_(DW_Tag tag, DW_AttribKind kind) +{ + local_persist read_only DW_Attrib null_attrib; + DW_Attrib *attrib = &null_attrib; + for (DW_AttribNode *attrib_n = tag.attribs.first; attrib_n != 0; attrib_n = attrib_n->next) { + if (attrib_n->v.attrib_kind == kind) { + attrib = &attrib_n->v; + break; + } + } + return attrib; +} + +internal DW_Attrib * +dw_attrib_from_tag(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + DW_Attrib *attrib = dw_attrib_from_tag_(tag, kind); + + if (attrib->attrib_kind == DW_AttribKind_Null) { + if (cu && cu->tag_ht) { + DW_Attrib *ao_attrib = dw_attrib_from_tag_(tag, DW_AttribKind_AbstractOrigin); + if (ao_attrib->attrib_kind == DW_AttribKind_AbstractOrigin) { + DW_Reference ref = dw_interp_ref(input, cu, ao_attrib->form); + DW_TagNode *ref_tag = dw_tag_node_from_info_off(ref.cu, ref.info_off); + attrib = dw_attrib_from_tag_(ref_tag->tag, kind); + } + } + } + + return attrib; +} + +internal B32 +dw_tag_has_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); + B32 has_attrib = attrib->attrib_kind != DW_AttribKind_Null; + return has_attrib; +} + +internal String8 +dw_exprloc_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_exprloc_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal String8 +dw_block_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_block_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal U128 +dw_const_u128_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_const_u128_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal U64 +dw_const_u64_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_const_u64_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal U32 +dw_const_u32_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_const_u32_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal U64 +dw_address_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_address_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal String8 +dw_string_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_string_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal String8 +dw_line_ptr_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_line_ptr_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal DW_Reference +dw_ref_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_ref_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal DW_LocList +dw_loclist_from_tag_attrib_kind(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_loclist_from_attrib(arena, input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal Rng1U64List +dw_rnglist_from_tag_attrib_kind(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_rnglist_from_attrib(arena, input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal B32 +dw_flag_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_flag_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal DW_LineFile * +dw_file_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Tag tag, DW_AttribKind kind) +{ + return dw_file_from_attrib(cu, line_vm, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal B32 +dw_try_byte_size_from_tag(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, U64 *byte_size_out) +{ + B32 has_byte_size = dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ByteSize); + B32 has_bit_size = dw_tag_has_attrib(input, cu, tag, DW_AttribKind_BitSize ); + + if (has_byte_size && has_bit_size) { + Assert(!"ill formated byte size"); + } + + if (has_byte_size) { + *byte_size_out = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); + return 1; + } else if (has_bit_size) { + U64 bit_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_BitSize); + *byte_size_out = bit_size / 8; + return 1; + } + + return 0; +} + +internal U64 +dw_byte_size_from_tag(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag) +{ + U64 byte_size = max_U64; + dw_try_byte_size_from_tag(input, cu, tag, &byte_size); + return byte_size; +} + +internal U32 +dw_byte_size_32_from_tag(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag) +{ + U32 byte_size32 = 0; + U64 byte_size64; + if (dw_try_byte_size_from_tag(input, cu, tag, &byte_size64)) { + byte_size32 = safe_cast_u32(byte_size64); + } + return byte_size32; +} + +internal U64 +dw_u64_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + U64 result = 0; + DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); + DW_AttribClass attrib_class = dw_value_class_from_attrib(cu, attrib); + if (attrib_class == DW_AttribClass_Const || attrib_class == DW_AttribClass_Block) { + if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Type)) { + Temp scratch = scratch_begin(0,0); + DW_Reference type_ref = dw_ref_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Type); + DW_Tag type_tag = {0}; + dw_read_tag_cu(scratch.arena, input, type_ref.cu, type_ref.info_off, &type_tag); + U64 type_byte_size = dw_byte_size_from_tag(input, cu, type_tag); + DW_ATE type_encoding = dw_const_u64_from_tag_attrib_kind(input, type_ref.cu, type_tag, DW_AttribKind_Encoding); + if (type_encoding == DW_ATE_Unsigned || type_encoding == DW_ATE_UnsignedChar) { + result = dw_interp_const64(type_byte_size, type_encoding, attrib->form); + } + scratch_end(scratch); + } else { + result = dw_interp_const_u64(attrib->form); + } + } else if (attrib_class == DW_AttribClass_Address) { + result = dw_address_from_attrib(input, cu, attrib); + } else if (attrib_class == DW_AttribClass_Reference) { + NotImplemented; + } else if (attrib_class != DW_AttribClass_Null) { + AssertAlways(!"unexpected attrib class"); + } + return result; +} + +internal B32 +dw_is_attrib_var_ref(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + B32 is_var_ref = 0; + if (dw_is_form_kind_ref(cu->version, cu->ext, attrib->form.kind)) { + Temp scratch = scratch_begin(0,0); + DW_Reference ref = dw_ref_from_attrib(input, cu, attrib); + DW_Tag ref_tag = {0}; + if (dw_read_tag_cu(scratch.arena, input, ref.cu, ref.info_off, &ref_tag)) { + is_var_ref = ref_tag.kind == DW_TagKind_Variable; + } + scratch_end(scratch); + } + return is_var_ref; +} + +internal DW_CompUnit +dw_cu_from_info_off(Arena *arena, DW_Raw *input, DW_ListUnitInput lu_input, U64 cu_header_offset, B32 relaxed) +{ + DW_CompUnit cu = {0}; + + U32 first_four_bytes = 0; + if (str8_deserial_read_struct(input->sec[DW_Section_Info].data, 0, &first_four_bytes) != sizeof(first_four_bytes)) { goto exit; } + DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit; + + // read unit size in bytes + U64 length = 0; + U64 length_size = str8_deserial_read_dwarf_packed_size(input->sec[DW_Section_Info].data, cu_header_offset, &length); + if (length_size == 0) { goto exit; } + + // compute unit range + Rng1U64 info_range = rng_1u64(cu_header_offset, cu_header_offset + length_size + length); + String8 info = str8_substr(input->sec[DW_Section_Info].data, info_range); + U64 info_cursor = length_size; + + // read version + DW_Version version; + TryRead(str8_deserial_read_struct(info, info_cursor, &version), info_cursor, exit); + + U64 abbrev_base = max_U64; + U8 address_size = 0; + DW_CompUnitKind unit_kind = DW_CompUnitKind_Reserved; + U64 spec_dwo_id = max_U64; + B32 is_header_ok = 0; + switch (version) { + default: + case DW_Version_Null: { + } break; + case DW_Version_1: { + NotImplemented; + } break; + case DW_Version_2: { + U32 abbrev_base32; + TryRead(str8_deserial_read_struct(info, info_cursor, &abbrev_base32), info_cursor, exit); + TryRead(str8_deserial_read_struct(info, info_cursor, &address_size), info_cursor, exit); + abbrev_base = abbrev_base32; + is_header_ok = 1; + } break; + case DW_Version_3: + case DW_Version_4: { + TryRead(str8_deserial_read_dwarf_uint(info, info_cursor, format, &abbrev_base), info_cursor, exit); + TryRead(str8_deserial_read_struct (info, info_cursor, &address_size), info_cursor, exit); + is_header_ok = 1; + } break; + case DW_Version_5: { + TryRead(str8_deserial_read_struct (info, info_cursor, &unit_kind), info_cursor, exit); + TryRead(str8_deserial_read_struct (info, info_cursor, &address_size), info_cursor, exit); + TryRead(str8_deserial_read_dwarf_uint(info, info_cursor, format, &abbrev_base), info_cursor, exit); + if (unit_kind == DW_CompUnitKind_Skeleton || input->sec[DW_Section_Info].is_dwo) { + TryRead(str8_deserial_read_struct(info, info_cursor, &spec_dwo_id), info_cursor, exit); + } + is_header_ok = 1; + } break; + } + + U64 header_size = info_cursor; + + if (is_header_ok) { + Temp temp = temp_begin(arena); + + // TODO: cache abbrev tables with identical offsets + DW_AbbrevTable abbrev_table = dw_make_abbrev_table(arena, input->sec[DW_Section_Abbrev].data, abbrev_base); + + DW_Tag cu_tag = {0}; + dw_read_tag(arena, input, abbrev_table, version, format, address_size, info_range, cu_header_offset + header_size, &cu_tag); + + // TODO: handle these unit types + if (cu_tag.kind == DW_TagKind_SkeletonUnit) { log_user_errorf("TODO: Skeleton Unit"); } + if (cu_tag.kind == DW_TagKind_TypeUnit) { log_user_errorf("TODO Type Unit"); } + + if (cu_tag.kind != DW_TagKind_CompileUnit && cu_tag.kind != DW_TagKind_PartialUnit) { + // unexpected tag, release memory and exit + temp_end(temp); + goto exit; + } + + // fetch attribs for list sections + DW_Attrib *addr_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_AddrBase ); + DW_Attrib *str_offsets_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_StrOffsetsBase); + DW_Attrib *rnglists_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_RngListsBase ); + DW_Attrib *loclists_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_LocListsBase ); + + // interp attribs as section offsets + U64 addr_sec_off = dw_interp_sec_offset(addr_base_attrib->form ); + U64 str_offsets_sec_off = dw_interp_sec_offset(str_offsets_base_attrib->form); + U64 rnglists_sec_off = dw_interp_sec_offset(rnglists_base_attrib->form ); + U64 loclists_sec_off = dw_interp_sec_offset(loclists_base_attrib->form ); + + // map section offset to unit index + U64 addr_lu_num = rng1u64_array_num_from_value__binary_search(&lu_input.addr_ranges, addr_sec_off ); + U64 str_offsets_lu_num = rng1u64_array_num_from_value__binary_search(&lu_input.str_offset_ranges, str_offsets_sec_off); + U64 rnglists_lu_num = rng1u64_array_num_from_value__binary_search(&lu_input.rnglist_ranges, rnglists_sec_off ); + U64 loclists_lu_num = rng1u64_array_num_from_value__binary_search(&lu_input.loclist_ranges, loclists_sec_off ); + + // map index to unit + DW_ListUnit *addr_lu = 0 < (addr_lu_num && addr_lu_num <= lu_input.addr_count) ? &lu_input.addrs[addr_lu_num-1] : 0; + DW_ListUnit *str_offsets_lu = 0 < (str_offsets_lu_num && str_offsets_lu_num <= lu_input.str_offset_count) ? &lu_input.str_offsets[str_offsets_lu_num-1] : 0; + DW_ListUnit *rnglists_lu = 0 < (rnglists_lu_num && rnglists_lu_num <= lu_input.rnglist_count) ? &lu_input.rnglists[rnglists_lu_num-1] : 0; + DW_ListUnit *loclists_lu = 0 < (loclists_lu_num && loclists_lu_num <= lu_input.loclist_count) ? &lu_input.loclists[loclists_lu_num-1] : 0; + + // find compile unit base address + DW_Attrib *low_pc_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_LowPc); + U64 low_pc = dw_interp_address(address_size, max_U64, addr_lu, low_pc_attrib->form); + + // fill out compile unit + cu.relaxed = relaxed; + cu.ext = DW_Ext_All; + cu.kind = unit_kind; + cu.version = version; + cu.format = format; + cu.address_size = address_size; + cu.abbrev_off = abbrev_base; + cu.info_range = info_range; + cu.first_tag_info_off = cu_header_offset + header_size; + cu.abbrev_table = abbrev_table; + cu.addr_lu = addr_lu; + cu.str_offsets_lu = str_offsets_lu; + cu.rnglists_lu = rnglists_lu; + cu.loclists_lu = loclists_lu; + cu.low_pc = low_pc; + cu.tag = cu_tag; + } + + exit:; + return cu; +} + +internal void +dw_tag_tree_from_data(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_TagNode *parent, U64 *cursor, U64 *tag_count) +{ + while (*cursor < cu->info_range.max) { + // read tag + DW_Tag tag = {0}; + TryRead(dw_read_tag(arena, input, cu->abbrev_table, cu->version, cu->format, cu->address_size, cu->info_range, *cursor, &tag), *cursor, exit); + + // reached of the CU? + if (tag.kind == DW_TagKind_Null) { break; } + + // normal tag + DW_TagNode *tag_n = push_array(arena, DW_TagNode, 1); + tag_n->tag = tag; + + SLLQueuePush_N(parent->first_child, parent->last_child, tag_n, sibling); + + // update tag count + *tag_count += 1; + + if (tag.has_children) { + dw_tag_tree_from_data(arena, input, cu, tag_n, cursor, tag_count); + } + } + exit:; +} + +internal DW_TagTree +dw_tag_tree_from_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu) +{ + DW_TagNode root = {0}; + U64 cursor = cu->first_tag_info_off; + U64 tag_count = 0; + dw_tag_tree_from_data(arena, input, cu, &root, &cursor, &tag_count); + Assert(cursor == cu->info_range.max); + return (DW_TagTree){ .root = root.first_child, .tag_count = tag_count }; +} + +internal HashTable * +dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree) +{ + Temp scratch = scratch_begin(&arena, 1); + + struct Frame { + struct Frame *next; + DW_TagNode *node; + }; + + struct Frame *free_frames = 0; + struct Frame *stack = push_array(scratch.arena, struct Frame, 1); + stack->node = tag_tree.root; + + HashTable *ht = hash_table_init(arena, (U64)((F64)tag_tree.tag_count * 1.3)); + + while (stack) { + while (stack->node) { + hash_table_push_u64_raw(arena, ht, stack->node->tag.info_off, stack->node); + + if (stack->node->first_child) { + struct Frame *frame = free_frames; + if (frame) { + SLLStackPop(free_frames); + MemoryZeroStruct(frame); + } else { + frame = push_array(scratch.arena, struct Frame, 1); + } + frame->node = stack->node->first_child; + SLLStackPush(stack, frame); + } else { + stack->node = stack->node->sibling; + } + } + + // recycle free frame + struct Frame *frame = stack; + SLLStackPop(stack); + SLLStackPush(free_frames, frame); + + if (stack) { + stack->node = stack->node->sibling; + } + } + + scratch_end(scratch); + return ht; +} + +internal DW_TagNode * +dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off) +{ + DW_TagNode *tag_node = hash_table_search_u64_raw(cu->tag_ht, info_off); + return tag_node; +} + +internal U64 +dw_read_line_vm_header(Arena *arena, + DW_Raw *input, + String8 cu_stmt_list, + String8 cu_dir, + String8 cu_name, + U8 cu_address_size, + DW_ListUnit *cu_str_offsets, + DW_LineVMHeader *header_out) +{ + Temp scratch = scratch_begin(&arena, 1); + + U64 cursor = 0; + + U32 first_four_bytes = 0; + if (str8_deserial_read_struct(cu_stmt_list, 0, &first_four_bytes) != sizeof(U32)) { goto exit; } + + // read unit length + U64 length = 0; + U64 length_size = str8_deserial_read_dwarf_packed_size(cu_stmt_list, 0, &length); + DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit; + + cursor = length_size; + String8 data = str8_substr(cu_stmt_list, r1u64(0, length + length_size)); + + // read unit version + DW_Version version = DW_Version_Null; + TryRead(str8_deserial_read_struct(data, cursor, &version), cursor, exit); + + // read DWARF5 address & segment selector + U8 address_size = cu_address_size; + U8 segsel_size = 0; + if (version == DW_Version_5) { + TryRead(str8_deserial_read_struct(data, cursor, &address_size), cursor, exit); + TryRead(str8_deserial_read_struct(data, cursor, &segsel_size), cursor, exit); + } + + U64 header_length = 0; + TryRead(str8_deserial_read_dwarf_uint(data, cursor, format, &header_length), cursor, exit); + U64 line_program_off = cursor + header_length; + + // substring header so we dont overread into the line program + data = str8_prefix(data, cursor + header_length); + + U8 min_inst_len = 0; + TryRead(str8_deserial_read_struct(data, cursor, &min_inst_len), cursor, exit); + + U8 max_ops_for_inst = 1; + if (version > DW_Version_3) { + TryRead(str8_deserial_read_struct(data, cursor, &max_ops_for_inst), cursor, exit); + Assert(max_ops_for_inst > 0); + } + + U8 default_is_stmt = 0; + TryRead(str8_deserial_read_struct(data, cursor, &default_is_stmt), cursor, exit); + + S8 line_base = 0; + TryRead(str8_deserial_read_struct(data, cursor, &line_base), cursor, exit); + + U8 line_range = 0; + TryRead(str8_deserial_read_struct(data, cursor, &line_range), cursor, exit); + + U8 opcode_base = 0; + TryRead(str8_deserial_read_struct(data, cursor, &opcode_base), cursor, exit); + + U64 num_opcode_lens = opcode_base > 0 ? opcode_base - 1 : 0; + String8 opcode_lens; + TryRead(str8_deserial_read_block(data, cursor, num_opcode_lens * sizeof(U8), &opcode_lens), cursor, exit); + + String8Array dir_table = {0}; + DW_LineFileArray file_table = {0}; + if (version < DW_Version_5) { + // read directory table + String8List dir_list = {0}; + + // compile directory is always first in the table + str8_list_push(scratch.arena, &dir_list, cu_dir); + + // parse additional directories + while (cursor < data.size) { + String8 dir = {0}; + TryRead(str8_deserial_read_cstr(data, cursor, &dir), cursor, exit); + if (dir.size == 0) { break; } + str8_list_push(scratch.arena, &dir_list, dir); + } + + DW_LineFileList file_list = {0}; + { + // compile unit name is always first in the file table + { + DW_LineFileNode *node = push_array(scratch.arena, DW_LineFileNode, 1); + node->file.path = cu_name; + SLLQueuePush(file_list.first, file_list.last, node); + file_list.node_count += 1; + } + + // read file table + while (cursor < data.size) { + U8 first_byte = 0; + if (str8_deserial_read_struct(data, cursor, &first_byte) == 0) { goto exit; } + if (first_byte == 0) { break; } + + DW_LineFile file = {0}; + TryRead(str8_deserial_read_cstr (data, cursor, &file.path), cursor, exit); + TryRead(str8_deserial_read_uleb128(data, cursor, &file.dir_idx), cursor, exit); + TryRead(str8_deserial_read_uleb128(data, cursor, &file.time_stamp), cursor, exit); + TryRead(str8_deserial_read_uleb128(data, cursor, &file.size), cursor, exit); + + DW_LineFileNode *node = push_array(scratch.arena, DW_LineFileNode, 1); + node->file = file; + + SLLQueuePush(file_list.first, file_list.last, node); + file_list.node_count += 1; + } + } + + // dir list -> array + dir_table = str8_array_from_list(arena, &dir_list); + + // file list -> array + file_table.count = 0; + file_table.v = push_array(arena, DW_LineFile, file_list.node_count); + for EachNode(n, DW_LineFileNode, file_list.first) { + DW_LineFile *dst = &file_table.v[file_table.count++]; + dst->path = push_str8_copy(arena, n->file.path); + dst->dir_idx = n->file.dir_idx; + dst->time_stamp = n->file.time_stamp; + dst->size = n->file.size; + } + } + // DWARF5 + else { + // directory table + { + // read table entry encoding count + U8 enc_count = 0; + TryRead(str8_deserial_read_struct(data, cursor, &enc_count), cursor, exit); + + // read table entry encodings + U64 *enc_arr = 0; + TryRead(str8_deserial_read_uleb128_array(scratch.arena, data, cursor, enc_count*2, &enc_arr), cursor, exit); + + // read table count + U64 table_count = 0; + TryRead(str8_deserial_read_uleb128(data, cursor, &table_count), cursor, exit); + + // validate encoding + if (table_count > 0) { + if (enc_count != 1) { goto exit; } + if (enc_arr[0] != DW_LNCT_Path) { goto exit; } + } + + // read table + dir_table.count = table_count; + dir_table.v = push_array(arena, String8, table_count); + for EachIndex(i, table_count) { + DW_FormKind form_kind = enc_arr[1]; + DW_Form form = {0}; + U64 form_size = 0; + if (!dw_read_form(str8_skip(data, cursor), version, format, address_size, form_kind, max_U64, &form, &form_size)) { goto exit; } + cursor += form_size; + dir_table.v[i] = dw_interp_string(input, format, cu_str_offsets, form); + } + } + + // file table + { + // read table entry encoding count + U8 enc_count = 0; + TryRead(str8_deserial_read_struct(data, cursor, &enc_count), cursor, exit); + + // read table entry encodings + U64 *enc_arr = 0; + TryRead(str8_deserial_read_uleb128_array(scratch.arena, data, cursor, enc_count*2, &enc_arr), cursor, exit); + + // read table count + U64 table_count = 0; + TryRead(str8_deserial_read_uleb128(data, cursor, &table_count), cursor, exit); + + file_table.count = table_count; + file_table.v = push_array(arena, DW_LineFile, table_count); + + for EachIndex(i, table_count) { + DW_LineFile *file = &file_table.v[i]; + for EachIndex(enc_idx, enc_count) { + DW_LNCT lnct = enc_arr[enc_idx*2 + 0]; + + DW_FormKind form_kind = enc_arr[enc_idx*2 + 1]; + DW_Form form = {0}; + U64 form_size = 0; + if (!dw_read_form(str8_skip(data, cursor), version, format, address_size, form_kind, max_U64, &form, &form_size)) { goto exit; } + cursor += form_size; + + switch (lnct) { + case DW_LNCT_Path: { file->path = dw_interp_string(input, format, cu_str_offsets, form); } break; + case DW_LNCT_DirectoryIndex: { file->dir_idx = dw_interp_const_u64(form); } break; + case DW_LNCT_TimeStamp: { file->time_stamp = dw_interp_const_u64(form); } break; + case DW_LNCT_Size: { file->size = dw_interp_const_u64(form); } break; + case DW_LNCT_MD5: { file->md5 = dw_interp_const_u128(form); } break; + case DW_LNCT_LLVM_Source: { file->source = dw_interp_string(input, format, cu_str_offsets, form); } break; + default: { + Assert(!"unexpected LNTC encoding"); + } break; + } + } + } + } + } + + if (header_out) { + header_out->unit_length = length_size + length; + header_out->version = version; + header_out->address_size = address_size; + header_out->segment_selector_size = segsel_size; + header_out->header_length = header_length; + header_out->min_inst_len = min_inst_len; + header_out->max_ops_for_inst = max_ops_for_inst; + header_out->default_is_stmt = default_is_stmt; + header_out->line_base = line_base; + header_out->line_range = line_range; + header_out->opcode_base = opcode_base; + header_out->num_opcode_lens = num_opcode_lens; + header_out->opcode_lens = opcode_lens.str; + header_out->line_program_off = line_program_off; + header_out->dir_table = dir_table; + header_out->file_table = file_table; + } + + exit:; + scratch_end(scratch); + return cursor; +} + +internal DW_LineVM * +dw_line_vm_init(DW_Raw *input, DW_CompUnit *cu) +{ + DW_LineVM *vm = 0; + + Arena *arena = arena_alloc(.reserve_size = KB(64), .commit_size = KB(1)); + + String8 cu_stmt_list = dw_line_ptr_from_tag_attrib_kind(input, cu, cu->tag, DW_AttribKind_StmtList); + String8 cu_dir = dw_string_from_tag_attrib_kind(input, cu, cu->tag, DW_AttribKind_CompDir); + String8 cu_name = dw_string_from_tag_attrib_kind(input, cu, cu->tag, DW_AttribKind_Name); + + // read the line table header + DW_LineVMHeader header = {0}; + if (cu_stmt_list.size) { + if ( ! dw_read_line_vm_header(arena, input, cu_stmt_list, cu_dir, cu_name, cu->address_size, cu->str_offsets_lu, &header)) { + goto exit; + } + } + + vm = push_array(arena, DW_LineVM, 1); + *vm = (DW_LineVM){ + .arena = arena, + .cursor = header.line_program_off, + .program = str8_prefix(cu_stmt_list, header.unit_length), + .header = header, + .state.end_sequence = 1, + }; + + exit:; + if (vm == 0) { arena_release(arena); } + return vm; +} + +internal void +dw_line_vm_release(DW_LineVM *vm) +{ + arena_release(vm->arena); +} + +internal void +dw_line_vm_advance(DW_LineVM *vm, U64 advance) +{ + U64 op_index = vm->state.op_index + advance; + vm->state.address += vm->header.min_inst_len * (op_index / vm->header.max_ops_for_inst); + vm->state.op_index = op_index % vm->header.max_ops_for_inst; + vm->advance = advance; +} + +internal B32 +dw_line_vm_step(DW_LineVM *vm) +{ + B32 is_ok = 0; + + if (vm->cursor >= vm->program.size) { goto exit; } + + vm->new_line = 0; + + // reset VM state + if (vm->state.end_sequence) { + vm->state.address = 0; + vm->state.op_index = 0; + vm->state.file_index = 1; + vm->state.line = 1; + vm->state.column = 0; + vm->state.is_stmt = vm->header.default_is_stmt; + vm->state.basic_block = 0; + vm->state.end_sequence = 0; + vm->state.prologue_end = 0; + vm->state.epilogue_begin = 0; + vm->state.isa = 0; + vm->state.discriminator = 0; + } + + // read opcode + TryRead(str8_deserial_read_struct(vm->program, vm->cursor, &vm->opcode), vm->cursor, exit); + + // special opcodes + if (vm->opcode >= vm->header.opcode_base) { + U32 adjusted_opcode = (U32)(vm->opcode - vm->header.opcode_base); + U32 op_advance = adjusted_opcode / vm->header.line_range; + S32 line_advance = (S64)vm->header.line_base + ((S64)adjusted_opcode) % (S64)vm->header.line_range; + U64 addr_advance = vm->header.min_inst_len * ((vm->state.op_index + op_advance) / vm->header.max_ops_for_inst); + + if (vm->header.line_range > 0 && vm->header.max_ops_for_inst > 0) { + adjusted_opcode = (U32)(vm->opcode - vm->header.opcode_base); + op_advance = adjusted_opcode / vm->header.line_range; + line_advance = (S32)vm->header.line_base + ((S32)adjusted_opcode) % (S32)vm->header.line_range; + addr_advance = vm->header.min_inst_len * ((vm->state.op_index+op_advance) / vm->header.max_ops_for_inst); + } + + vm->state.address += addr_advance; + vm->state.op_index = (vm->state.op_index + op_advance) % vm->header.max_ops_for_inst; + vm->state.line = (U64)((S64)vm->state.line + line_advance); + vm->state.basic_block = 0; + vm->state.prologue_end = 0; + vm->state.epilogue_begin = 0; + vm->state.discriminator = 0; + + vm->line_advance = line_advance; + vm->addr_advance = addr_advance; + vm->new_line = 1; + } else { + // standard opcodes + switch (vm->opcode) { + case DW_StdOpcode_Copy: { + vm->new_line = 1; + + vm->state.discriminator = 0; + vm->state.basic_block = 0; + vm->state.prologue_end = 0; + vm->state.epilogue_begin = 0; + } break; + + case DW_StdOpcode_AdvancePc: { + TryRead(str8_deserial_read_uleb128(vm->program, vm->cursor, &vm->operands[0].u64), vm->cursor, exit); + dw_line_vm_advance(vm, vm->operands[0].u64); + } break; + + case DW_StdOpcode_AdvanceLine: { + TryRead(str8_deserial_read_sleb128(vm->program, vm->cursor, &vm->operands[0].s64), vm->cursor, exit); + vm->state.line += vm->operands[0].s64; + } break; + + case DW_StdOpcode_SetFile: { + TryRead(str8_deserial_read_uleb128(vm->program, vm->cursor, &vm->operands[0].u64), vm->cursor, exit); + vm->state.file_index = vm->operands[0].u64; + } break; + + case DW_StdOpcode_SetColumn: { + TryRead(str8_deserial_read_uleb128(vm->program, vm->cursor, &vm->operands[0].u64), vm->cursor, exit); + vm->state.column = vm->operands[0].u64; + } break; + + case DW_StdOpcode_NegateStmt: { + vm->state.is_stmt = !vm->state.is_stmt; + } break; + + case DW_StdOpcode_SetBasicBlock: { + vm->state.basic_block = 1; + } break; + + case DW_StdOpcode_ConstAddPc: { + U64 advance = (0xffu - vm->header.opcode_base) / vm->header.line_range; + dw_line_vm_advance(vm, advance); + } break; + + case DW_StdOpcode_FixedAdvancePc: { + U16 fixed_advance = 0; + TryRead(str8_deserial_read_struct(vm->program, vm->cursor, &fixed_advance), vm->cursor, exit); + vm->operands[0].u64 = fixed_advance; + vm->state.address += vm->operands[0].u64; + vm->state.op_index = 0; + } 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: { + TryRead(str8_deserial_read_uleb128(vm->program, vm->cursor, &vm->operands[0].u64), vm->cursor, exit); + vm->state.isa = vm->operands[0].u64; + } break; + + // extended opcodes + case DW_StdOpcode_ExtendedOpcode: { + TryRead(str8_deserial_read_uleb128(vm->program, vm->cursor, &vm->ext_length), vm->cursor, exit); + String8 ext_data = str8_substr(vm->program, r1u64(vm->cursor, vm->cursor + vm->ext_length)); + vm->cursor += vm->ext_length; + + U64 ext_cursor = 0; + TryRead(str8_deserial_read_struct(ext_data, ext_cursor, &vm->ext_opcode), ext_cursor, exit); + + switch (vm->ext_opcode) { + case DW_ExtOpcode_EndSequence: { + vm->new_seq = 1; + vm->new_line = 1; + vm->state.end_sequence = 1; + } break; + + case DW_ExtOpcode_SetAddress: { + TryRead(str8_deserial_read(ext_data, ext_cursor, &vm->operands[0].u64, vm->header.address_size, vm->header.address_size), ext_cursor, exit); + vm->state.address = vm->operands[0].u64; + vm->state.op_index = 0; + } break; + + case DW_ExtOpcode_DefineFile: { + TryRead(str8_deserial_read_cstr (ext_data, ext_cursor, &vm->operands[0].string), ext_cursor, exit); // file name + TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[1].u64), ext_cursor, exit); // dir index + TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[2].u64), ext_cursor, exit); // modify time + TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[3].u64), ext_cursor, exit); // file size + + if (vm->ext_file_ht == 0) { + vm->ext_file_ht = hash_table_init(vm->arena, 512); + } + + DW_LineFile *file = push_array(vm->arena, DW_LineFile, 1); + file->path = vm->operands[0].string; + file->dir_idx = vm->operands[1].u64; + file->time_stamp = vm->operands[2].u64; + file->size = vm->operands[3].u64; + + if (hash_table_search_u64_raw(vm->ext_file_ht, vm->state.file_index) == 0) { + vm->error = push_str8f(vm->arena, "file with index %I64d was already defined", vm->state.file_index); + goto exit; + } + + hash_table_push_u64_raw(vm->arena, vm->ext_file_ht, vm->state.file_index, file); + } break; + + case DW_ExtOpcode_SetDiscriminator: { + TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[0].u64), ext_cursor, exit); + vm->state.discriminator = vm->operands[0].u64; + } break; + + default: { NotImplemented; } break; + } + } break; + + default: { + // skip unknown opcode + if (0 == vm->opcode || vm->opcode > vm->header.num_opcode_lens) { goto exit; } + for EachIndex(i, vm->header.opcode_lens[vm->opcode - 1]) { + U64 v = 0; + TryRead(str8_deserial_read_uleb128(vm->program, vm->cursor, &v), vm->cursor, exit); + } + } break; + } + } + + is_ok = 1; + exit:; + return is_ok; +} + +internal DW_LineFile * +dw_line_vm_find_file(DW_LineVM *vm, U64 file_idx) +{ + DW_LineFile *file = 0; + if (file == 0 && file_idx < vm->header.file_table.count) { + file = &vm->header.file_table.v[file_idx]; + } else if (vm->ext_file_ht) { + file = hash_table_search_u64_raw(vm->ext_file_ht, file_idx); + } + return file; +} + +internal String8 +dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file) +{ + Temp scratch = scratch_begin(&arena, 1); + + // directory table must contain at least compile unit directory + Assert(dir_table.count > 0); + + // find directory and file name associated with the file index + String8 dir = dir_table.v[file->dir_idx]; + String8 path = file->path; + + // infer path style if directory is empty use file name + PathStyle style = path_style_from_str8(dir); + if (style == PathStyle_Null || style == PathStyle_Relative) { + style = path_style_from_str8(file->path); + } + + String8List path_list = {0}; + { + // directories that start with ".." are relative to the compile unit directory + if (str8_match_lit("..", dir, StringMatchFlag_RightSideSloppy)) { + String8List comp_dir = str8_split_path(scratch.arena, dir_table.v[0]); + str8_list_concat_in_place(&path_list, &comp_dir); + } + + // push directory + String8List dir_list = str8_split_path(scratch.arena, dir); + str8_list_concat_in_place(&path_list, &dir_list); + + // push file name + str8_list_push(scratch.arena, &path_list, file->path); + + // resolve dots in the path + str8_path_list_resolve_dots_in_place(&path_list, style); + } + + // join path + String8 result = str8_path_list_join_by_style(arena, &path_list, style); + + scratch_end(scratch); + return result; +} + +internal DW_PubStringsTable +dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Raw *input, DW_SectionKind section_kind) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_PubStringsTable names_table = {0}; + names_table.size = 16384; + names_table.buckets = push_array(arena, DW_PubStringsBucket*, names_table.size); + + String8 section_data = input->sec[section_kind].data; + for(U64 cursor = 0; cursor < section_data.size; ) { + U32 first_four_bytes = 0; + if (str8_deserial_read_struct(input->sec[DW_Section_Info].data, 0, &first_four_bytes) != sizeof(first_four_bytes)) { break; } + DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit; + + U64 unit_length = 0; + U64 unit_length_size = str8_deserial_read_dwarf_packed_size(section_data, cursor, &unit_length); + if (unit_length_size == 0) { + break; + } + cursor += unit_length_size; + + U64 cursor_opl = Min(cursor + unit_length, section_data.size); + if (cursor >= cursor_opl) { + break; + } + + DW_Version unit_version = 0; + cursor += str8_deserial_read_struct(section_data, cursor, &unit_version); + if (cursor >= cursor_opl) { + break; + } + + U64 debug_info_off = 0; + cursor += str8_deserial_read_dwarf_uint(section_data, cursor, format, &debug_info_off); + if (cursor >= cursor_opl) { + break; + } + + U64 debug_info_length = 0; + cursor += str8_deserial_read_dwarf_packed_size(section_data, cursor, &debug_info_length); + if (cursor >= cursor_opl) { + break; + } + + U64 off_size = dw_size_from_format(format); + for (; (cursor + off_size) <= cursor_opl;) { + U64 info_off = 0; + U64 info_off_size = str8_deserial_read_dwarf_uint(section_data, cursor, format, &info_off); + cursor += info_off_size; + + if (info_off_size == 0 || info_off == 0) { + break; + } + + String8 string = {0}; + cursor += str8_deserial_read_cstr(section_data, cursor, &string); + + U64 hash = dw_hash_from_string(string); + U64 bucket_idx = hash % names_table.size; + + DW_PubStringsBucket *bucket = push_array(arena, DW_PubStringsBucket, 1); + bucket->next = names_table.buckets[bucket_idx]; + bucket->string = string; + bucket->info_off = info_off; + bucket->cu_info_off = debug_info_off; + names_table.buckets[bucket_idx] = bucket; + } + } + + scratch_end(scratch); + return names_table; +} + +internal DW_Expr +dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data) +{ + DW_Expr expr = {0}; + for (U64 cursor = 0, inst_start = 0; cursor < data.size; inst_start = cursor) { + // read opcode + DW_ExprOp opcode = 0; + U64 opcode_size = str8_deserial_read_struct(data, cursor, &opcode); + if (opcode_size == 0) { break; } + cursor += opcode_size; + + // read operands + U64 operand_count = dw_operand_count_from_expr_op(opcode); + DW_ExprOperandType *operand_types = dw_operand_types_from_expr_opcode(opcode); + DW_ExprOperand operands[2] = {0}; + for EachIndex(operand_idx, operand_count) { + U64 operand_size = 0; + switch (operand_types[operand_idx]) { + case DW_ExprOperandType_Null: { } break; + case DW_ExprOperandType_U8: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].u8); } break; + case DW_ExprOperandType_U16: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].u16); } break; + case DW_ExprOperandType_U32: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].u32); } break; + case DW_ExprOperandType_U64: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].u64); } break; + case DW_ExprOperandType_S8: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].s8); } break; + case DW_ExprOperandType_S16: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].s16); } break; + case DW_ExprOperandType_S32: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].s32); } break; + case DW_ExprOperandType_S64: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].s64); } break; + case DW_ExprOperandType_ULEB128: { operand_size = str8_deserial_read_uleb128(data, cursor, &operands[operand_idx].u64); } break; + case DW_ExprOperandType_SLEB128: { operand_size = str8_deserial_read_sleb128(data, cursor, &operands[operand_idx].s64); } break; + case DW_ExprOperandType_Addr: { operand_size = str8_deserial_read(data, cursor, &operands[operand_idx].u64, addr_size, addr_size); } break; + case DW_ExprOperandType_DwarfUInt: { operand_size = str8_deserial_read_dwarf_uint(data, cursor, format, &operands[operand_idx].u64); } break; + case DW_ExprOperandType_Block: { + U8 block_size; + U64 block_size_size = str8_deserial_read_struct(data, cursor, &block_size); + U64 block_read_size = str8_deserial_read_block(data, cursor + block_size_size, block_size, &operands[operand_idx].block); + if(block_read_size == block_size_size) { + operand_size = block_size_size + block_read_size; + } + } break; + default: { InvalidPath; } break; + } + if (operand_size == 0) { goto exit; } + cursor += operand_size; + } + + // fill out instruction + DW_ExprInst *inst = push_array(arena, DW_ExprInst, 1); + inst->opcode = opcode; + inst->size = cursor - inst_start; + inst->operands = operand_count ? push_array(arena, DW_ExprOperand, operand_count) : 0; + MemoryCopy(inst->operands, operands, operand_count * sizeof(DW_ExprOperand)); + + // push instruction + DLLPushBack(expr.first, expr.last, inst); + expr.count += 1; + } + exit:; + return expr; +} + +internal void +dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n) +{ + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal DW_CFA_InstNode * +dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v) +{ + DW_CFA_InstNode *n = push_array(arena, DW_CFA_InstNode, 1); + n->v = v; + dw_cfa_inst_list_push_node(list, n); + return n; +} + +internal U64 +dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out) +{ + U64 read_size = 0; + if (cie->segment_selector_size) { + NotImplemented; + } else { + read_size = str8_deserial_read(data, 0, ptr_out, cie->address_size, cie->address_size); + } + return read_size; +} + +internal U64 +dw_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; } + + U64 id_type = format == DW_Format_32Bit ? max_U32 : max_U64; + desc_out->format = format; + 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; + + exit:; + return length + length_size; +} + +internal B32 +dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out) +{ + B32 is_parsed = 0; + U64 cursor = format == DW_Format_32Bit ? 4 : 12; + + U64 cie_id = 0; + TryRead(str8_deserial_read_dwarf_uint(data, cursor, format, &cie_id), cursor, exit); + + U8 version = 0; + TryRead(str8_deserial_read_struct(data, cursor, &version), cursor, exit); + + String8 aug_string = {0}; + TryRead(str8_deserial_read_cstr(data, cursor, &aug_string), cursor, exit); + + U8 address_size = 0; + U8 segment_selector_size = 0; + if (version >= DW_Version_4) { + TryRead(str8_deserial_read_struct(data, cursor, &address_size), cursor, exit); + TryRead(str8_deserial_read_struct(data, cursor, &segment_selector_size), cursor, exit); + } else { + address_size = byte_size_from_arch(arch); + } + + U64 code_align_factor = 0; + TryRead(str8_deserial_read_uleb128(data, cursor, &code_align_factor), cursor, exit); + + S64 data_align_factor = 0; + TryRead(str8_deserial_read_sleb128(data, cursor, &data_align_factor), cursor, exit); + + U64 ret_addr_reg = 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); } + + if (aug_string.size > 0) { goto exit; } + + cie_out->insts = str8_skip(data, cursor); + cie_out->aug_string = aug_string; + 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 = address_size; + cie_out->segment_selector_size = segment_selector_size; + + is_parsed = 1; + exit:; + return is_parsed; +} + +internal B32 +dw_parse_fde(String8 data, DW_Format format, DW_CIE *cie, DW_FDE *fde_out) +{ + B32 is_parsed = 0; + U64 cursor = format == DW_Format_32Bit ? 4 : 12; + + // extract CIE pointer + U64 cie_pointer = 0; + TryRead(str8_deserial_read_dwarf_uint(data, cursor, format, &cie_pointer), cursor, exit); + + // extract address of first instruction + U64 pc_begin = 0; + TryRead(dw_read_debug_frame_ptr(str8_skip(data, cursor), cie, &pc_begin), cursor, exit); + + // extract instruction range size + U64 pc_range = 0; + TryRead(dw_read_debug_frame_ptr(str8_skip(data, cursor), cie, &pc_range), cursor, exit); + + // parse augmentation data + String8 aug_data = str8_substr(data, rng_1u64(cursor, cursor + cie->aug_data.size)); + cursor += cie->aug_data.size; + + // commit values to out + fde_out->format = format; + fde_out->cie_pointer = cie_pointer; + fde_out->pc_range = rng_1u64(pc_begin, pc_begin + pc_range); + fde_out->insts = str8_skip(data, cursor); + + is_parsed = 1; + exit:; + return is_parsed; +} + +internal B32 +dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out) +{ + B32 is_parsed = 0; + DW_DescriptorEntry fde_desc = {0}; + dw_parse_descriptor_entry_header(data, fde_offset, &fde_desc); + 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_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; + } + } + } + } + } + + return is_parsed; +} + +internal DW_CFA_ParseErrorCode +dw_parse_cfa_inst(String8 data, + U64 code_align_factor, + S64 data_align_factor, + DW_DecodePtr *decode_ptr_func, + void *decode_ptr_ud, + U64 *bytes_read_out, + DW_CFA_Inst *inst_out) +{ + *bytes_read_out = 0; + + DW_CFA_ParseErrorCode error_code = DW_CFA_ParseErrorCode_End; + U64 cursor = 0; + + // read opcode + DW_CFA_Opcode raw_opcode = 0; + TryRead(str8_deserial_read_struct(data, cursor, &raw_opcode), cursor, exit); + + // decode opcode implicit operand + U64 opcode = raw_opcode & ~DW_CFA_Mask_OpcodeHi; + U64 implicit_operand = 0; + if ((raw_opcode & DW_CFA_Mask_OpcodeHi) != 0) { + opcode = raw_opcode & DW_CFA_Mask_OpcodeHi; + implicit_operand = raw_opcode & DW_CFA_Mask_Operand; + } + + // decode operands + DW_CFA_Operand operands[DW_CFA_OperandMax] = {0}; + switch (opcode) { + case DW_CFA_SetLoc: { + U64 address_size = decode_ptr_func(str8_skip(data, cursor), decode_ptr_ud, &operands[0].u64); + if (address_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += address_size; + } break; + case DW_CFA_AdvanceLoc: { + operands[0].u64 = implicit_operand * code_align_factor; + } break; + case DW_CFA_AdvanceLoc1: { + U8 delta = 0; + U64 delta_size = str8_deserial_read_struct(data, cursor, &delta); + if (delta_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += delta_size; + operands[0].u64 = delta * code_align_factor; + } break; + case DW_CFA_AdvanceLoc2: { + U16 delta = 0; + U64 delta_size = str8_deserial_read_struct(data, cursor, &delta); + if (delta_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += delta_size; + operands[0].u64 = delta * code_align_factor; + } break; + case DW_CFA_AdvanceLoc4: { + U32 delta = 0; + U64 delta_size = str8_deserial_read_struct(data, cursor, &delta); + if (delta_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += delta_size; + operands[0].u64 = delta * code_align_factor; + } break; + case DW_CFA_DefCfa: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + U64 offset = 0; + U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = reg; + operands[1].u64 = offset; + } break; + case DW_CFA_DefCfaSf: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + S64 offset = 0; + U64 offset_size = str8_deserial_read_sleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = reg; + operands[1].s64 = offset * data_align_factor; + } break; + case DW_CFA_DefCfaRegister: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + operands[0].u64 = reg; + } break; + case DW_CFA_DefCfaOffset: { + U64 offset = 0; + U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = offset; + } break; + case DW_CFA_DefCfaOffsetSf: { + U64 offset = 0; + U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = offset * data_align_factor; + } break; + case DW_CFA_DefCfaExpr: { + U64 expr_size = 0; + U64 expr_size_size = str8_deserial_read_uleb128(data, cursor, &expr_size); + if (expr_size_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += expr_size_size; + + if (cursor + expr_size > data.size) { goto exit; } + String8 expr = str8_prefix(str8_skip(data, cursor), expr_size); + + operands[0].block = expr; + cursor += expr_size; + } break; + case DW_CFA_Undefined: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + operands[0].u64 = reg; + } break; + case DW_CFA_SameValue: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + operands[0].u64 = reg; + } break; + case DW_CFA_Offset: { + U64 offset = 0; + U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = implicit_operand; + operands[1].s64 = (S64)offset * data_align_factor; + } break; + case DW_CFA_OffsetExt: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + U64 offset = 0; + U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = reg; + operands[1].u64 = offset * data_align_factor; + } break; + case DW_CFA_OffsetExtSf: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + S64 offset = 0; + U64 offset_size = str8_deserial_read_sleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = reg; + operands[1].s64 = offset * data_align_factor; + } break; + case DW_CFA_ValOffset: { + U64 val = 0; + U64 val_size = str8_deserial_read_uleb128(data, cursor, &val); + if (val_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += val_size; + + U64 offset = 0; + U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = val; + operands[1].u64 = offset * data_align_factor; + } break; + case DW_CFA_ValOffsetSf: { + U64 val = 0; + U64 val_size = str8_deserial_read_uleb128(data, cursor, &val); + if (val_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += val_size; + + S64 offset = 0; + U64 offset_size = str8_deserial_read_sleb128(data, cursor, &offset); + if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += offset_size; + + operands[0].u64 = val; + operands[1].s64 = offset; + } break; + case DW_CFA_Register: { + U64 dst_reg = 0; + U64 dst_reg_size = str8_deserial_read_uleb128(data, cursor, &dst_reg); + if (dst_reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += dst_reg_size; + + U64 src_reg = 0; + U64 src_reg_size = str8_deserial_read_uleb128(data, cursor, &src_reg); + if (src_reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += src_reg_size; + + operands[0].u64 = dst_reg; + operands[1].u64 = src_reg; + } break; + case DW_CFA_Expr: { + U64 reg = 0; + U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); + if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += reg_size; + + U64 expr_size = 0; + U64 expr_size_size = str8_deserial_read_uleb128(data, cursor, &expr_size); + if (expr_size_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += expr_size_size; + + if (cursor + expr_size > data.size) { goto exit; } + String8 expr = str8_prefix(str8_skip(data, cursor), expr_size); + cursor += expr_size; + + operands[0].u64 = reg; + operands[1].block = expr; + } break; + case DW_CFA_ValExpr: { + U64 val = 0; + U64 val_size = str8_deserial_read_uleb128(data, cursor, &val); + if (val_size == 0) { goto exit; } + cursor += val_size; + + U64 expr_size = 0; + U64 expr_size_size = str8_deserial_read_uleb128(data, cursor, &expr_size); + if (expr_size_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } + cursor += expr_size_size; + + if (cursor + expr_size > data.size) { goto exit; } + String8 expr = str8_prefix(str8_skip(data, cursor), expr_size); + cursor += expr_size; + + operands[0].u64 = val; + operands[1].block = expr; + } break; + case DW_CFA_Restore: { + operands[0].u64 = implicit_operand; + } break; + case DW_CFA_RestoreExt: {} break; + case DW_CFA_RememberState: {} break; + case DW_CFA_RestoreState: {} break; + case DW_CFA_Nop: {} break; + default: { goto exit; } break; + } + + // fill out output + inst_out->opcode = opcode; + MemoryCopyTyped(&inst_out->operands[0], &operands[0], DW_CFA_OperandMax); + + *bytes_read_out = cursor; + + error_code = DW_CFA_ParseErrorCode_NewInst; + + exit:; + return error_code; +} + +internal DW_CFA_InstList +dw_parse_cfa_inst_list(Arena *arena, + String8 data, + U64 code_align_factor, + S64 data_align_factor, + DW_DecodePtr *decode_ptr_func, + void *decode_ptr_ud) +{ + U64 pos = arena_pos(arena); + DW_CFA_InstList list = {0}; + for (U64 cursor = 0, inst_size; cursor < data.size; cursor += inst_size) { + DW_CFA_Inst inst = {0}; + DW_CFA_ParseErrorCode error_code = dw_parse_cfa_inst(str8_skip(data, cursor), code_align_factor, data_align_factor, decode_ptr_func, decode_ptr_ud, &inst_size, &inst); + if (error_code == DW_CFA_ParseErrorCode_End) { break; } + if (error_code != DW_CFA_ParseErrorCode_NewInst) { + MemoryZeroStruct(&list); + arena_pop_to(arena, pos); + break; + } + dw_cfa_inst_list_push(arena, &list, inst); + } + return list; +} + +internal +DW_DECODE_PTR(dw_decode_ptr_debug_frame) +{ + return dw_read_debug_frame_ptr(data, ud, ptr_out); +} + diff --git a/obsolete/dwarf/dwarf_parse_old.h b/obsolete/dwarf/dwarf_parse_old.h new file mode 100644 index 00000000..2bddbe72 --- /dev/null +++ b/obsolete/dwarf/dwarf_parse_old.h @@ -0,0 +1,528 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DWARF_PARSE_H +#define DWARF_PARSE_H + +typedef struct DW_Section +{ + String8 name; + String8 data; + B32 is_dwo; +} DW_Section; + +typedef struct DW_Raw +{ + DW_Section sec[DW_Section_COUNT]; + DW_Section sup[DW_Section_COUNT]; +} DW_Raw; + +typedef struct DW_ListUnit +{ + DW_Version version; + U64 address_size; + U64 segment_selector_size; + U64 entry_size; + String8 entries; +} DW_ListUnit; + +typedef struct DW_ListUnitInput +{ + U64 addr_count; + U64 str_offset_count; + U64 rnglist_count; + U64 loclist_count; + Rng1U64Array addr_ranges; + Rng1U64Array str_offset_ranges; + Rng1U64Array rnglist_ranges; + Rng1U64Array loclist_ranges; + DW_ListUnit *addrs; + DW_ListUnit *str_offsets; + DW_ListUnit *rnglists; + DW_ListUnit *loclists; +} DW_ListUnitInput; + +typedef struct DW_AbbrevTableEntry +{ + U64 id; + U64 off; +} DW_AbbrevTableEntry; + +typedef struct DW_AbbrevTable DW_AbbrevTable; +struct DW_AbbrevTable +{ + U64 count; + DW_AbbrevTableEntry *entries; +}; + +typedef enum DW_AbbrevKind +{ + DW_Abbrev_Null, + DW_Abbrev_Tag, + DW_Abbrev_Attrib, + DW_Abbrev_AttribSequenceEnd, + DW_Abbrev_DIEBegin, + DW_Abbrev_DIEEnd, +} DW_AbbrevKind; + +typedef U32 DW_AbbrevFlags; +enum +{ + DW_AbbrevFlag_HasImplicitConst = (1 << 0), + DW_AbbrevFlag_HasChildren = (1 << 1), +}; + +typedef struct DW_Abbrev +{ + DW_AbbrevKind kind; + U64 sub_kind; + U64 id; + S64 implicit_const; + DW_AbbrevFlags flags; +} DW_Abbrev; + +typedef struct DW_Attrib +{ + U64 info_off; + U64 abbrev_off; + U64 abbrev_id; + DW_AttribKind attrib_kind; + DW_Form form; +} DW_Attrib; + +typedef struct DW_AttribNode +{ + struct DW_AttribNode *next; + DW_Attrib v; +} DW_AttribNode; + +typedef struct DW_AttribList +{ + DW_AttribNode *first; + DW_AttribNode *last; + U64 count; +} DW_AttribList; + +typedef U8 DW_TagSpare; +typedef struct DW_Tag +{ + B32 has_children; + U64 abbrev_id; + DW_TagKind kind; + DW_AttribList attribs; + U64 info_off; + DW_TagSpare v; +} DW_Tag; + +typedef struct DW_TagNode +{ + DW_Tag tag; + struct DW_TagNode *sibling; + struct DW_TagNode *first_child; + struct DW_TagNode *last_child; +} DW_TagNode; + +typedef struct DW_Loc +{ + Rng1U64 range; + String8 expr; +} DW_Loc; + +typedef struct DW_LocNode +{ + DW_Loc v; + struct DW_LocNode *next; +} DW_LocNode; + +typedef struct DW_LocList +{ + U64 count; + DW_LocNode *first; + DW_LocNode *last; +} DW_LocList; + +typedef struct DW_CompUnit +{ + B32 relaxed; + DW_Ext ext; + DW_CompUnitKind kind; + DW_Version version; + DW_Format format; + U64 address_size; + U64 abbrev_off; + Rng1U64 info_range; + U64 first_tag_info_off; + DW_AbbrevTable abbrev_table; + DW_ListUnit *addr_lu; + DW_ListUnit *str_offsets_lu; + DW_ListUnit *rnglists_lu; + DW_ListUnit *loclists_lu; + U64 low_pc; + U64 dwo_id; + DW_Tag tag; + HashTable *tag_ht; +} DW_CompUnit; + +typedef struct DW_TagTree +{ + DW_TagNode *root; + U64 tag_count; +} DW_TagTree; + +//////////////////////////////// + +typedef struct DW_LineFile +{ + String8 path; + U64 dir_idx; + U64 time_stamp; + U64 size; + U128 md5; + String8 source; +} DW_LineFile; + +typedef struct DW_LineFileNode +{ + struct DW_LineFileNode *next; + DW_LineFile file; +} DW_LineFileNode; + +typedef struct DW_LineFileList +{ + U64 node_count; + DW_LineFileNode *first; + DW_LineFileNode *last; +} DW_LineFileList; + +typedef struct DW_LineFileArray +{ + U64 count; + DW_LineFile *v; +} DW_LineFileArray; + +typedef struct DW_LineVMHeader +{ + U64 unit_length; + DW_Version version; + U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str. + U8 segment_selector_size; + U64 header_length; + U8 min_inst_len; + U8 max_ops_for_inst; + U8 default_is_stmt; + S8 line_base; + U8 line_range; + U8 opcode_base; + U64 num_opcode_lens; + U8 *opcode_lens; + U64 line_program_off; + String8Array dir_table; + DW_LineFileArray file_table; +} DW_LineVMHeader; + +typedef struct DW_LineVMState +{ + U64 address; // Address of a machine instruction. + U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction. + + // Line table doesn't contain full path to a file, instead + // DWARF encodes path as two indices. First index will point into a directory + // table, and second points into a file name table. + U64 file_index; + + U64 line; + U64 column; + + B32 is_stmt; // Indicates that "address" points to place suitable for a breakpoint. + B32 basic_block; // Indicates that the "address" is inside a basic block. + + // Indicates that "address" points to place where function starts. + // Usually prologue is the place where compiler emits instructions to + // prepare stack for a function. + B32 prologue_end; + + B32 epilogue_begin; // Indicates that "address" points to section where function exits and unwinds stack. + U64 isa; // Instruction set that is used. + U64 discriminator; // Arbitrary id that indicates to which block these instructions belong. + B32 end_sequence; // Indicates that "address" points to the first instruction in the instruction block that follows. +} DW_LineVMState; + +typedef struct DW_LineVM +{ + Arena *arena; + U64 cursor; + String8 program; + DW_LineVMHeader header; + B32 new_line; + B32 new_seq; + B32 skip_opcode; + DW_LineVMState state; + U64 advance; + U64 opcode_off; + DW_StdOpcode opcode; + DW_ExtOpcode ext_opcode; + U64 ext_length; + U64 line_advance; + U64 addr_advance; + HashTable *ext_file_ht; + struct { + union { + String8 string; + U64 u64; + S64 s64; + }; + } operands[4]; + String8 error; +} DW_LineVM; + +//////////////////////////////// +// .debug_pubnames and .debug_pubtypes + +typedef struct DW_PubStringsBucket +{ + struct DW_PubStringsBucket *next; + String8 string; + U64 info_off; + U64 cu_info_off; +} DW_PubStringsBucket; + +typedef struct DW_PubStringsTable +{ + U64 size; + DW_PubStringsBucket **buckets; +} DW_PubStringsTable; + +typedef struct DW_Reference +{ + DW_CompUnit *cu; + U64 info_off; // global .debug_info offset +} DW_Reference; + +//////////////////////////////// +//~ Expression + +typedef union DW_ExprOperand +{ + U8 u8; + U16 u16; + U32 u32; + U64 u64; + + S8 s8; + S16 s16; + S32 s32; + S64 s64; + + String8 block; +} DW_ExprOperand; + +typedef struct DW_ExprInst +{ + DW_ExprOp opcode; + DW_ExprOperand *operands; + U64 size; + struct DW_ExprInst *next; + struct DW_ExprInst *prev; +} DW_ExprInst; + +typedef struct DW_Expr +{ + U64 count; + DW_ExprInst *first; + DW_ExprInst *last; +} DW_Expr; + +//////////////////////////////// +// .debug_frame + +typedef struct DW_CIE +{ + String8 insts; + String8 aug_string; + String8 aug_data; + 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; +} DW_CIE; + +typedef struct DW_FDE +{ + DW_Format format; + U64 cie_pointer; + Rng1U64 pc_range; + String8 insts; +} DW_FDE; + +typedef union DW_CFA_Operand +{ + U64 u64; + S64 s64; + String8 block; +} DW_CFA_Operand; + +typedef enum +{ + DW_CFA_ParseErrorCode_NewInst, + DW_CFA_ParseErrorCode_End, + DW_CFA_ParseErrorCode_OutOfData +} DW_CFA_ParseErrorCode; + +typedef struct DW_CFA_Inst +{ + DW_CFA_Opcode opcode; + DW_CFA_Operand operands[DW_CFA_OperandMax]; +} DW_CFA_Inst; + +typedef struct DW_CFA_InstNode +{ + DW_CFA_Inst v; + struct DW_CFA_InstNode *next; +} DW_CFA_InstNode; + +typedef struct DW_CFA_InstList +{ + U64 count; + DW_CFA_InstNode *first; + DW_CFA_InstNode *last; +} DW_CFA_InstList; + +#define DW_DECODE_PTR(name) U64 name(String8 data, void *ud, U64 *ptr_out) +typedef DW_DECODE_PTR(DW_DecodePtr); + +// hasher + +internal U64 dw_hash_from_string(String8 string); + +// deserial helpers + +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_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); + +internal Rng1U64List dw_unit_ranges_from_data(Arena *arena, String8 data); +internal Rng1U64Array dw_unit_ranges_from_data_arr(Arena *arena, String8 data); + +// list units + +internal U64 dw_read_list_unit_header_addr (String8 unit_data, DW_ListUnit *lu_out); +internal U64 dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out); +internal U64 dw_read_list_unit_header_list (String8 unit_data, DW_ListUnit *lu_out); + +internal DW_ListUnitInput dw_list_unit_input_from_input(Arena *arena, DW_Raw *input); + +internal U64 dw_offset_from_list_unit(DW_ListUnit *lu, U64 index); +internal U64 dw_addr_from_list_unit (DW_ListUnit *lu, U64 index); + +// abbrev table + +internal U64 dw_read_abbrev_tag (String8 data, U64 offset, DW_Abbrev *out_abbrev); +internal U64 dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev); + +internal DW_AbbrevTable dw_read_abbrev_table(Arena *arena, String8 abbrev_data, U64 abbrev_base); +internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id); + +// form and tag + +internal B32 dw_read_form (String8 data, DW_Version version, DW_Format unit_format, U64 address_size, DW_FormKind form_kind, S64 implicit_const, DW_Form *form_out, U64 *bytes_read_out); +internal U64 dw_read_tag (Arena *arena, DW_Raw *input, DW_AbbrevTable abbrev_table, DW_Version version, DW_Format format, U64 address_size, Rng1U64 cu_info_range, U64 tag_info_off, DW_Tag *tag_out); +internal U64 dw_read_tag_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out); + +// attrib interp + +internal U64 dw_interp_sec_offset(DW_Form form); +internal String8 dw_interp_exprloc (DW_Form form); +internal U128 dw_interp_const_u128(DW_Form form); +internal U64 dw_interp_const_u64 (DW_Form form); +internal U32 dw_interp_const_u32 (DW_Form form); +internal S64 dw_interp_const_s64 (DW_Form form); +internal S32 dw_interp_const_s32 (DW_Form form); +internal B32 dw_interp_flag (DW_Form form); +internal U64 dw_interp_address (U64 address_size, U64 base_addr, DW_ListUnit *addr_xlist, DW_Form form); +internal String8 dw_interp_block (DW_Raw *input, DW_CompUnit *cu, DW_Form form); +internal String8 dw_interp_string (DW_Raw *input, DW_Format unit_format, DW_ListUnit *str_offsets, DW_Form form); +internal String8 dw_interp_line_ptr (DW_Raw *input, DW_Form form); +internal DW_LineFile * dw_interp_file (DW_LineVM *line_vm, DW_Form form); +internal DW_Reference dw_interp_ref (DW_Raw *input, DW_CompUnit *cu, DW_Form form); +internal DW_LocList dw_interp_loclist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form); +internal Rng1U64List dw_interp_rnglist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form); + +internal String8 dw_exprloc_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal U128 dw_const_u128_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal U64 dw_const_u64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal U32 dw_const_u32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal S64 dw_const_s64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal S32 dw_const_s32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal B32 dw_flag_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal U64 dw_address_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal String8 dw_block_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal String8 dw_string_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal String8 dw_line_ptr_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal DW_LineFile * dw_file_from_attrib (DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib); +internal DW_Reference dw_ref_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); + +internal String8 dw_exprloc_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal U128 dw_const_u128_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal U64 dw_const_u64_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal U32 dw_const_u32_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal B32 dw_flag_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal U64 dw_address_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal String8 dw_block_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal String8 dw_string_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal DW_LineFile * dw_file_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Tag tag, DW_AttribKind kind); +internal DW_Reference dw_ref_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal DW_LocList dw_loclist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal Rng1U64List dw_rnglist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); + +internal B32 dw_is_attrib_var_ref(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); + +// compile unit + +internal DW_CompUnit dw_cu_from_info_off(Arena *arena, DW_Raw *input, DW_ListUnitInput lu_input, U64 offset, B32 relaxed); +internal DW_TagTree dw_tag_tree_from_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu); +internal HashTable * dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree); +internal DW_TagNode * dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off); + +// line VM + +internal U64 dw_read_line_vm_header(Arena *arena, DW_Raw *input, String8 cu_stmt_list, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets, DW_LineVMHeader *header_out); +internal DW_LineVM * dw_line_vm_init(DW_Raw *input, DW_CompUnit *cu); +internal void dw_line_vm_release(DW_LineVM *vm); +internal void dw_line_vm_advance(DW_LineVM *vm, U64 advance); +internal B32 dw_line_vm_step(DW_LineVM *vm); +internal DW_LineFile * dw_line_vm_find_file(DW_LineVM *vm, U64 file_idx); +internal String8 dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file); + +// helper for .debug_pubtypes and .debug_pubnames + +internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Raw *input, DW_SectionKind section_kind); + +// expression + +internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data); + +// debug frame + +internal void dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n); +internal DW_CFA_InstNode * dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v); + +internal U64 dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out); + +internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out); +internal B32 dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out); +internal B32 dw_parse_fde(String8 data, DW_Format format, DW_CIE *cie, DW_FDE *fde_out); +internal B32 dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out); + +internal DW_CFA_ParseErrorCode dw_parse_cfa_inst(String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud, U64 *bytes_read_out, DW_CFA_Inst *inst_out); +internal DW_CFA_InstList dw_parse_cfa_inst_list(Arena *arena, String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud); + +#endif // DWARF_PARSE_H diff --git a/obsolete/dwarf/dwarf_unwind_old.c b/obsolete/dwarf/dwarf_unwind_old.c new file mode 100644 index 00000000..c8124236 --- /dev/null +++ b/obsolete/dwarf/dwarf_unwind_old.c @@ -0,0 +1,373 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal DW_CFI_Row * +dw_make_cfi_row(Arena *arena, U64 reg_count) +{ + DW_CFI_Row *row = push_array(arena, DW_CFI_Row, 1); + row->regs = push_array(arena, DW_CFI_Register, reg_count); + for EachIndex(reg_idx, reg_count) { + row->regs[reg_idx].rule = DW_CFI_RegisterRule_SameValue; + } + return row; +} + +internal void +dw_memcpy_cfi_row(DW_CFI_Row *dst, DW_CFI_Row *src, U64 reg_count) +{ + dst->cfa = src->cfa; + MemoryCopyTyped(dst->regs, src->regs, reg_count); +} + +internal DW_CFI_Row * +dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count) +{ + DW_CFI_Row *new_row = dw_make_cfi_row(arena, reg_count); + dw_memcpy_cfi_row(new_row, row, reg_count); + return new_row; +} + +internal DW_CFI_Unwind * +dw_cfi_unwind_init(Arena *arena, + Arch arch, + DW_CIE *cie, + DW_FDE *fde, + DW_DecodePtr *decode_ptr_func, + void *decode_ptr_ud) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_CFI_Unwind *uw = push_array(arena, DW_CFI_Unwind, 1); + uw->insts = dw_parse_cfa_inst_list(arena, fde->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud); + uw->cie = cie; + uw->fde = fde; + uw->pc = fde->pc_range.min; + uw->arch = arch; + uw->reg_count = dw_reg_count_from_arch(arch); + + // setup initial register rules + DW_CFA_InstList initial_insts = dw_parse_cfa_inst_list(scratch.arena, cie->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud); + uw->row = dw_make_cfi_row(arena, uw->reg_count); + uw->curr_inst = initial_insts.first; + if (!dw_cfi_next_row(arena, uw)) { + AssertAlways(0 && "unable to interpret initial row instructions"); + } + + // make first row from initial rules + uw->initial_row = uw->row; + uw->row = dw_copy_cfi_row(arena, uw->initial_row, uw->reg_count); + uw->curr_inst = uw->insts.first; + + scratch_end(scratch); + return uw; +} + +internal B32 +dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw) +{ + B32 is_row_valid = 0; + DW_CFA_InstNode *row_inst = uw->curr_inst; + + // skip leading nops + while (uw->curr_inst) { + if (uw->curr_inst->v.opcode != DW_CFA_Nop) { + break; + } + uw->curr_inst = uw->curr_inst->next; + } + + while (uw->curr_inst) { + DW_CFA_Inst *inst = &uw->curr_inst->v; + + // validate register operands + DW_CFA_OperandType *operand_types = dw_operand_types_from_cfa_op(inst->opcode); + U64 operand_count = dw_operand_count_from_cfa_opcode(inst->opcode); + for EachIndex(operand_idx, operand_count) { + if (operand_types[operand_idx] == DW_CFA_OperandType_Register) { + if (inst->operands[operand_idx].u64 >= uw->reg_count) { + goto exit; + } + } + } + + switch (inst->opcode) { + // Row Creation Instructions + case DW_CFA_SetLoc: { + uw->pc = inst->operands[0].u64; + } break; + case DW_CFA_AdvanceLoc: + case DW_CFA_AdvanceLoc1: + case DW_CFA_AdvanceLoc2: + case DW_CFA_AdvanceLoc4: { + uw->pc += inst->operands[0].u64; + } break; + + // CFA Definition Instructions + case DW_CFA_DefCfa: + case DW_CFA_DefCfaSf: { + U64 reg = inst->operands[0].u64; + S64 off = inst->operands[1].s64; + uw->row->cfa.rule = DW_CFA_Rule_RegOff; + uw->row->cfa.reg = reg; + uw->row->cfa.off = off; + } break; + case DW_CFA_DefCfaRegister: { + // TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset + if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; } + U64 reg = inst->operands[0].u64; + uw->row->cfa.reg = reg; + } break; + case DW_CFA_DefCfaOffset: + case DW_CFA_DefCfaOffsetSf: { + // TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset + if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; } + uw->row->cfa.off = inst->operands[0].s64; + } break; + case DW_CFA_DefCfaExpr: { + uw->row->cfa.rule = DW_CFA_Rule_Expression; + uw->row->cfa.expr = inst->operands[0].block; + } break; + + // Register Rule Instructions + case DW_CFA_Undefined: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_Undefined; + } break; + case DW_CFA_SameValue: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_SameValue; + } break; + case DW_CFA_Offset: + case DW_CFA_OffsetExt: + case DW_CFA_OffsetExtSf: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_Offset; + uw->row->regs[reg].n = inst->operands[1].s64; + } break; + case DW_CFA_ValOffset: + case DW_CFA_ValOffsetSf: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValOffset; + uw->row->regs[reg].n = inst->operands[1].s64; + } break; + case DW_CFA_Register: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_Register; + uw->row->regs[reg].n = inst->operands[1].s64; + } break; + case DW_CFA_Expr: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_Expression; + uw->row->regs[reg].expr = inst->operands[1].block; + } break; + case DW_CFA_ValExpr: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValExpression; + uw->row->regs[reg].expr = inst->operands[1].block; + } break; + case DW_CFA_Restore: + case DW_CFA_RestoreExt: { + U64 reg = inst->operands[0].u64; + uw->row->regs[reg] = uw->initial_row->regs[reg]; + } break; + + // Row State Instructions + case DW_CFA_RememberState: { + DW_CFI_Row *new_row = dw_copy_cfi_row(arena, uw->row, uw->reg_count); + SLLStackPush(uw->row, new_row); + } break; + case DW_CFA_RestoreState: { + if (uw->row == 0) { goto exit; } // TODO: report error: unbalanced number of pushes and pops + DW_CFI_Row *free_row = uw->row; + SLLStackPop(uw->row); + SLLStackPush(uw->free_rows, free_row); + } break; + + case DW_CFA_Nop: {} break; + + default: { NotImplemented; } break; // TODO: report error: unknown CFA opcode + } + + uw->curr_inst = uw->curr_inst->next; + if (uw->curr_inst) { + if (dw_is_new_row_cfa_opcode(uw->curr_inst->v.opcode)) { break; } + } + } + + is_row_valid = row_inst != 0; + exit:; + return is_row_valid; +} + +internal DW_CFI_Row * +dw_cfi_row_from_pc(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc) +{ + Temp scratch = scratch_begin(&arena, 1); + + B32 is_row_found = 0; + U64 reg_count = dw_reg_count_from_arch(arch); + DW_CFI_Unwind *uw = dw_cfi_unwind_init(scratch.arena, arch, cie, fde, decode_ptr_func, decode_ptr_ctx); + DW_CFI_Row *row = dw_copy_cfi_row(scratch.arena, uw->row, uw->reg_count); + U64 prev_pc = uw->pc; + while (dw_cfi_next_row(scratch.arena, uw)) { + if (prev_pc <= pc && pc < uw->pc) { + is_row_found = 1; + break; + } + dw_memcpy_cfi_row(row, uw->row, uw->reg_count); + prev_pc = uw->pc; + } + + // handle last row + if (!is_row_found) { + if (contains_1u64(fde->pc_range, pc)) { + row = uw->row; + is_row_found = 1; + } + } + + // copy out final row + DW_CFI_Row *result = 0; + if (is_row_found) { + result = dw_copy_cfi_row(arena, row, reg_count); + } + + scratch_end(scratch); + return result; +} + +internal MachineOpResult +dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out) +{ + MachineOpResult unwind_status = MachineOpResult_Fail; + ARCH_Info *arch_info = arch_info_from_arch(arch); + switch(row->cfa.rule) + { + case DW_CFA_Rule_Null:{}break; + case DW_CFA_Rule_RegOff: + { + // TODO: report error (invalid register read) + U64 cfa_reg_value = 0; + U64 reg_size = dw_reg_size_from_code(arch, row->cfa.reg); + AssertAlways(reg_size <= sizeof(cfa_reg_value)); + ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, row->cfa.reg); + Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code]; + if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, &cfa_reg_value)) + { + break; + } + *cfa_out = cfa_reg_value + row->cfa.off; + unwind_status = MachineOpResult_Ok; + }break; + case DW_CFA_Rule_Expression: + { + Temp scratch = scratch_begin(0,0); + DW_ExprValue value = {0}; + DW_Expr expr = dw_expr_from_data(scratch.arena, DW_Format_32Bit, byte_size_from_arch(arch), row->cfa.expr); + DW_ExprEvalResult eval_result = dw_eval_expr(scratch.arena, arch, DW_Format_32Bit, 0, 0, 0, 9999, expr, reg_block, mem_read_func, mem_read_ud, &value); + if (eval_result == DW_ExprEvalResult_Ok) { + if (DW_ExprValueType_IsInt(value.type)) { + *cfa_out = value.u64; + unwind_status = MachineOpResult_Ok; + } + } else if (eval_result == DW_ExprEvalResult_Maybe) { + unwind_status = MachineOpResult_Maybe; + } + scratch_end(scratch); + }break; + } + return unwind_status; +} + +internal MachineOpResult +dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud) +{ + Temp scratch = scratch_begin(0,0); + MachineOpResult unwind_status = MachineOpResult_Ok; + + ARCH_Info *arch_info = arch_info_from_arch(arch); + + U64 max_reg_size = dw_reg_max_size_from_arch(arch); + void *reg_buffer = push_array(scratch.arena, U8, max_reg_size); + + U64 reg_count = dw_reg_count_from_arch(arch); + for EachIndex(reg_idx, reg_count) + { + DW_CFI_Register *reg = &row->regs[reg_idx]; + ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_idx); + Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code]; + switch(reg->rule) + { + default:{}break; + case DW_CFI_RegisterRule_Undefined: {} break; + case DW_CFI_RegisterRule_SameValue: {} break; + case DW_CFI_RegisterRule_Offset: + { + // read register value from memory + U64 addr = cfa + reg->n; + U64 reg_size = dw_reg_size_from_code(arch, reg_idx); + unwind_status = mem_read_func(addr, reg_buffer, reg_size, mem_read_ud); + if (unwind_status != MachineOpResult_Ok) { goto exit; } + + // write register value to the thread context + if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer)) + { + unwind_status = MachineOpResult_Fail; + goto exit; + } + }break; + case DW_CFI_RegisterRule_ValOffset: + { + // compute register value + U64 reg_value = cfa + reg->n; + + // write register value to the thread context + U64 reg_size = dw_reg_size_from_code(arch, reg_idx); + if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, ®_value)) + { + unwind_status = MachineOpResult_Fail; + goto exit; + } + }break; + case DW_CFI_RegisterRule_Register: + { + // read register value from another register + U64 reg_size = dw_reg_size_from_code(arch, reg_idx); + if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, reg_buffer)) + { + unwind_status = MachineOpResult_Fail; + goto exit; + } + + // write register value to the thread context + if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer)) + { + unwind_status = MachineOpResult_Fail; + goto exit; + } + if (unwind_status != MachineOpResult_Ok) { goto exit; } + }break; + case DW_CFI_RegisterRule_Expression: + { + // TODO: evaluate expression + NotImplemented; + }break; + case DW_CFI_RegisterRule_ValExpression: + { + // TODO: evaluate expression + NotImplemented; + }break; + case DW_CFI_RegisterRule_Architectural: + { + NotImplemented; + }break; + } + } + + // update stack pointer + arch_reg_block_write_sp(arch_info, reg_block, cfa); + + exit:; + scratch_end(scratch); + return unwind_status; +} diff --git a/obsolete/dwarf/dwarf_unwind_old.h b/obsolete/dwarf/dwarf_unwind_old.h new file mode 100644 index 00000000..63e5ba3f --- /dev/null +++ b/obsolete/dwarf/dwarf_unwind_old.h @@ -0,0 +1,81 @@ +// Copyright (c) Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DWARF_UNWIND_H +#define DWARF_UNWIND_H + +typedef enum DW_CFI_RegisterRule +{ + DW_CFI_RegisterRule_Undefined, + DW_CFI_RegisterRule_SameValue, + DW_CFI_RegisterRule_Offset, + DW_CFI_RegisterRule_ValOffset, + DW_CFI_RegisterRule_Register, + DW_CFI_RegisterRule_Expression, + DW_CFI_RegisterRule_ValExpression, + DW_CFI_RegisterRule_Architectural +} DW_CFI_RegisterRule; + +typedef enum DW_CFA_Rule +{ + DW_CFA_Rule_Null, + DW_CFA_Rule_RegOff, + DW_CFA_Rule_Expression +} DW_CFA_Rule; + +typedef struct DW_CFA +{ + DW_CFA_Rule rule; + union { + struct { + DW_Reg reg; + S64 off; + }; + String8 expr; + }; +} DW_CFA; + +typedef struct DW_CFI_Register +{ + DW_CFI_RegisterRule rule; + union { + S64 n; + String8 expr; + }; +} DW_CFI_Register; + +typedef struct DW_CFI_Row +{ + DW_CFA cfa; + DW_CFI_Register *regs; + struct DW_CFI_Row *next; +} DW_CFI_Row; + +typedef struct DW_CFI_Unwind +{ + DW_CFA_InstList insts; + DW_CIE *cie; + DW_FDE *fde; + DW_CFI_Row *initial_row; + DW_CFI_Row *row; + DW_CFA_InstNode *curr_inst; + DW_CFI_Row *free_rows; + U64 pc; + Arch arch; + U64 reg_count; +} DW_CFI_Unwind; + +//////////////////////////////// + +internal DW_CFI_Row * dw_make_cfi_row(Arena *arena, U64 reg_count); +internal DW_CFI_Row * dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count); + +internal DW_CFI_Unwind * dw_cfi_unwind_init(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud); +internal B32 dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw); + +internal DW_CFI_Row * dw_cfi_row_from_pc(Arena *arena, Arch arch, struct DW_CIE *cie, struct DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc); +internal MachineOpResult dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out); +internal MachineOpResult dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud); + +#endif // DWARF_UNWIND_H + diff --git a/src/dwarf/dwarf_dump.c b/src/dwarf/dwarf_dump.c index 9b6d6481..04f7669c 100644 --- a/src/dwarf/dwarf_dump.c +++ b/src/dwarf/dwarf_dump.c @@ -1,254 +1,29 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#define dw_indent() do { indent += 1; } while (0) -#define dw_unindent() do { indent -= 1; } while (0) -#define dw_print(string) dw_print_ (arena, strings, indent, string) -#define dw_printf(...) dw_printf_(arena, strings, indent, __VA_ARGS__) -static char g_spaces[] = " "; - -internal void -dw_print_(Arena *arena, String8List *out, int indent, String8 string) -{ - Temp scratch = scratch_begin(&arena, 1); - str8_list_pushf(arena, out, "%.*s%S", Min(indent * 2, sizeof(g_spaces)), g_spaces, string); - scratch_end(scratch); -} - -internal void -dw_printf_(Arena *arena, String8List *out, int indent, char *fmt, ...) -{ - Temp scratch = scratch_begin(&arena, 1); - va_list args; - va_start(args, fmt); - String8 string = push_str8fv(scratch.arena, fmt, args); - dw_print_(arena, out, indent, string); - va_end(args); - scratch_end(scratch); -} - -internal Rng1U64Array -dw_get_info_ranges(DW_Dumper *dumper) -{ - if (!(dumper->cache_flags & DW_DumperCacheFlag_InfoRanges)) { - dumper->cache.info_ranges = dw_unit_ranges_from_data_arr(dumper->arena, dumper->input->sec[DW_Section_Info].data); - } - return dumper->cache.info_ranges; -} - -internal DW_CompUnit * -dw_get_cu_arr(DW_Dumper *dumper) -{ - if (!(dumper->cache_flags & DW_DumperCacheFlag_CuArr)) { - Rng1U64Array info_ranges = dw_get_info_ranges(dumper); - DW_ListUnitInput lu_input = dw_list_unit_input_from_input(dumper->arena, dumper->input); - dumper->cache.cu_arr = push_array(dumper->arena, DW_CompUnit, info_ranges.count); - for EachIndex(cu_idx, info_ranges.count) { - dumper->cache.cu_arr[cu_idx] = dw_cu_from_info_off(dumper->arena, dumper->input, lu_input, info_ranges.v[cu_idx].min, dumper->is_relaxed); - } - } - return dumper->cache.cu_arr; -} - -internal HashTable * -dw_get_line_vm_map(DW_Dumper *dumper) -{ - if (!(dumper->cache_flags & DW_DumperCacheFlag_LineVmMap)) { - Rng1U64Array unit_ranges = dw_unit_ranges_from_data_arr(dumper->arena, dumper->input->sec[DW_Section_Line].data); - dumper->cache.line_vm_map = hash_table_init(dumper->arena, unit_ranges.count * 2); - } - return dumper->cache.line_vm_map; -} - -internal DW_TagTree * -dw_get_tag_trees(DW_Dumper *dumper) -{ - if (!(dumper->cache_flags & DW_DumperCacheFlag_TagTrees)) { - Rng1U64Array info_ranges = dw_get_info_ranges(dumper); - DW_CompUnit *cu_arr = dw_get_cu_arr(dumper); - dumper->cache.tag_trees = push_array(dumper->arena, DW_TagTree, info_ranges.count); - for EachIndex(cu_idx, info_ranges.count) { - dumper->cache.tag_trees[cu_idx] = dw_tag_tree_from_cu(dumper->arena, dumper->input, &cu_arr[cu_idx]); - } - } - return dumper->cache.tag_trees; -} - //////////////////////////////// -//~ rjf: Stringification Helpers +//~ rjf: Helpers internal String8List -dw_string_list_from_cfi_program(Arena *arena, - U64 cu_base, - Arch arch, - DW_Version ver, - DW_Ext ext, - DW_Format format, - U64 pc_begin, - DW_CIE *cie, - DW_DecodePtr *decode_ptr_func, - void *deocde_ptr_ud, - String8 program) +dw_dump_list_from_expr(Arena *arena, String8 data, Arch arch, DW2_ParseCtx *ctx) { - Temp scratch = scratch_begin(&arena, 1); - String8List list = {0}; - - U64 reg_max = dw_reg_count_from_arch(arch); - U64 pc = pc_begin; - for (U64 cursor = 0, inst_size; cursor < program.size; cursor += inst_size) { - // unpack instruction - DW_CFA_Inst inst = {0}; - DW_CFA_ParseErrorCode error_code = dw_parse_cfa_inst(str8_skip(program, cursor), cie->code_align_factor, cie->data_align_factor, 0, 0, &inst_size, &inst); - if (error_code == DW_CFA_ParseErrorCode_End) { break; } - if (error_code != DW_CFA_ParseErrorCode_NewInst) { - str8_list_pushf(arena, &list, "ERROR: failed to unpack CFA instruction @ 0x%I64", cursor); - break; - } - - // error check operands - DW_CFA_OperandType *operand_types = dw_operand_types_from_cfa_op(inst.opcode); - U64 operand_count = dw_operand_count_from_cfa_opcode(inst.opcode); - for EachIndex(operand_idx, operand_count) { - switch (operand_types[operand_idx]) { - case DW_CFA_OperandType_Null: break; - case DW_CFA_OperandType_Value: break; - case DW_CFA_OperandType_Register: { - if (inst.operands[operand_idx].u64 >= reg_max) { - str8_list_pushf(arena, &list, "ERROR: DW_CFA_%S @ 0x%I64x has an invalid register", - dw_string_from_cfa_opcode(inst.opcode), - cursor); - } - } break; - case DW_CFA_OperandType_Expression: { - DW_Expr expr = dw_expr_from_data(scratch.arena, format, cie->address_size, inst.operands[operand_idx].block); - for EachNode(inst, DW_ExprInst, expr.first) { - if (dw_is_cfa_expr_opcode_invalid(inst->opcode)) { - String8 expr_opcode_str = dw_string_from_expr_op(scratch.arena, ver, ext, inst->opcode); - str8_list_pushf(arena, &list, "ERROR: Exrepssion in DW_CFA_%S @ 0x%I64x has an invalid opcode DW_ExprOp_%S", expr_opcode_str); - } - } - } break; - default: { InvalidPath; } break; - } - } - - // format operands - String8 operand_str = str8_lit("???"); - switch (inst.opcode) { - case DW_CFA_Nop: { operand_str = str8_zero(); } break; - case DW_CFA_SetLoc: { - operand_str = str8f(arena, "0x%X", inst.operands[0].u64); - pc = inst.operands[0].u64; - } break; - case DW_CFA_AdvanceLoc1: { - U64 delta = inst.operands[0].u64; - pc += delta; - operand_str = str8f(arena, "%+u `PC 0x%I64x`", delta, pc); - } break; - case DW_CFA_AdvanceLoc2: { - U64 delta = inst.operands[0].u64; - pc += delta; - operand_str = str8f(arena, "%+u `PC 0x%I64x`", delta, pc); - } break; - case DW_CFA_AdvanceLoc4: { - U64 delta = inst.operands[0].u64; - pc += delta; - operand_str = str8f(arena, "%+u `PC 0x%I64x`", delta, pc); - } break; - case DW_CFA_OffsetExt: { - U64 reg = inst.operands[0].u64; - S64 offset = (S64)inst.operands[1].u64; - operand_str = dw_string_from_reg_off(arena, arch, reg, offset); - } break; - case DW_CFA_RestoreExt: { operand_str = str8_zero(); } break; - case DW_CFA_Undefined: { - operand_str = str8f(arena, "%I64u", inst.operands[0].u64); - } break; - case DW_CFA_SameValue: { - operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, 0); - } break; - case DW_CFA_Register: { - operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].u64); - } break; - case DW_CFA_RememberState: { operand_str = str8_zero(); } break; - case DW_CFA_RestoreState: { operand_str = str8_zero(); } break; - case DW_CFA_DefCfa: { - operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].u64); - } break; - case DW_CFA_DefCfaRegister: { - operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, 0); - } break; - case DW_CFA_DefCfaOffset: { - operand_str = str8f(arena, "+%I64u", inst.operands[0].u64); - } break; - case DW_CFA_DefCfaExpr: { - operand_str = dw_string_from_expression(arena, inst.operands[0].block, cu_base, cie->address_size, arch, ver, ext, format); - } break; - case DW_CFA_Expr: { - String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, inst.operands[0].u64, 0); - String8 expr_str = dw_string_from_expression(scratch.arena, inst.operands[1].block, cu_base, cie->address_size, arch, ver, ext, format); - operand_str = str8f(arena, "%S expression %S", reg_str, expr_str); - } break; - case DW_CFA_OffsetExtSf: { - operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].s64); - } break; - case DW_CFA_DefCfaSf: { - operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].s64); - } break; - case DW_CFA_DefCfaOffsetSf: { operand_str = str8_zero(); } break; - case DW_CFA_ValOffset: { - operand_str = str8f(arena, "value 0x%I64x, offset %+I64d", inst.operands[0].u64, inst.operands[1].u64); - } break; - case DW_CFA_ValOffsetSf: { - operand_str = str8f(arena, "value %I64u, offset %+I64d", inst.operands[0].u64, inst.operands[1].s64); - } break; - case DW_CFA_ValExpr: { - String8 expr_str = dw_string_from_expression(scratch.arena, inst.operands[1].block, cu_base, cie->address_size, arch, ver, ext, format); - operand_str = str8f(arena, "value +%I64u, expression %S", inst.operands[0].u64, expr_str); - } break; - case DW_CFA_AdvanceLoc: { - U64 delta = inst.operands[0].u64; - pc += delta; - operand_str = str8f(arena, "+%I64u `PC 0x%I64x`", delta, pc); - } break; - case DW_CFA_Offset: { - U64 reg = inst.operands[0].u64; - S64 offset = (S64)inst.operands[1].u64; - operand_str = dw_string_from_reg_off(arena, arch, reg, offset); - } break; - case DW_CFA_Restore: { - operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, 0); - } break; - default: { - str8_list_pushf(arena, &list, "ERROR: unknown CFA opcode 0x%I64u", inst.opcode); - } goto exit; - } - - if (operand_str.size) { - str8_list_pushf(arena, &list, "DW_CFA_%S: %S", dw_string_from_cfa_opcode(inst.opcode), operand_str); - } else { - str8_list_pushf(arena, &list, "DW_CFA_%S", dw_string_from_cfa_opcode(inst.opcode)); - } - } - - exit:; - scratch_end(scratch); - return list; -} - -internal String8List -dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 addr_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); + 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; - String8 op_value = str8_zero(); - U64 size_param = 0; - B32 is_signed = 0; - switch (op) { + // 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: @@ -259,10 +34,11 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 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: { + case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: + { U64 x = op - DW_ExprOp_Lit0; - op_value = push_str8f(scratch.arena, "%I64u", x); - } break; + 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; @@ -274,35 +50,41 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 case DW_ExprOp_Const8S:size_param = 8; is_signed = 1; goto const_n; const_n: { - if (is_signed) { + if(is_signed) + { S64 x = 0; - cursor += str8_deserial_read(raw_data, cursor, &x, size_param, 1); + off += str8_deserial_read(data, off, &x, size_param, 1); x = extend_sign64(x, size_param); - op_value = push_str8f(scratch.arena, "%I64d", x); - } else { - U64 x = 0; - cursor += str8_deserial_read(raw_data, cursor, &x, size_param, 1); - op_value = push_str8f(scratch.arena, "%I64u", x); + operand_string = str8f(scratch.arena, "%I64d", x); } - } break; + 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: { + case DW_ExprOp_Addr: + { U64 addr = 0; - cursor += str8_deserial_read(raw_data, cursor, &addr, addr_size, 1); - op_value = push_str8f(scratch.arena, "%#I64x", addr); - } break; + off += str8_deserial_read(data, off, &addr, ctx->addr_size, 1); + operand_string = str8f(scratch.arena, "0x%I64x", addr); + }break; - case DW_ExprOp_ConstU: { + case DW_ExprOp_ConstU: + { U64 x = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, &x); - op_value = push_str8f(scratch.arena, "%I64u", x); - } break; + off += str8_deserial_read_uleb128(data, off, &x); + operand_string = str8f(scratch.arena, "%I64u", x); + }break; - case DW_ExprOp_ConstS: { + case DW_ExprOp_ConstS: + { S64 x = 0; - cursor += str8_deserial_read_sleb128(raw_data, cursor, &x); - op_value = push_str8f(scratch.arena, "%I64d", x); - } break; + 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: @@ -314,63 +96,74 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 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: { + 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; + 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: { + 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; + 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: { + 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; + 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); - op_value = str8_list_join(scratch.arena, &value_strings, &(StringJoin){.pre = str8_lit("{ "), .sep = str8_lit(", "), .post = str8_lit(" }")}); - } break; + operand_string = str8_list_join(scratch.arena, &value_strings, &(StringJoin){.pre = str8_lit("{ "), .sep = str8_lit(", "), .post = str8_lit(" }")}); + }break; - case DW_ExprOp_Piece: { + 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; + off += str8_deserial_read_uleb128(data, off, &size); + operand_string = str8f(scratch.arena, "%u", size); + }break; - case DW_ExprOp_BitPiece: { + 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 %I64u, bit offset %I64u", bit_size, bit_off); - } break; + 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: { + 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; + off += str8_deserial_read_struct(data, off, &stack_idx); + operand_string = str8f(scratch.arena, "stack index %u", stack_idx); + }break; - case DW_ExprOp_PlusUConst: { + case DW_ExprOp_PlusUConst: + { U64 addend = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, &addend); - op_value = push_str8f(arena, "addend %I64u", addend); - } break; + off += str8_deserial_read_uleb128(data, off, &addend); + operand_string = str8f(arena, "addend %I64u", addend); + }break; - case DW_ExprOp_Skip: { + 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; + off += str8_deserial_read_struct(data, off, &x); + operand_string = str8f(scratch.arena, "%+d bytes", x); + }break; - case DW_ExprOp_Bra: { + 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; + 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: @@ -382,1839 +175,544 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 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: { + 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; + 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: { + case DW_ExprOp_FBReg: + { S64 reg_off = 0; - cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); - op_value = push_str8f(scratch.arena, "offset %I64d", reg_off); - } break; + off += str8_deserial_read_sleb128(data, off, ®_off); + operand_string = str8f(scratch.arena, "frame base offset %I64d", reg_off); + }break; - case DW_ExprOp_BRegX: { + 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; + 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: { + 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; + off += str8_deserial_read_struct(data, off, &x); + operand_string = str8f(scratch.arena, "%u", x); + }break; - case DW_ExprOp_Call2: { + 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: { + off += str8_deserial_read_struct(data, off, &x); + operand_string = 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: { + off += str8_deserial_read_struct(data, off, &x); + operand_string = 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, "%I64u", x); - } break; + off += dw2_read_fmt_u64(data, off, ctx->format, &x); + operand_string = str8f(scratch.arena, "%I64u", x); + }break; case DW_ExprOp_ImplicitPointer: - case DW_ExprOp_GNU_ImplicitPointer: { + case DW_GNU_ExprOp_ImplicitPointer: + { U64 info_off = 0; - cursor += str8_deserial_read_dwarf_uint(raw_data, cursor, format, &info_off); + off += dw2_read_fmt_u64(data, off, ctx->format, &info_off); S64 ptr = 0; - cursor += str8_deserial_read_sleb128(raw_data, cursor, &ptr); - - op_value = push_str8f(scratch.arena, ".debug_info+%#I64x, ptr %I64x", info_off, ptr); + 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_ExprOp_GNU_Convert: { + case DW_GNU_ExprOp_Convert: + { U64 type_cu_off = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, &type_cu_off); - op_value = push_str8f(scratch.arena, "TypeCuOff %#I64x", cu_base + type_cu_off); - } break; - case DW_ExprOp_GNU_ParameterRef: { + 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; - cursor += str8_deserial_read_struct(raw_data, cursor, &cu_off); - op_value = push_str8f(scratch.arena, "CuOff %#x", cu_base + cu_off); - } break; + 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_ExprOp_GNU_DerefType: { - U8 deref_size = 0; + case DW_GNU_ExprOp_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 %#I64x", deref_size, cu_base + type_cu_off); - } break; + 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_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); + 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(", ")}); - op_value = push_str8f(scratch.arena, "TypeCuOff %#I64x, Const Value { %S }", cu_base + type_cu_off, const_value_str); - cursor += const_value_size; - } break; + 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_ExprOp_GNU_RegvalType: { + case DW_GNU_ExprOp_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 %#I64x", dw_string_from_register(scratch.arena, arch, reg_idx), cu_base + type_cu_off); - } break; + 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_ExprOp_GNU_EntryValue: { + case DW_GNU_ExprOp_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, addr_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; + 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: { + case DW_ExprOp_Addrx: + { U64 addr = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, &addr); - op_value = push_str8f(scratch.arena, "%#I64x", 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; + off += str8_deserial_read_uleb128(data, off, &addr); + operand_string = str8f(scratch.arena, "%#I64x", addr); + }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); + // 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; } -internal String8 -dw_string_from_reg_off(Arena *arena, Arch arch, DW_Reg 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; - if (reg_off != 0) { - result = push_str8f(arena, "%S%+I64d", reg_str, reg_off); - } else { - result = reg_str; - } - scratch_end(scratch); - return result; -} - -internal String8 -dw_string_from_expression(Arena *arena, String8 expr, U64 cu_base, U64 addr_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, expr, cu_base, addr_size, arch, ver, ext, format); - String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); - return result; -} - -internal String8 -dw_string_from_cfa(Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFA cfa) -{ - String8 cfa_str = str8_lit("???"); - switch (cfa.rule) { - case DW_CFA_Rule_Null: {} break; - case DW_CFA_Rule_RegOff: { cfa_str = dw_string_from_reg_off(arena, arch, cfa.reg, cfa.off); } break; - case DW_CFA_Rule_Expression: { cfa_str = dw_string_from_expression(arena, cfa.expr, max_U64, address_size, arch, version, ext, format); } break; - default: { InvalidPath; } break; - } - return cfa_str; -} - -internal String8 -dw_string_from_cfi_row(Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFI_Row *row) -{ - Temp scratch = scratch_begin(&arena, 1); - String8List cfi_regs_list = {0}; - U64 reg_count = dw_reg_count_from_arch(arch); - for EachIndex(reg_idx, reg_count) { - DW_CFI_Register *cfi_reg = &row->regs[reg_idx]; - String8 rule_str = str8_lit("???"); - switch (cfi_reg->rule) { - case DW_CFI_RegisterRule_Undefined: { - rule_str = str8f(scratch.arena, "Undefined(%S)", dw_string_from_register(scratch.arena, arch, cfi_reg->n)); - } break; - case DW_CFI_RegisterRule_SameValue: { - rule_str = str8_zero(); - } break; - case DW_CFI_RegisterRule_Offset: { - rule_str = str8f(scratch.arena, "[CFA%+I64d]", cfi_reg->n); - } break; - case DW_CFI_RegisterRule_ValOffset: { - rule_str = str8f(scratch.arena, "Val(CFA%+I64d)", cfi_reg->n); - } break; - case DW_CFI_RegisterRule_Register: { - rule_str = str8f(scratch.arena, "Register(%S)", dw_string_from_register(scratch.arena, arch, cfi_reg->n)); - } break; - case DW_CFI_RegisterRule_Expression: { - rule_str = str8f(scratch.arena, "Expression(%S)", dw_string_from_expression(scratch.arena, cfi_reg->expr, max_U64, address_size, arch, version, ext, format)); - } break; - case DW_CFI_RegisterRule_ValExpression: { - rule_str = str8f(scratch.arena, "ValExpression(%S)", dw_string_from_expression(scratch.arena, cfi_reg->expr, max_U64, address_size, arch, version, ext, format)); - } break; - case DW_CFI_RegisterRule_Architectural: { - rule_str = str8_lit("???"); - } break; - default: { InvalidPath; } break; - } - - if (rule_str.size) { - str8_list_pushf(scratch.arena, &cfi_regs_list, "%S: %S", dw_string_from_register(scratch.arena, arch, reg_idx), rule_str); - } - } - - String8 string = str8_list_join(arena, &cfi_regs_list, &(StringJoin){.sep=str8_lit(", ")}); - - scratch_end(scratch); - return string; -} - -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; -} - -internal String8 -dw_string_from_attrib_value(Arena *arena, DW_Raw *input, Arch arch, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8List attrib_fmt = {0}; - - // rjf: log attrib's value based on vlass - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - switch(value_class) - { - default: {str8_list_pushf(scratch.arena, &attrib_fmt, "`unknown value class`");}break; - case DW_AttribClass_Undefined: {str8_list_pushf(scratch.arena, &attrib_fmt, "`undefined value class`");}break; - case DW_AttribClass_Address: {str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", dw_address_from_attrib(input, cu, attrib));}break; - case DW_AttribClass_Const: {str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", dw_const_u64_from_attrib(input, cu, attrib));}break; - case DW_AttribClass_Block: - { - String8 block = dw_block_from_attrib(input, cu, attrib); - String8List block_strs = numeric_str8_list_from_data(scratch.arena, 16, block, 1); - String8 block_str = str8_list_join(scratch.arena, &block_strs, &(StringJoin){.sep = str8_lit(", ")}); - str8_list_pushf(scratch.arena, &attrib_fmt, "{ %S }", block_str); - }break; - case DW_AttribClass_ExprLoc: - { - String8 exprloc = dw_exprloc_from_attrib(input, cu, attrib); - String8 exprloc_str = dw_single_line_string_from_expression(scratch.arena, exprloc, cu->info_range.min, cu->address_size, arch, cu->version, cu->ext, cu->format); - str8_list_pushf(scratch.arena, &attrib_fmt, "{ %S }", exprloc_str); - }break; - case DW_AttribClass_Flag: - { - B32 flag = dw_flag_from_attrib(input, cu, attrib); - str8_list_pushf(scratch.arena, &attrib_fmt, "%I64u (%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) - { - str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", attrib->form.sec_offset); - } - else - { - str8_list_pushf(scratch.arena, &attrib_fmt, "`unexpected form kind %S`", dw_string_from_form_kind(scratch.arena, cu->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 = cu->info_range.min + attrib->form.ref; - str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", info_off); - if(!contains_1u64(cu->info_range, info_off)) - { - str8_list_pushf(scratch.arena, &attrib_fmt, ": `(out of this cu's bounds)`"); - } - } - else - { - str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x", attrib->form.ref); - } - }break; - case DW_AttribClass_String: - { - if(attrib->form.kind == DW_Form_Strp || attrib->form.kind == DW_Form_LineStrp || attrib->form.kind == DW_Form_StrpSup) - { - str8_list_pushf(scratch.arena, &attrib_fmt, "0x%I64x ", attrib->form.sec_offset); - } - String8 string = dw_string_from_attrib(input, cu, attrib); - str8_list_pushf(scratch.arena, &attrib_fmt, "\"%S\"", string); - }break; - } - - // rjf: extend attrib's value with enum info - { - String8 enum_info = {0}; - switch(attrib->attrib_kind) - { - case DW_AttribKind_Language: - { - DW_Language lang = dw_const_u64_from_attrib(input, cu, attrib); - enum_info = dw_string_from_language(scratch.arena, lang); - }break; - case DW_AttribKind_DeclFile: - { - U64 file_idx = dw_const_u64_from_attrib(input, cu, attrib); - DW_LineFile *file = dw_file_from_attrib(cu, line_vm, attrib); - if(file != 0) - { - enum_info = dw_path_from_file(scratch.arena, line_vm->header.dir_table, file); - } - }break; - case DW_AttribKind_DeclLine: - { - enum_info = str8f(scratch.arena, "%I64u", dw_const_u64_from_attrib(input, cu, attrib)); - }break; - case DW_AttribKind_Inline: - { - DW_InlKind inl = dw_const_u64_from_attrib(input, cu, attrib); - enum_info = dw_string_from_inl(scratch.arena, inl); - }break; - case DW_AttribKind_Accessibility: - { - DW_AccessKind access = dw_const_u64_from_attrib(input, cu, attrib); - enum_info = dw_string_from_access_kind(scratch.arena, access); - }break; - case DW_AttribKind_CallingConvention: - { - DW_CallingConventionKind calling_convetion = dw_const_u64_from_attrib(input, cu, attrib); - enum_info = dw_string_from_calling_convetion(scratch.arena, calling_convetion); - }break; - case DW_AttribKind_Encoding: - { - DW_ATE encoding = dw_const_u64_from_attrib(input, cu, attrib); - enum_info = dw_string_from_attrib_type_encoding(scratch.arena, encoding); - }break; - case DW_AttribKind_Visibility: - { - DW_Vis vis = dw_const_u64_from_attrib(input, cu, attrib); - enum_info = dw_string_from_attrib_visibility(scratch.arena, vis); - }break; - } - - if(enum_info.size) - { - str8_list_pushf(scratch.arena, &attrib_fmt, " `%S`", enum_info); - } - } - - String8 result = str8_list_join(arena, &attrib_fmt, 0); - - scratch_end(scratch); - return result; -} - -internal -DW_PRINTER(dw_print_abbrev) -{ - DW_Raw *input = dumper->input; - - 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); - dw_printf("abbrev: // abbrev[%I64u] abbrev_off: 0x%I64x \n {\n", idx, id_off); - dw_indent(); - dw_printf("id: %I64u tag_kind: %S has_children: %s\n", id, dw_string_from_tag_kind(temp.arena, tag), has_children ? "true" : "false"); - U64 attrib_kind_max_size = 0; - U64 form_kind_max_size = 0; - { - for(U64 off = cursor;;) - { - U64 attrib_id = 0, form_id = 0; - off += str8_deserial_read_uleb128(abbrev.data, off, &attrib_id); - off += str8_deserial_read_uleb128(abbrev.data, off, &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); - attrib_kind_max_size = Max(attrib_kind_max_size, attrib_str.size); - form_kind_max_size = Max(form_kind_max_size, form_str.size); - } - } - 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); - - String8List fmt = {0}; - str8_list_pushf(temp.arena, &fmt, "%S%.*s", attrib_str, attrib_kind_max_size - attrib_str.size, g_spaces); - str8_list_pushf(temp.arena, &fmt, "%S%.*s", form_str, form_kind_max_size - form_str.size, g_spaces); - String8 value = str8_list_join(temp.arena, &fmt, &(StringJoin){.sep=str8_lit(" ")}); - dw_printf("attrib: { %S } // 0x%I64x\n", value, attrib_off); - } - dw_unindent(); - dw_printf("}\n"); - temp_end(temp); - } - scratch_end(scratch); -} - -internal void -dw_print_tag(Arena *arena, String8List *strings, int indent, Arch arch, DW_Raw *input, DW_CompUnit *cu, DW_LineVM *line_vm, DW_TagNode *root) -{ - Temp scratch = scratch_begin(0, 0); - - for (DW_TagNode *n = root; n != 0; n = n->sibling) { - DW_Tag *tag = &n->tag; - - // compute columns' max widths - U64 attrib_name_max_size = 0, form_kind_max_size = 0, value_max_size = 0; - for EachNode(attrib_n, DW_AttribNode, tag->attribs.first) - { - Temp attrib_temp = temp_begin(scratch.arena); - attrib_name_max_size = Max(attrib_name_max_size, dw_string_from_attrib_kind (attrib_temp.arena, cu->version, cu->ext, attrib_n->v.attrib_kind).size); - form_kind_max_size = Max(form_kind_max_size, dw_string_from_form_kind (attrib_temp.arena, cu->version, attrib_n->v.form.kind).size); - value_max_size = Max(value_max_size, dw_string_from_attrib_value(attrib_temp.arena, input, arch, cu, line_vm, &attrib_n->v).size); - temp_end(attrib_temp); - } - attrib_name_max_size = Min(40, attrib_name_max_size); - form_kind_max_size = Min(20, form_kind_max_size); - value_max_size = Min(80, value_max_size); - - dw_printf("tag: // info_off: 0x%I64x abbrev_id: %I64u\n", tag->info_off, tag->abbrev_id); - dw_printf("{\n"); - dw_indent(); - dw_printf("kind: %S\n", dw_string_from_tag_kind(scratch.arena, tag->kind)); - for EachNode(attrib_n, DW_AttribNode, tag->attribs.first) { - DW_Attrib *attrib = &attrib_n->v; - - String8 attrib_kind_str = dw_string_from_attrib_kind(scratch.arena, cu->version, cu->ext, attrib->attrib_kind); - String8 form_kind_str = dw_string_from_form_kind(scratch.arena, cu->version, attrib->form.kind); - String8 value_str = dw_string_from_attrib_value(scratch.arena, input, arch, cu, line_vm, attrib); - - String8List fmt = {0}; - str8_list_pushf(scratch.arena, &fmt, "%S%.*s", attrib_kind_str, attrib_kind_str.size <= attrib_name_max_size ? attrib_name_max_size - attrib_kind_str.size : 0, g_spaces); - str8_list_pushf(scratch.arena, &fmt, "%S%.*s", form_kind_str, form_kind_str.size <= form_kind_max_size ? form_kind_max_size - form_kind_str.size : 0, g_spaces); - str8_list_pushf(scratch.arena, &fmt, "%S%.*s", value_str, value_str.size <= value_max_size ? value_max_size - value_str.size : 0, g_spaces); - String8 attrib_str = str8_list_join(scratch.arena, &fmt, &(StringJoin){.sep = str8_lit(" ")}); - - dw_printf("attrib: { %S } // info_off: 0x%I64x\n", attrib_str, attrib->info_off); - } - - if (tag->has_children) { - dw_print_tag(arena, strings, indent, arch, input, cu, line_vm, n->first_child); - } - - dw_unindent(); - dw_printf("}\n"); - } - - scratch_end(scratch); -} - -internal -DW_PRINTER(dw_print_info) -{ - DW_Raw *input = dumper->input; - Arch arch = dumper->arch; - HashTable *line_vm_map = dw_get_line_vm_map(dumper); - Rng1U64Array cu_ranges = dw_get_info_ranges(dumper); - DW_CompUnit *cu_arr = dw_get_cu_arr(dumper); - DW_TagTree *tag_trees = dw_get_tag_trees(dumper); - - Temp scratch = scratch_begin(&arena, 1); - for EachIndex(cu_idx, cu_ranges.count) { - Rng1U64 cu_range = cu_ranges.v[cu_idx]; - DW_CompUnit *cu = &cu_arr[cu_idx]; - String8 cu_dir = dw_string_from_tag_attrib_kind (input, cu, cu->tag, DW_AttribKind_CompDir ); - String8 cu_name = dw_string_from_tag_attrib_kind (input, cu, cu->tag, DW_AttribKind_Name ); - String8 stmt_list = dw_line_ptr_from_tag_attrib_kind(input, cu, cu->tag, DW_AttribKind_StmtList); - - DW_LineVM *line_vm = 0; - if (stmt_list.str) { - line_vm = hash_table_search_raw_raw(line_vm_map, stmt_list.str); - if (line_vm == 0) { - line_vm = dw_line_vm_init(input, cu); - // decode line table to find all the defined files, in version 5 this behaviour was deprecated - if (cu->version < DW_Version_5) { - while (dw_line_vm_step(line_vm)); - } - hash_table_push_raw_raw(scratch.arena, line_vm_map, stmt_list.str, line_vm); - } - } - - dw_printf("cu: // compile_unit[%I64u] @ %r (%M)\n", cu_idx, cu_range, dim_1u64(cu->info_range)); - dw_printf("{\n"); - dw_indent(); - dw_printf("format: %S\n", dw_string_from_format(cu->format)); - dw_printf("version: %u\n", cu->version); - dw_printf("kind: %S\n", dw_string_from_comp_unit_kind(scratch.arena, cu->kind)); - dw_printf("address_size: %I64u\n", cu->address_size); - dw_printf("abbrev_off: 0x%I64x\n", cu->abbrev_off); - dw_print_tag(arena, strings, indent, arch, input, cu, line_vm, tag_trees[cu_idx].root); - dw_unindent(); - dw_printf("} // compile_unit[/%u]\n", cu_idx); - } -} - -DW_PRINTER(dw_print_line) -{ - DW_Raw *input = dumper->input; - B32 is_verbose = dumper->is_verbose; - DW_CompUnit *cu_arr = dw_get_cu_arr(dumper); - Temp scratch = scratch_begin(&arena, 1); - Rng1U64Array unit_ranges = dw_unit_ranges_from_data_arr(scratch.arena, input->sec[DW_Section_Line].data); - for EachIndex(unit_idx, unit_ranges.count) - { - Temp unit_temp = temp_begin(scratch.arena); - - DW_CompUnit *cu = &cu_arr[unit_idx]; - DW_LineVM *vm = dw_line_vm_init(input, cu); - - // rjf: begin logging line table - dw_printf("line_table: // line_table[%I64u]\n", unit_idx); - dw_printf("{\n"); - dw_indent(); - { - // rjf: log line table header - dw_printf("header:\n"); - dw_printf("{\n"); - dw_indent(); - { - String8List opcode_length_strings = numeric_str8_list_from_data(unit_temp.arena, 16, str8(vm->header.opcode_lens, vm->header.num_opcode_lens), 1); - String8 opcode_lengths_string = str8_list_join(arena, &opcode_length_strings, &(StringJoin){.sep = str8_lit(", ")}); - dw_printf("version: %u\n", vm->header.version ); - dw_printf("line_table_size: %I64u\n", vm->header.unit_length ); - dw_printf("address_size: %u\n", vm->header.address_size ); - dw_printf("segment_selector_size: %u\n", vm->header.segment_selector_size); - dw_printf("header_length: %I64u\n", vm->header.header_length ); - dw_printf("min_instruction_length: %u\n", vm->header.min_inst_len ); - dw_printf("max_ops_for_instruction: %u\n", vm->header.max_ops_for_inst ); - dw_printf("default_is_stmt: %u\n", vm->header.default_is_stmt ); - dw_printf("line_base: %d\n", vm->header.line_base ); - dw_printf("line_range: %u\n", vm->header.line_range ); - dw_printf("opcode_base: %u\n", vm->header.opcode_base ); - dw_printf("opcode_lengths: { %S }\n", opcode_lengths_string ); - } - dw_unindent(); - dw_printf("}\n"); - - // rjf: log directory table - dw_printf("directory_table:\n"); - dw_printf("{\n"); - dw_indent(); - { - dw_printf("// %-4s %-30s\n", "No.", "Name"); - dw_printf("// ---- ------------------------------\n"); - for EachIndex(dir_idx, vm->header.dir_table.count) - { - dw_printf("{ %-4I64u %-30S }\n", dir_idx, vm->header.dir_table.v[dir_idx]); - } - } - dw_unindent(); - dw_printf("}\n"); - - // rjf: log file table - dw_printf("file_table:\n"); - dw_printf("{\n"); - dw_indent(); - { - dw_printf("// %-4s %-8s %-8s %-33s %-8s %-20s\n", "No.", "Dir No.", "Time", "MD5", "Size", "Path"); - dw_printf("// ---- -------- -------- --------------------------------- -------- --------------------\n"); - for EachIndex(file_idx, vm->header.file_table.count) - { - DW_LineFile *file = &vm->header.file_table.v[file_idx]; - dw_printf("{ %-4I64u %-8I64u %-8I64u %016I64x-%016I64x %-8I64u %-20S }\n", - file_idx, - file->dir_idx, - file->time_stamp, - file->md5.u64[1], - file->md5.u64[0], - file->size, - file->path); - } - } - dw_unindent(); - dw_printf("}\n"); - - // rjf: log opcodes - dw_printf("line_table:\n"); - dw_printf("{\n"); - dw_indent(); - { - dw_printf("//\n"); - dw_printf("// %-16s %-8s %-4s %-5s %-3s %-7s %-16s\n", "Address", "Line", "Col", "File", "ISA", "Discrim", "Flags"); - dw_printf("// ---------------- -------- ---- ----- --- ------- ----------------\n"); - - for(;;) - { - U64 global_opcode_off = unit_ranges.v[unit_idx].min + vm->cursor; - - if( ! dw_line_vm_step(vm)) { break; } - - Temp opcode_temp = temp_begin(unit_temp.arena); - String8List opcode_fmt = {0}; - - // opcode offset - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%08I64x:", global_opcode_off); - - // push opcode id - if (vm->opcode != 0) { - String8 opcode_str = dw_string_from_std_opcode(opcode_temp.arena, vm->opcode); - str8_list_pushf(arena, &opcode_fmt, "%-11S:", opcode_str); - } - - // print operands - switch(vm->opcode) - { - default: - { - if(vm->opcode >= vm->header.opcode_base) - { - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "advance line by %I64d, advance address by %I64d", vm->line_advance, vm->addr_advance); - } - else - { - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "skipping %I64x unknown opcodes", vm->header.opcode_lens[vm->opcode - 1]); - } - }break; - case DW_StdOpcode_Copy: - { - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "Line = %I64u, Column = %I64u, Address = %#I64x", vm->state.line, vm->state.column, vm->state.address); - }break; - case DW_StdOpcode_AdvancePc: - { - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "advance %#I64x ; current address %#I64x", vm->operands[0].u64, vm->state.address); - }break; - case DW_StdOpcode_AdvanceLine: - { - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "advance %I64d ; current line %I64u", vm->operands[0].s64, vm->state.line); - }break; - case DW_StdOpcode_SetFile: - { - DW_LineFile *file = dw_line_vm_find_file(vm, vm->state.file_index); - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%I64u \"%S\"", vm->state.file_index, dw_path_from_file(opcode_temp.arena, vm->header.dir_table, file)); - }break; - case DW_StdOpcode_SetColumn: - { - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%I64u", vm->state.column); - }break; - case DW_StdOpcode_NegateStmt: - { - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "is_stmt = %u", vm->state.is_stmt); - }break; - case DW_StdOpcode_SetBasicBlock: - { - }break; - case DW_StdOpcode_ConstAddPc: - { - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%I64d ; address %#I64x", vm->advance, vm->state.address); - }break; - case DW_StdOpcode_FixedAdvancePc: - { - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%I64u", vm->operands[0].u64); - }break; - case DW_StdOpcode_SetPrologueEnd: - { - }break; - case DW_StdOpcode_SetEpilogueBegin: - { - }break; - case DW_StdOpcode_SetIsa: - { - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%I64u", vm->state.isa); - }break; - case DW_StdOpcode_ExtendedOpcode: - { - str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%S*", dw_string_from_ext_opcode(opcode_temp.arena, vm->ext_opcode)); - //str8_list_pushf(opcode_temp.arena, &opcode_fmt, "length: %u", length); - switch(vm->ext_opcode) - { - case DW_ExtOpcode_EndSequence: {} break; - case DW_ExtOpcode_SetAddress: { str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%#I64x", vm->operands[0].u64); } break; - case DW_ExtOpcode_DefineFile: { str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%S Dir: %I64u, Time: %I64u, Size: %I64u", - vm->operands[0].string, vm->operands[1].u64, vm->operands[2].u64, vm->operands[3].u64); } break; - case DW_ExtOpcode_SetDiscriminator: { str8_list_pushf(arena, &opcode_fmt, "%I64u", vm->state.discriminator); }break; - } - }break; - } - - if(is_verbose) - { - String8 string = str8_list_join(opcode_temp.arena, &opcode_fmt, &(StringJoin){.sep=str8_lit(" ")}); - dw_printf("// %S\n", string); - } - - if(vm->new_line) { - String8List l = {0}; - if(vm->state.is_stmt) - { - str8_list_pushf(opcode_temp.arena, &l, "is_stmt"); - } - if(vm->state.end_sequence) - { - str8_list_pushf(opcode_temp.arena, &l, "end_seq"); - } - String8 flags = str8_list_join(opcode_temp.arena, &l, &(StringJoin){.sep = str8_lit("|")}); - - dw_printf("{ %#016I64x %8I64u %4I64u %5I64u %3I64u %7I64u %-16S } %s\n", vm->state.address, vm->state.line, vm->state.column, vm->state.file_index, vm->state.isa, vm->state.discriminator, flags, vm->new_seq ? "// new seq" : ""); - } - - temp_end(opcode_temp); - } - - if(vm->error.size) - { - dw_printf("ERROR: Line VM failed stepping @ 0x%I64x\n", vm->cursor); - } - } - dw_unindent(); - dw_printf("}\n"); - - temp_end(unit_temp); - } - dw_unindent(); - dw_printf("}\n"); - } - scratch_end(scratch); -} - -DW_PRINTER(dw_print_strings) -{ - DW_Raw *input = dumper->input; - 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); - dw_printf(" { 0x%08I64x %I64u \"%S\" }\n", cursor, string.size, string); - } -} - -DW_PRINTER(dw_print_frame) -{ - DW_Raw *input = dumper->input; - Arch arch = dumper->arch; - Temp scratch = scratch_begin(&arena, 1); - HashTable *cie_ht = hash_table_init(scratch.arena, 0x2000); - String8 debug_frame = input->sec[DW_Section_Frame].data; - U64 addr_size = byte_size_from_arch(arch); - - // make offset -> CIE hash table - 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_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); - if (dw_parse_cie(raw_cie, desc.format, arch, cie)) { - hash_table_push_u64_raw(scratch.arena, cie_ht, cursor, cie); - } else { - arena_pop_to(scratch.arena, restore_pos); - } - } - } - - 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); - String8 raw_desc = str8_substr(debug_frame, desc.entry_range); - switch (desc.type) { - 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); - - dw_printf("CIE: // entry range: %r\n", desc.entry_range); - dw_printf("{\n"); - dw_printf(" Format: %S\n", dw_string_from_format(desc.format)); - dw_printf(" Version: %u\n", cie.version); - dw_printf(" Aug string: \"%S\"\n", cie.aug_string); - dw_printf(" Code align: %I64u\n", cie.code_align_factor); - dw_printf(" Data align: %I64d\n", cie.data_align_factor); - dw_printf(" Return addr reg: %u\n", cie.ret_addr_reg); - if (cie.version > DW_Version_3) { - dw_printf(" Address size: %u\n", cie.address_size); - dw_printf(" Segment selector size: %u\n", cie.segment_selector_size); - } - dw_printf(" Initial Insturction:\n"); - dw_printf(" {\n"); - for EachNode(n, String8Node, init_insts_str_list.first) { dw_printf(" %S\n", n->string); } - dw_printf(" }\n"); - dw_printf("}\n"); - } else { - dw_printf("ERROR: unable to parse CIE @ %I64x\n", desc.entry_range.min); - } - } break; - 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); - DW_CIE cie = {0}; - dw_parse_cie(cie_data, cie_desc.format, arch, &cie); - - DW_FDE fde = {0}; - if (dw_parse_fde(raw_desc, desc.format, &cie, &fde)) { - DW_Version version = DW_Version_5; - DW_Ext ext = DW_Ext_All; - String8List insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, version, ext, fde.format, fde.pc_range.min, &cie, dw_decode_ptr_debug_frame, &cie, fde.insts); - dw_printf("FDE: // entry range: %r\n", desc.entry_range); - dw_printf("{\n"); - { - dw_printf(" Format: %S\n", dw_string_from_format(fde.format)); - dw_printf(" CIE pointer: 0x%I64x\n", fde.cie_pointer); - dw_printf(" PC range: %r\n", fde.pc_range); - dw_printf(" Instructions:\n"); - dw_printf(" {\n"); - for EachNode(n, String8Node, insts_str_list.first) { dw_printf(" %S\n", n->string); } - dw_printf(" }\n"); - } - dw_printf(" Unwind:\n"); - dw_printf(" {\n"); - DW_CFI_Unwind *cfi_unwind = dw_cfi_unwind_init(scratch.arena, arch, &cie, &fde, dw_decode_ptr_debug_frame, &cie); - do { - String8 cfa_str = dw_string_from_cfa(scratch.arena, arch, cie.address_size, version, ext, fde.format, cfi_unwind->row->cfa); - String8 cfi_regs_str = dw_string_from_cfi_row(scratch.arena, arch, cie.address_size, version, ext, fde.format, cfi_unwind->row); - dw_printf(" { PC: 0x%I64x, CFA: %-7S, Rules: { %S }\n", cfi_unwind->pc, cfa_str, cfi_regs_str); - } while (dw_cfi_next_row(scratch.arena, cfi_unwind)); - dw_printf(" }\n"); - - dw_printf("}\n"); - } else { - dw_printf("ERROR: unable to parse FDE @ %I64x\n", desc.entry_range.min); - } - } break; - } - } -} - -#if 0 -internal -DW_PRINTER(dw_print_debug_loc) -{ - DW_Raw *input = dumper->input; - DW_TagTree *tag_trees = dw_get_tag_trees(dumper); - 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); - - // TODO: warn about overlaps in ranges - - Rng1U64Array info_ranges = dw_get_info_ranges(dumper); - DW_CompUnit *cu_arr = dw_get_cu_arr(dumper); - - // parse debug_info for attributes with LOCLIST and store .debug_loc offsets - U64List *loc_lists = push_array(scratch.arena, U64List, info_ranges.count); - for EachIndex(cu_idx, info_ranges.count) { - DW_CompUnit *cu = &cu_arr[cu_idx]; - DW_TagTree *tag_tree = tag_trees[cu_idx]; - for (D2R_TagIterator *it = d2r_tag_iterator_init(scratch.arena, tag_tree); - it->tag_node != 0; - d2r_tag_iterator_next(it)) { - DW_TagNode *tag_node = it->tag_node; - DW_Tag tag = tag_node->tag; - for EachNode(attrib_n, DW_AttribNode, tag.attribs.first) { - DW_Attrib *attrib = &attrib_n->v; - DW_AttribClass attrib_class = dw_attrib_class_from_attrib(cu->version, cu->ext, attrib->kind); - B32 is_sect_offset = attrib_class == DW_AttribClass_LocListPtr || (attrib_class == DW_AttribClass_LocList && attrib->form.kind == DW_Form_SecOffset); - B32 is_sect_index = attrib_class == DW_AttribClass_LocList && attrib->form.kind == DW_Form_LocListx; - if (is_sect_offset) { - U64 sec_offset = dw_interp_sec_offset(attrib->form.kind, attrib->form); - u64_list_push(scratch.arena, &loc_lists[cu_idx], attrib->value.v[0]); - } else if (is_sect_index) { - // TODO: support for section indexing - } - } - } - } - - void *base = dw_base_from_sec(input, DW_Section_Loc); - Rng1U64 range = dw_range_from_sec(input, DW_Section_Loc); - - dw_printf(".debug_loc"); - dw_indent(); - dw_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, "%08I64x", 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, ""); - } 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, "%08I64x %08I64x %S", min, max, expression); - } - - // print entry - String8 print = str8_list_join(range_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); - dw_printf("%S", print); - - // cleanup temp - temp_end(range_temp); - - // exit check - if (is_list_end) { - break; - } - } - } - - temp_end(locs_temp); - } - dw_unindent(); - - dw_unindent(); - scratch_end(scratch); -} -#endif - -#if 0 -internal void -dw_print_debug_ranges(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *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; - } - } - } - - dw_printf("# %S", sections->v[DW_Section_Ranges].name); - dw_indent(); - dw_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, "%08I64x", 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, ""); - } 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, "%08I64x %08I64x", min, max); - } - - // print entry - String8 print = str8_list_join(range_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); - dw_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 g_dw_indent, DW_Raw *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); - - dw_printf("# %S", sections->v[DW_Section_ARanges].name); - dw_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; - } - - dw_printf("Unit length: %I64u", unit_length); - dw_printf("Version: %u", version); - dw_printf("Debug info offset: %#I64x", debug_info_offset); - dw_printf("Address size: %u", address_size); - dw_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)"); - } - - dw_indent(); - dw_printf("%-8s %-8s", "Offset", "Range"); - for (; cursor < unit_opl; ) { - Temp temp = temp_begin(arena); - - String8List list = {0}; - - str8_list_pushf(temp.arena, &list, "%08I64x", 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, ""); - } else { - if (segment_selector != 0) { - str8_list_pushf(temp.arena, &list, "%02I64u:", segment_selector); - } - str8_list_pushf(temp.arena, &list, "%I64x-%I64x", address, address+length); - } - - String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ") }); - dw_printf("%S", print); - - temp_end(temp); - } - dw_unindent(); - rd_newline(); - } - dw_unindent(); - - scratch_end(scratch); -#endif -} - -internal void -dw_print_debug_addr(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *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); - - dw_printf("# %S", sections->v[DW_Section_Addr].name); - dw_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; - } - - dw_printf("Unit @ %#I64x, length %I64u", unit_offset, unit_length); - dw_printf("Version: %u", version); - dw_printf("Address size: %u", address_size); - dw_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)"); - } - - dw_indent(); - dw_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, ""); - } else { - if (segment_selector != 0) { - str8_list_pushf(temp.arena, &list, "%02u:", segment_selector); - } - str8_list_pushf(temp.arena, &list, "%I64x", address); - } - - String8 print = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(" ")}); - dw_printf("%S", print); - - temp_end(temp); - } - dw_unindent(); - rd_newline(); - } - dw_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 g_dw_indent, DW_Raw *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); - - dw_printf("# %S", sections->v[DW_Section_LocLists].name); - dw_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); - - dw_printf("Unit @ %#I64x, length %I64u", unit_offset, unit_length); - dw_printf("Version: %u", version); - dw_printf("Address size: %u", address_size); - dw_printf("Segment selector size: %u", segment_selector_size); - dw_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) { - dw_printf("Offsets:"); - dw_indent(); - dw_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); - dw_printf("%-8I64u %I64x", offset_idx, offset+past_header_offset); - } - dw_unindent(); - } - - dw_printf("Locations:"); - dw_indent(); - dw_printf("%-8s %-8s", "Offset", "Location"); - for (; cursor < unit_opl; ) { - Temp temp = temp_begin(arena); - - String8List list = {0}; - - str8_list_pushf(temp.arena, &list, "%08I64x", 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, "%I64x", 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, "%I64x, %I64x", 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, "%I64x, %I64x", 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, "%I64x", 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, "%I64x, %I64x", 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, "%I64x, %I64x", 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(" ")}); - dw_printf("%S", print); - - temp_end(temp); - } - dw_unindent(); - rd_newline(); - } - dw_unindent(); - - scratch_end(scratch); -#endif -} - -internal void -dw_print_debug_rnglists(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *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); - - dw_printf("# %S", sections->v[DW_Section_RngLists].name); - dw_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); - - dw_printf("Unit @ %#I64x, length %I64u", unit_offset, unit_length); - dw_printf("Version: %u", version); - dw_printf("Address size: %u", address_size); - dw_printf("Segment selector size: %u", segment_selector_size); - dw_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) { - dw_printf("Offsets:"); - dw_indent(); - dw_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); - dw_printf("%-8I64u %I64x", offset_idx, offset+past_header_offset); - } - dw_unindent(); - } - - dw_printf("Ranges:"); - dw_indent(); - dw_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, "%08I64x", 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, "%I64x", 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, "%I64x", 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, "%I64x, %I64x", 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, "%I64x, %I64x", 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, "%I64x, %I64x", 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, "%I64x, %I64x", 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, "%I64x, %I64x", start, length); - } break; - } - - // output row - String8 print = str8_list_join(temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); - dw_printf("%S", print); - - temp_end(temp); - } - dw_unindent(); - rd_newline(); - } - dw_unindent(); - - scratch_end(scratch); -#endif -} - -internal void -dw_format_string_table(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *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); - - dw_printf("# %S", sections->v[sec].name); - dw_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); - - dw_printf("Unit @ %#I64x, length %I64u", unit_offset, unit_length); - dw_printf("Version: %u", version); - dw_printf("Debug info offset: %#I64x", debug_info_offset); - dw_printf("Debug info length: %#I64x", debug_info_length); - - dw_printf("Entries:"); - dw_indent(); - dw_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); - - dw_printf("%08I64x %S", info_offset, string); - } - dw_unindent(); - rd_newline(); - } - dw_unindent(); - - scratch_end(scratch); -#endif -} - -internal void -dw_print_debug_pubnames(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *input) -{ - dw_format_string_table(arena, out, g_dw_indent, input, DW_Section_PubNames); -} - -internal void -dw_print_debug_pubtypes(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *input) -{ - dw_format_string_table(arena, out, g_dw_indent, input, DW_Section_PubTypes); -} - -internal void -dw_print_debug_line_str(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *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); - - dw_printf("# %S", sections->v[DW_Section_LineStr].name); - dw_indent(); - - dw_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); - dw_printf("%08llX %S", offset, string); - } - dw_unindent(); - - scratch_end(scratch); -#endif -} - -internal void -dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 g_dw_indent, DW_Raw *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); - - dw_printf("# %S", sections->v[DW_Section_StrOffsets].name); - dw_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); - - dw_printf("Unit @ %#llX, length %I64d", unit_offset, unit_length); - dw_printf("Version: %d", version); - dw_printf("Padding: %d", padding); - dw_indent(); - dw_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); - dw_printf("%08I64x %08I64x", read_at, offset); - if (dim_1u64(debug_str_range) > 0) { - String8 string = dw_based_range_read_string(debug_str_base, debug_str_range, offset); - dw_printf(" %S", string); - } - rd_newline(); - } - dw_unindent(); - rd_newline(); - } - dw_unindent(); - - scratch_end(scratch); -#endif -} - -#endif - //////////////////////////////// -//~ rjf: Dump Entry Point - -read_only struct { - DW_Printer *printer; - DW_SectionKind kind; -} g_dw_printers[] = { - { dw_print_abbrev, DW_Section_Abbrev }, - { dw_print_info, DW_Section_Info }, - { dw_print_strings, DW_Section_Str }, - { dw_print_frame, DW_Section_Frame }, - { dw_print_line, DW_Section_Line }, -}; +//~ rjf: Main Dump Entry Point internal String8List -dw_dump_list_from_sections(Arena *arena, - DW_Raw *input, - Arch arch, - DW_SectionFlags subset_flags, - B32 is_verbose) +dw_dump_list_from_raw(Arena *arena, DW_Raw *raw, Arch arch, DW_SectionFlags subset_flags) { + ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); - String8List *strings = push_array(scratch.arena, String8List, 1); - int indent = 0; + String8 indent = str8_lit(" "); - DW_Dumper dumper = {0}; - dumper.arena = arena_alloc(); - dumper.arch = arch; - dumper.is_verbose = is_verbose; - dumper.input = input; - dumper.is_relaxed = 1; + ////////////////////////////// + //- 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) - for EachElement(i, g_dw_printers) { - if (((1 << g_dw_printers[i].kind) & subset_flags) != 0) { - String8List s = {0}; - g_dw_printers[i].printer(arena, &s, indent + 1, &dumper); - - if (s.total_size > 0) { - dw_printf("%S:\n", str8_skip(dw_name_string_from_section_kind(g_dw_printers[i].kind), 1)); - dw_printf("{\n"); - dw_indent(); - str8_list_concat_in_place(strings, &s); - dw_unindent(); - dw_printf("}\n"); + ////////////////////////////// + //- 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"); } } - String8List result = *strings; - arena_release(dumper.arena); + ////////////////////////////// + //- 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); - return result; + ProfEnd(); + return result_strings; } - diff --git a/src/dwarf/dwarf_dump.h b/src/dwarf/dwarf_dump.h index 6a015952..eddc47b2 100644 --- a/src/dwarf/dwarf_dump.h +++ b/src/dwarf/dwarf_dump.h @@ -4,70 +4,14 @@ #ifndef DWARF_DUMP_H #define DWARF_DUMP_H -typedef enum -{ - DW_DumperCacheFlag_InfoRanges = (1 << 0), - DW_DumperCacheFlag_CuArr = (1 << 1), - DW_DumperCacheFlag_LineVmMap = (1 << 2), - DW_DumperCacheFlag_TagTrees = (1 << 3), -} DW_DumperCacheFlags; +//////////////////////////////// +//~ rjf: Helpers -typedef struct DW_Dumper -{ - Arena *arena; - Arch arch; - B32 is_relaxed; - B32 is_verbose; - DW_Raw *input; - DW_DumperCacheFlags cache_flags; - struct { - Rng1U64Array info_ranges; - DW_CompUnit *cu_arr; - HashTable *line_vm_map; - DW_TagTree *tag_trees; - } cache; -} DW_Dumper; - -#define DW_PRINTER(name) void name(Arena *arena, String8List *strings, int indent, DW_Dumper *dumper) -typedef DW_PRINTER(DW_Printer); +internal String8List dw_dump_list_from_expr(Arena *arena, String8 data, Arch arch, DW2_ParseCtx *ctx); //////////////////////////////// +//~ rjf: Main Dump Entry Point -// cache -internal Rng1U64Array dw_get_info_ranges(DW_Dumper *dumper); -internal DW_CompUnit * dw_get_cu_arr(DW_Dumper *dumper); -internal HashTable * dw_get_line_vm_map(DW_Dumper *dumper); -internal DW_TagTree * dw_get_tag_trees(DW_Dumper *dumper); - -//////////////////////////////// -//~ rjf: Stringification Helpers - -internal String8List dw_string_list_from_cfi_program(Arena *arena, U64 cu_base, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format, U64 pc_begin, DW_CIE *cie, DW_DecodePtr *decode_ptr_func, void *deocde_ptr_ud, String8 program); -internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); - -internal String8 dw_string_from_reg_off (Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off); -internal String8 dw_string_from_attrib_value(Arena *arena, DW_Raw *input, Arch arch, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib); -internal String8 dw_string_from_expression (Arena *arena, String8 expr, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); -internal String8 dw_string_from_cfa (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFA cfa); -internal String8 dw_string_from_cfi_row (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFI_Row *row); - -#if 0 -internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx); -internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed); -internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed); -internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input); -internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_Raw *input); -internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges, Arch arch); -internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges); -internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_Raw *input); -internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_Raw *input); -internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_Raw *input); -internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Raw *input); -#endif - -//////////////////////////////// -//~ rjf: Dump Entry Point - -internal String8List dw_dump_list_from_sections(Arena *arena, DW_Raw *input, Arch arch, DW_SectionFlags dump_sections, B32 is_verbose); +internal String8List dw_dump_list_from_raw(Arena *arena, DW_Raw *raw, Arch arch, DW_SectionFlags subset_flags); #endif // DWARF_DUMP_H diff --git a/src/dwarf/dwarf_dump_2.c b/src/dwarf/dwarf_dump_2.c deleted file mode 100644 index 04f7669c..00000000 --- a/src/dwarf/dwarf_dump_2.c +++ /dev/null @@ -1,718 +0,0 @@ -// 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; -} diff --git a/src/dwarf/dwarf_dump_2.h b/src/dwarf/dwarf_dump_2.h deleted file mode 100644 index 620c7562..00000000 --- a/src/dwarf/dwarf_dump_2.h +++ /dev/null @@ -1,17 +0,0 @@ -// 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 diff --git a/src/dwarf/dwarf_expr.c b/src/dwarf/dwarf_expr.c index 8f8e23ac..3e3d6397 100644 --- a/src/dwarf/dwarf_expr.c +++ b/src/dwarf/dwarf_expr.c @@ -1,1580 +1,393 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -internal DW_PieceNode * -dw_piece_list_push(Arena *arena, DW_PieceList *list, DW_Piece v) -{ - DW_PieceNode *n = push_array(arena, DW_PieceNode, 1); - n->v = v; - SLLQueuePush(list->first, list->last, n); - list->count += 1; - return n; -} +//////////////////////////////// +//~ rjf: Expression Evaluation Functions -internal DW_ExprValueType -dw_expr_unsigned_value_type_from_bit_size(U64 bit_size) +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) { - switch (bit_size) { - case 8: return DW_ExprValueType_U8; - case 16: return DW_ExprValueType_U16; - case 32: return DW_ExprValueType_U32; - case 64: return DW_ExprValueType_U64; - case 128: return DW_ExprValueType_U128; - case 256: return DW_ExprValueType_U256; - case 512: return DW_ExprValueType_U512; - } - AssertAlways(0 && "no suitable unsigned type was found for the specified size"); - return DW_ExprValueType_Generic; -} - -internal DW_ExprValueType -dw_expr_signed_value_type_from_bit_size(U64 bit_size) -{ - switch (bit_size) { - case 8: return DW_ExprValueType_S8; - case 16: return DW_ExprValueType_S16; - case 32: return DW_ExprValueType_S32; - case 64: return DW_ExprValueType_S64; - case 128: return DW_ExprValueType_S128; - case 256: return DW_ExprValueType_S256; - case 512: return DW_ExprValueType_S512; - } - AssertAlways(0 && "no suitable signed type was found for the specified size"); - return DW_ExprValueType_Generic; -} - -internal DW_ExprValueType -dw_expr_float_type_from_bit_size(U64 bit_size) -{ - switch (bit_size) { - case 4: return DW_ExprValueType_F32; - case 8: return DW_ExprValueType_F64; - } - AssertAlways(0 && "no suitable type was found for the specified size"); - return DW_ExprValueType_Generic; -} - -internal U64 -dw_expr_byte_size_from_value_type(U64 addr_size, DW_ExprValueType k) -{ - switch (k) { - default: { InvalidPath; } - case DW_ExprValueType_Generic: return 0; - case DW_ExprValueType_Addr: return addr_size; - case DW_ExprValueType_U8: return 1; - case DW_ExprValueType_U16: return 2; - case DW_ExprValueType_U32: return 4; - case DW_ExprValueType_U64: return 8; - case DW_ExprValueType_U128: return 16; - case DW_ExprValueType_U256: return 32; - case DW_ExprValueType_U512: return 64; - case DW_ExprValueType_S8: return 1; - case DW_ExprValueType_S16: return 2; - case DW_ExprValueType_S32: return 4; - case DW_ExprValueType_S64: return 8; - case DW_ExprValueType_S128: return 16; - case DW_ExprValueType_S256: return 32; - case DW_ExprValueType_S512: return 64; - case DW_ExprValueType_F32: return 4; - case DW_ExprValueType_F64: return 8; - } -} - -internal DW_ExprValueType -dw_expr_pick_common_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs) -{ - if (lhs == rhs) { - return lhs; - } - // unsigned vs unsigned - else if (DW_ExprValueType_IsUnsigned(lhs) && DW_ExprValueType_IsUnsigned(rhs)) { - return Max(lhs, rhs); - } - // signed vs signed - else if (DW_ExprValueType_IsSigned(lhs) && DW_ExprValueType_IsSigned(rhs)) { - return Max(lhs, rhs); - } - // (unsigned vs signed) || (signed vs unsigned) - else if ((DW_ExprValueType_IsUnsigned(lhs) && DW_ExprValueType_IsSigned(rhs)) || - (DW_ExprValueType_IsSigned(lhs) && DW_ExprValueType_IsUnsigned(rhs))) { - U64 lhs_size = dw_expr_byte_size_from_value_type(0, lhs); - U64 rhs_size = dw_expr_byte_size_from_value_type(0, rhs); - if (lhs_size < rhs_size) { - return rhs; - } else if (lhs > rhs_size) { - return lhs; - } else { - return dw_expr_unsigned_value_type_from_bit_size(lhs_size * 8); - } - } - // float vs int - else if (DW_ExprValueType_IsFloat(lhs) && DW_ExprValueType_IsInt(rhs)) { - return lhs; - } - // int vs float - else if (DW_ExprValueType_IsInt(lhs) && DW_ExprValueType_IsFloat(rhs)) { - return rhs; - } - // float vs float - else if (DW_ExprValueType_IsFloat(lhs) && DW_ExprValueType_IsFloat(rhs)) { - return Max(lhs, rhs); - } - // address vs int - else if (lhs == DW_ExprValueType_Addr && DW_ExprValueType_IsInt(rhs)) { - return DW_ExprValueType_Addr; - } - // int vs address - else if (DW_ExprValueType_IsInt(lhs) && rhs == DW_ExprValueType_Addr) { - return DW_ExprValueType_Addr; - } - // address vs float - else if (lhs == DW_ExprValueType_Addr && DW_ExprValueType_IsFloat(rhs)) { - return DW_ExprValueType_Generic; - } - // float vs address - else if (DW_ExprValueType_IsFloat(lhs) && rhs == DW_ExprValueType_Addr) { - return DW_ExprValueType_Generic; - } - // no conversion for implicit value - else if (lhs == DW_ExprValueType_Implicit || rhs == DW_ExprValueType_Implicit) { - return DW_ExprValueType_Generic; - } - AssertAlways(!"undefined conversion case"); - return DW_ExprValueType_Generic; -} - -internal DW_ExprValueType -dw_expr_pick_common_compar_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs) -{ - DW_ExprValueType result; - if (lhs == DW_ExprValueType_Generic || rhs == DW_ExprValueType_Generic) { - result = DW_ExprValueType_S64; - } else { - result = dw_expr_pick_common_value_type(lhs, rhs); - } - return result; -} - -internal DW_ExprValue -dw_expr_cast(DW_ExprValue value, DW_ExprValueType type) -{ - DW_ExprValue result = { type }; - -#define CastTable(f, t) \ -switch (value.type) { \ -case DW_ExprValueType_Generic: { MemoryCopy(&result.f, value.generic.str, Min(sizeof(t), value.generic.size)); } break; \ -case DW_ExprValueType_U8: { result.f = (t)value.u8; } break; \ -case DW_ExprValueType_U16: { result.f = (t)value.u16; } break; \ -case DW_ExprValueType_U32: { result.f = (t)value.u32; } break; \ -case DW_ExprValueType_U64: { result.f = (t)value.u64; } break; \ -case DW_ExprValueType_U128: { NotImplemented; } break; \ -case DW_ExprValueType_U256: { NotImplemented; } break; \ -case DW_ExprValueType_U512: { NotImplemented; } break; \ -case DW_ExprValueType_S8: { result.f = (t)value.s8; } break; \ -case DW_ExprValueType_S16: { result.f = (t)value.s16; } break; \ -case DW_ExprValueType_S32: { result.f = (t)value.s32; } break; \ -case DW_ExprValueType_S64: { result.f = (t)value.s64; } break; \ -case DW_ExprValueType_S128: { NotImplemented; } break; \ -case DW_ExprValueType_S256: { NotImplemented; } break; \ -case DW_ExprValueType_S512: { NotImplemented; } break; \ -case DW_ExprValueType_F32: { result.f = (t)value.f32; } break; \ -case DW_ExprValueType_F64: { result.f = (t)value.f64; } break; \ -case DW_ExprValueType_Addr: { result.f = (t)value.addr; } break; \ -case DW_ExprValueType_Implicit: { InvalidPath; } break; \ -case DW_ExprValueType_Bool: { result.f = (t)value.boolean; } break; \ -default: { InvalidPath; } break; \ -} - - switch (type) { - case DW_ExprValueType_Generic: {} break; - case DW_ExprValueType_U8: { CastTable(u8, U8); } break; - case DW_ExprValueType_U16: { CastTable(u16, U16); } break; - case DW_ExprValueType_U32: { CastTable(u32, U32); } break; - case DW_ExprValueType_U64: { CastTable(u64, U64); } break; - case DW_ExprValueType_U128: { NotImplemented; } break; - case DW_ExprValueType_U256: { NotImplemented; } break; - case DW_ExprValueType_U512: { NotImplemented; } break; - case DW_ExprValueType_S8: { CastTable(s8, S8); } break; - case DW_ExprValueType_S16: { CastTable(s16, S16); } break; - case DW_ExprValueType_S32: { CastTable(s32, S32); } break; - case DW_ExprValueType_S64: { CastTable(s64, S64); } break; - case DW_ExprValueType_S128: { NotImplemented; } break; - case DW_ExprValueType_S256: { NotImplemented; } break; - case DW_ExprValueType_S512: { NotImplemented; } break; - case DW_ExprValueType_F32: { CastTable(f32, F32); } break; - case DW_ExprValueType_F64: { CastTable(f64, F64); } break; - case DW_ExprValueType_Addr: { CastTable(addr, U64); } break; - case DW_ExprValueType_Implicit: { NotImplemented; } break; - case DW_ExprValueType_Bool: { CastTable(boolean, DW_ExprBool); } break; - } - -#undef CastTable - return result; -} - -internal DW_ExprValue -dw_expr_add(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 + common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 + common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 + common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 + common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 + common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 + common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 + common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 + common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 + common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 + common_rhs.f32; } break; - case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 + common_rhs.f64; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr + common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - return result; -} - -internal DW_ExprValue -dw_expr_minus(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 - common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 - common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 - common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 - common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 - common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 - common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 - common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 - common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 - common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 - common_rhs.f32; } break; - case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 - common_rhs.f64; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr - common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - return result; -} - -internal DW_ExprValue -dw_expr_mul(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 * common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 * common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 * common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 * common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 * common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 * common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 * common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 * common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 * common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 * common_rhs.f32; } break; - case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 * common_rhs.f64; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr * common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - return result; -} - -internal DW_ExprValue -dw_expr_div(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 / common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 / common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 / common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 / common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 / common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 / common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 / common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 / common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 / common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 / common_rhs.f32; } break; - case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 / common_rhs.f64; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr / common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - return result; -} - -internal DW_ExprValue -dw_expr_mod(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 % common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 % common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 % common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 % common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 % common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 % common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 % common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 % common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 % common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { InvalidPath; } break; - case DW_ExprValueType_F64: { InvalidPath; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr % common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - return result; -} - -internal DW_ExprValue -dw_expr_eq(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 == common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 == common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 == common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 == common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 == common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 == common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 == common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 == common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 == common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 == common_rhs.f32; } break; - case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 == common_rhs.f64; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr == common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_ge(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 >= common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 >= common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 >= common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 >= common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 >= common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 >= common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 >= common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 >= common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 >= common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 >= common_rhs.f32; } break; - case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 >= common_rhs.f64; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr >= common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_gt(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 > common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 > common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 > common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 > common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 > common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 > common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 > common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 > common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 > common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 > common_rhs.f32; } break; - case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 > common_rhs.f64; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr > common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_le(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 <= common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 <= common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 <= common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 <= common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 <= common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 <= common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 <= common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 <= common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 <= common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 <= common_rhs.f32; } break; - case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 <= common_rhs.f64; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr <= common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_lt(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 < common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 < common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 < common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 < common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 < common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 < common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 < common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 < common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 < common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 < common_rhs.f32; } break; - case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 < common_rhs.f64; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr < common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_ne(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 != common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 != common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 != common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 != common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 != common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 != common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 != common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 != common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 != common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = common_lhs.f32 != common_rhs.f32; } break; - case DW_ExprValueType_F64: { result.f64 = common_lhs.f64 != common_rhs.f64; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr != common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_xor(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 ^ common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 ^ common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 ^ common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 ^ common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 ^ common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 ^ common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 ^ common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 ^ common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 ^ common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { InvalidPath; } break; - case DW_ExprValueType_F64: { InvalidPath; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr ^ common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_and(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 & common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 & common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 & common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 & common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 & common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 & common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 & common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 & common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 & common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { InvalidPath; } break; - case DW_ExprValueType_F64: { InvalidPath; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr & common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_or(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 | common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 | common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 | common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 | common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 | common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 | common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 | common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 | common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 | common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { InvalidPath; } break; - case DW_ExprValueType_F64: { InvalidPath; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr | common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_shl(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 << common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 << common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 << common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 << common_rhs.u64; } break; - - case DW_ExprValueType_U128: - case DW_ExprValueType_U256: - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 << common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 << common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 << common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 << common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 << common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { InvalidPath; } break; - case DW_ExprValueType_F64: { InvalidPath; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr << common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_shr(DW_ExprValue rhs, DW_ExprValue lhs) -{ - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = common_lhs.u8 >> common_rhs.u8; } break; - case DW_ExprValueType_U16: { result.u16 = common_lhs.u16 >> common_rhs.u16; } break; - case DW_ExprValueType_U32: { result.u32 = common_lhs.u32 >> common_rhs.u32; } break; - case DW_ExprValueType_U64: { result.u64 = common_lhs.u64 >> common_rhs.u64; } break; - - case DW_ExprValueType_U128: { NotImplemented; } break; - case DW_ExprValueType_U256: { NotImplemented; } break; - case DW_ExprValueType_U512: { NotImplemented; } break; - - case DW_ExprValueType_Bool: { InvalidPath; } break; - case DW_ExprValueType_S8: { InvalidPath; } break; - case DW_ExprValueType_S16: { InvalidPath; } break; - case DW_ExprValueType_S32: { InvalidPath; } break; - case DW_ExprValueType_S64: { InvalidPath; } break; - case DW_ExprValueType_S128: { InvalidPath; } break; - case DW_ExprValueType_S256: { InvalidPath; } break; - case DW_ExprValueType_S512: { InvalidPath; } break; - - case DW_ExprValueType_F32: { InvalidPath; } break; - case DW_ExprValueType_F64: { InvalidPath; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr >> common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_shra(DW_ExprValue rhs, DW_ExprValue lhs) -{ - if (DW_ExprValueType_IsUnsigned(lhs.type)) { - DW_ExprValueType new_type = dw_expr_signed_value_type_from_bit_size(dw_expr_byte_size_from_value_type(0, lhs.type) * 8); - lhs = dw_expr_cast(lhs, new_type); - } - - if (DW_ExprValueType_IsUnsigned(rhs.type)) { - DW_ExprValueType new_type = dw_expr_signed_value_type_from_bit_size(dw_expr_byte_size_from_value_type(0, rhs.type) * 8); - rhs = dw_expr_cast(rhs, new_type); - } - - DW_ExprValue result = {0}; - result.type = dw_expr_pick_common_compar_value_type(lhs.type, rhs.type); - - DW_ExprValue common_lhs = dw_expr_cast(lhs, result.type); - DW_ExprValue common_rhs = dw_expr_cast(rhs, result.type); - - switch (result.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { InvalidPath; } break; - case DW_ExprValueType_U16: { InvalidPath; } break; - case DW_ExprValueType_U32: { InvalidPath; } break; - case DW_ExprValueType_U64: { InvalidPath; } break; - case DW_ExprValueType_U128: { InvalidPath; } break; - case DW_ExprValueType_U256: { InvalidPath; } break; - case DW_ExprValueType_U512: { InvalidPath; } break; - - case DW_ExprValueType_Bool: { result.s8 = common_lhs.s8 >> common_rhs.s8; } break; - case DW_ExprValueType_S8: { result.s8 = common_lhs.s8 >> common_rhs.s8; } break; - case DW_ExprValueType_S16: { result.s16 = common_lhs.s16 >> common_rhs.s16; } break; - case DW_ExprValueType_S32: { result.s32 = common_lhs.s32 >> common_rhs.s32; } break; - case DW_ExprValueType_S64: { result.s64 = common_lhs.s64 >> common_rhs.s64; } break; - - case DW_ExprValueType_S128: - case DW_ExprValueType_S256: - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { InvalidPath; } break; - case DW_ExprValueType_F64: { InvalidPath; } break; - case DW_ExprValueType_Addr: { result.addr = common_lhs.addr >> common_rhs.addr; } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - - default: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_abs(DW_ExprValue value) -{ - DW_ExprValue result = value; - - switch (value.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: {}; break; - case DW_ExprValueType_U16: {}; break; - case DW_ExprValueType_U32: {}; break; - case DW_ExprValueType_U64: {}; break; - case DW_ExprValueType_U128: {}; break; - case DW_ExprValueType_U256: {}; break; - case DW_ExprValueType_U512: {}; break; - - case DW_ExprValueType_S8: { result.s8 = abs_s64(result.s8); } break; - case DW_ExprValueType_S16: { result.s16 = abs_s64(result.s16); } break; - case DW_ExprValueType_S32: { result.s32 = abs_s64(result.s32); } break; - case DW_ExprValueType_S64: { result.s64 = abs_s64(result.s64); } break; - case DW_ExprValueType_S128: { NotImplemented; } break; - case DW_ExprValueType_S256: { NotImplemented; } break; - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = abs_f32(result.f32); } break; - case DW_ExprValueType_F64: { result.f64 = abs_f64(result.f64); } break; - - case DW_ExprValueType_Addr: {} break; - case DW_ExprValueType_Bool: { result.boolean = abs_s64(result.boolean); } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_neg(DW_ExprValue value) -{ - DW_ExprValue result = value; - - switch (value.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = -result.u8; }; break; - case DW_ExprValueType_U16: { result.u16 = -result.u16; }; break; - case DW_ExprValueType_U32: { result.u32 = -result.u32; }; break; - case DW_ExprValueType_U64: { result.u64 = -result.u64; }; break; - case DW_ExprValueType_U128: { NotImplemented; }; break; - case DW_ExprValueType_U256: { NotImplemented; }; break; - case DW_ExprValueType_U512: { NotImplemented; }; break; - - case DW_ExprValueType_S8: { result.s8 = -result.s8; } break; - case DW_ExprValueType_S16: { result.s16 = -result.s16; } break; - case DW_ExprValueType_S32: { result.s32 = -result.s32; } break; - case DW_ExprValueType_S64: { result.s64 = -result.s64; } break; - case DW_ExprValueType_S128: { NotImplemented; } break; - case DW_ExprValueType_S256: { NotImplemented; } break; - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = -result.f32; } break; - case DW_ExprValueType_F64: { result.f64 = -result.f64; } break; - - case DW_ExprValueType_Addr: { result.addr = -result.addr; } break; - case DW_ExprValueType_Bool: { result.boolean = abs_s64(result.boolean); } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - } - - return result; -} - -internal DW_ExprValue -dw_expr_not(DW_ExprValue value) -{ - DW_ExprValue result = value; - - switch (value.type) { - case DW_ExprValueType_Generic: { InvalidPath; } break; - - case DW_ExprValueType_U8: { result.u8 = !result.u8; }; break; - case DW_ExprValueType_U16: { result.u16 = !result.u16; }; break; - case DW_ExprValueType_U32: { result.u32 = !result.u32; }; break; - case DW_ExprValueType_U64: { result.u64 = !result.u64; }; break; - case DW_ExprValueType_U128: { NotImplemented; }; break; - case DW_ExprValueType_U256: { NotImplemented; }; break; - case DW_ExprValueType_U512: { NotImplemented; }; break; - - case DW_ExprValueType_S8: { result.s8 = !result.s8; } break; - case DW_ExprValueType_S16: { result.s16 = !result.s16; } break; - case DW_ExprValueType_S32: { result.s32 = !result.s32; } break; - case DW_ExprValueType_S64: { result.s64 = !result.s64; } break; - case DW_ExprValueType_S128: { NotImplemented; } break; - case DW_ExprValueType_S256: { NotImplemented; } break; - case DW_ExprValueType_S512: { NotImplemented; } break; - - case DW_ExprValueType_F32: { result.f32 = !result.f32; } break; - case DW_ExprValueType_F64: { result.f64 = !result.f64; } break; - - case DW_ExprValueType_Addr: { result.addr = !result.addr; } break; - case DW_ExprValueType_Bool: { result.boolean = abs_s64(result.boolean); } break; - case DW_ExprValueType_Implicit: { InvalidPath; } break; - } - - return result; -} - -internal String8 -dw_string_from_expr_value(Arena *arena, U64 addr_size, DW_ExprValue v) -{ - String8 s = {0}; - switch (v.type) { - case DW_ExprValueType_Generic: { } break; - case DW_ExprValueType_U8: { s = str8_struct(&v.u8); } break; - case DW_ExprValueType_U16: { s = str8_struct(&v.u16); } break; - case DW_ExprValueType_U32: { s = str8_struct(&v.u32); } break; - case DW_ExprValueType_U64: { s = str8_struct(&v.u64); } break; - case DW_ExprValueType_U128: { s = str8_struct(&v.u128); } break; - case DW_ExprValueType_U256: { s = str8_struct(&v.u256); } break; - case DW_ExprValueType_U512: { s = str8_struct(&v.u512); } break; - case DW_ExprValueType_S8: { s = str8_struct(&v.s8); } break; - case DW_ExprValueType_S16: { s = str8_struct(&v.s16); } break; - case DW_ExprValueType_S32: { s = str8_struct(&v.s32); } break; - case DW_ExprValueType_S64: { s = str8_struct(&v.s64); } break; - case DW_ExprValueType_F32: { s = str8_struct(&v.f32); } break; - case DW_ExprValueType_F64: { s = str8_struct(&v.f64); } break; - case DW_ExprValueType_Addr: { s = str8((U8 *)&v.addr, addr_size); } break; - case DW_ExprValueType_Implicit: { s = v.implicit; } break; - default: { NotImplemented; } break; - } - return str8_copy(arena, s); -} - -internal DW_ExprValueNode * -dw_expr_stack_push(Arena *arena, DW_ExprStack *stack, DW_ExprValue value) -{ - DW_ExprValueNode *n = push_array(arena, DW_ExprValueNode, 1); - n->v = value; - SLLStackPush(stack->top, n); - stack->count += 1; - return n; -} - -internal DW_ExprValueNode * -dw_expr_stack_push_unsigned(Arena *arena, DW_ExprStack *stack, void *value, U64 value_size) -{ - DW_ExprValueNode *n = 0; - switch (value_size) { - case 0: {} break; - case 1: { n = dw_expr_stack_push(arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U8, .u8 = *(U8 *)value }); } break; - case 2: { n = dw_expr_stack_push(arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U16, .u16 = *(U16 *)value }); } break; - case 4: { n = dw_expr_stack_push(arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U32, .u32 = *(U32 *)value }); } break; - case 8: { n = dw_expr_stack_push(arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U64, .u64 = *(U64 *)value }); } break; - default: { NotImplemented; } break; - } - return n; -} - -internal DW_ExprValue -dw_expr_stack_pop(DW_ExprStack *stack) -{ - DW_ExprValueNode *n = stack->top; - DW_ExprValue v = n->v; - SLLStackPop(stack->top); - return v; -} - -internal DW_ExprValue -dw_expr_stack_peek(DW_ExprStack *stack) -{ - return stack->top->v; -} - -internal DW_ExprValueNode * -dw_expr_stack_pick(DW_ExprStack *stack, U64 idx) -{ - DW_ExprValueNode *n = 0; - if (idx < stack->count) { - U64 c = idx; - for (n = stack->top; n != 0 && c > 0; n = n->next, c -= 1); - } - return n; -} - -internal DW_ExprInst * -dw_expr_inst_from_delta(DW_ExprInst *inst, S16 delta) -{ - B32 skip_fwd = inst->operands[0].s16 >= 0; - DW_ExprInst *i = inst; - U16 u_delta = abs_s64(inst->operands[0].s16); - U64 cursor = 0; - for (i = skip_fwd ? inst : inst->prev; i != 0 && cursor < u_delta; i = skip_fwd ? inst->next : inst->prev) { - cursor += inst->size; - } - if (cursor != u_delta) { - i = 0; - } - return i; -} - -internal DW_ExprEvalResult -dw_eval_expr(Arena *arena, Arch arch, DW_Format format, U64 frame_base, U64 cfa, U64 tls, U64 exec_op_limit, DW_Expr expr, void *reg_block, MachineOp_MemRead *mem_read, void *mem_read_ud, DW_ExprValue *value_out) -{ - Temp scratch = scratch_begin(&arena, 1); - + DW_Eval result = {0}; ARCH_Info *arch_info = arch_info_from_arch(arch); - - DW_ExprEvalResult result = DW_ExprEvalResult_Fail; - DW_PieceList pieces = {0}; - DW_ExprStack *stack = push_array(scratch.arena, DW_ExprStack, 1); - U64 exec_op_count = 0; - - for EachNode(inst, DW_ExprInst, expr.first) { - again:; + 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; - exec_op_count += 1; - if (exec_op_count > exec_op_limit) { - Assert(0 && "reached opcode exec limit on the expression"); - result = DW_ExprEvalResult_ExecOpLimitReached; - goto exit; + //- rjf: too many ops? -> error + if(state->op_idx >= op_idx_cap) + { + result.status = DW_EvalStatus_ExecOpLimitReached; + break; } - U64 pop_count = dw_pop_count_from_expr_op(inst->opcode); - if (pop_count > stack->count) { - Assert(0 && "not enough values on the stack to evaluate the instruction"); - goto exit; + //- 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)); } - switch (inst->opcode) { - case DW_ExprOp_Nop: {} break; - - 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: { - dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U8, .u8 = inst->opcode - DW_ExprOp_Lit0 }); - } break; - - case DW_ExprOp_Const1U: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U8, .u8 = inst->operands[0].u8 }); } break; - case DW_ExprOp_Const2U: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U16, .u16 = inst->operands[0].u16 }); } break; - case DW_ExprOp_Const4U: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U32, .u32 = inst->operands[0].u32 }); } break; - case DW_ExprOp_Const8U: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U64, .u64 = inst->operands[0].u64 }); } break; - case DW_ExprOp_Const1S: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_S8, .s8 = inst->operands[0].s8 }); } break; - case DW_ExprOp_Const2S: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_S16, .s16 = inst->operands[0].s16 }); } break; - case DW_ExprOp_Const4S: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_S32, .s32 = inst->operands[0].s32 }); } break; - case DW_ExprOp_Const8S: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_S64, .s64 = inst->operands[0].s64 }); } break; - case DW_ExprOp_ConstU: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U64, .u64 = inst->operands[0].u64 }); } break; - case DW_ExprOp_ConstS: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_S64, .s64 = inst->operands[0].s64 }); } break; - case DW_ExprOp_Addr: { dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_Addr, .addr = inst->operands[0].u64 }); } 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: + //- 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]) { - DW_Reg reg_dw_id = inst->opcode - DW_ExprOp_Reg0; - U64 reg_size = dw_reg_size_from_code(arch, reg_dw_id); - ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_dw_id); - Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code]; - U8 *reg_value = push_array(scratch.arena, U8, reg_size); - if(!arch_reg_block_read_range(arch_info, reg_block, r1u16(reg_rng.min, reg_rng.min + reg_size), reg_value)) + 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:; { - goto exit; + 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); } - dw_expr_stack_push_unsigned(scratch.arena, stack, reg_value, reg_size); + } + } + + //- 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; - 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: + //- 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:; { - DW_Reg reg_dw_id = inst->opcode - DW_ExprOp_BReg0; - U64 reg_size = dw_reg_size_from_code(arch, reg_dw_id); - ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_dw_id); - Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code]; - AssertAlways(reg_size <= byte_size_from_arch(arch)); - - U64 reg_value = 0; - if(!arch_reg_block_read_range(arch_info, reg_block, r1u16(reg_rng.min, reg_rng.min + reg_size), ®_value)) + 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)) { - goto exit; + need_a_break = 1; + result.status = DW_EvalStatus_FailedMemoryRead; + result.missed_read_vaddr_range = read_vaddr_range; } - - U64 addr = (U64)((S64)reg_value + inst->operands[0].s64); - dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_Addr, .addr = addr}); }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:; { - DW_Reg reg_dw_id = inst->operands[0].u64; - U64 reg_size = dw_reg_size_from_code(arch, reg_dw_id); - U8 *reg_value = push_array(scratch.arena, U8, reg_size); - ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_dw_id); + ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_code_dw); Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code]; - if(!arch_reg_block_read_range(arch_info, reg_block, r1u16(reg_rng.min, reg_rng.min + reg_size), reg_value)) - { - goto exit; - } - dw_expr_stack_push_unsigned(scratch.arena, stack, reg_value, reg_size); + 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:; { - DW_Reg reg_dw_id = (DW_Reg)inst->operands[0].u64; - U64 reg_size = dw_reg_size_from_code(arch, reg_dw_id); - AssertAlways(reg_size <= byte_size_from_arch(arch)); - ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_dw_id); + 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 reg_value = 0; - if(!arch_reg_block_read_range(arch_info, reg_block, r1u16(reg_rng.min, reg_rng.min + reg_size), ®_value)) - { - goto exit; - } - - U64 addr = (U64)((S64)reg_value + inst->operands[1].s64); - dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_Addr, .addr = addr}); + 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; - case DW_ExprOp_FBReg: { - U64 addr = frame_base + inst->operands[0].s64; - dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_Addr, .addr = addr}); - } break; - - case DW_ExprOp_ImplicitValue: { - if (inst->operands[0].block.size <= sizeof(U512)) { - dw_expr_stack_push_unsigned(scratch.arena, stack, inst->operands[0].block.str, inst->operands[0].block.size); - } else { - NotImplemented; - } - } break; - - case DW_ExprOp_Piece: { - B32 is_undefined = stack->count == 0 || (inst->prev && inst->prev->opcode == DW_ExprOp_Piece); - if (is_undefined) { - dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Undefined, .bit_size = inst->operands[0].u64 * 8 }); - } else { - DW_ExprValue top = dw_expr_stack_pop(stack); - - String8 value; - - // piece is a memory reference - if (top.type == DW_ExprValueType_Addr) { - U64 value_size = inst->operands[0].u64; - U8 *value_buffer = push_array(arena, U8, value_size); - MachineOpResult read_result = mem_read(top.addr, value_buffer, value_size, mem_read_ud); - if (read_result != MachineOpResult_Ok) { Assert(0 && "failed to read piece memory referece"); goto exit; } - } - // piece is a value - else { - value = dw_string_from_expr_value(arena, arch, top); - } - - if (inst->operands[0].u64 > value.size) { Assert(0 && "out of bounds size in the piece opcode"); goto exit; } - dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Value, .bit_size = inst->operands[0].u64 * 8, .value = value.str }); - } - } break; - - case DW_ExprOp_BitPiece: { - B32 is_undefined = stack->count == 0 || (inst->prev && inst->prev->opcode == DW_ExprOp_Piece); - if (is_undefined) { - dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Undefined, .bit_size = inst->operands[0].u64 }); - } else { - String8 value; - if (dw_expr_stack_peek(stack).type == DW_ExprValueType_Addr) { - NotImplemented; - } else { - value = dw_string_from_expr_value(arena, arch, dw_expr_stack_pop(stack)); - } - if (inst->operands[0].u64 > value.size * 8) { Assert(0 && "out of bounds size in piece opcode"); goto exit; } - dw_piece_list_push(arena, &pieces, (DW_Piece){ .kind = DW_PieceKind_Value, .bit_size = inst->operands[0].u64, .value = value.str }); - } - } break; - - case DW_ExprOp_Pick: { - DW_ExprValueNode *src = dw_expr_stack_pick(stack, inst->operands[0].u8); - if (src) { - dw_expr_stack_push(scratch.arena, stack, src->v); - } else { - Assert(0 && "out of bounds stack index"); - goto exit; - } - } break; - - case DW_ExprOp_Over: { - DW_ExprValueNode *src = dw_expr_stack_pick(stack, 1); - if (src) { - dw_expr_stack_push(scratch.arena, stack, src->v); - } else { - Assert(0 && "out of bounds stack index"); - goto exit; - } - } break; - - case DW_ExprOp_PlusUConst: { - DW_ExprValue lhs = dw_expr_stack_pop(stack); - DW_ExprValue rhs = { .type = DW_ExprValueType_U64, .u64 = inst->operands[0].u64 }; - DW_ExprValue sum = dw_expr_add(lhs, rhs); - dw_expr_stack_push(scratch.arena, stack, sum); - } break; - - case DW_ExprOp_Skip: { - DW_ExprInst *i = dw_expr_inst_from_delta(inst, inst->operands[0].s16); - - if (i == 0) { - Assert(0 && "seeking to an invalid offset"); - goto exit; - } - - inst = i; - goto again; - } - - case DW_ExprOp_Bra: { - DW_ExprValue cond = dw_expr_stack_pop(stack); - - if (cond.type != DW_ExprValueType_S16) { - Assert(0 && "unexpected value"); - goto exit; - } - - DW_ExprInst *i = dw_expr_inst_from_delta(inst, inst->operands[0].s16); - - if (i == 0) { - Assert(0 && "seeking to an invalid offset"); - goto exit; - } - - inst = i; - goto again; - } - - case DW_ExprOp_Call2: - case DW_ExprOp_Call4: - case DW_ExprOp_CallRef: { - NotImplemented; - } break; - - case DW_ExprOp_GNU_Convert: - case DW_ExprOp_Convert: { - if (inst->operands[0].u64 == 0) { - DW_ExprValue value = dw_expr_stack_pop(stack); - DW_ExprValue new_value = dw_expr_cast(value, DW_ExprValueType_Generic); - dw_expr_stack_push(scratch.arena, stack, new_value); - } else { - NotImplemented; - } - } break; - - case DW_ExprOp_Reinterpret: { - if (inst->operands[0].u64 == 0) { - DW_ExprValue value = dw_expr_stack_pop(stack); - DW_ExprValue new_value = dw_expr_cast(value, DW_ExprValueType_Generic); - dw_expr_stack_push(scratch.arena, stack, new_value); - } else { - NotImplemented; - } - } break; - - case DW_ExprOp_GNU_ParameterRef: { NotImplemented; } break; - case DW_ExprOp_GNU_DerefType: { NotImplemented; } break; - case DW_ExprOp_DerefType: { NotImplemented; } break; - case DW_ExprOp_ConstType: { NotImplemented; } break; - case DW_ExprOp_GNU_ConstType: { NotImplemented; } break; - case DW_ExprOp_RegvalType: { NotImplemented; } break; - - case DW_ExprOp_EntryValue: - case DW_ExprOp_GNU_EntryValue: + //- rjf: frame base register read + case DW_ExprOp_FBReg: { - DW_Expr entry_value_expr = dw_expr_from_data(scratch.arena, format, byte_size_from_arch(arch), inst->operands[0].block); - DW_ExprValue entry_value; - result = dw_eval_expr(scratch.arena, arch, format, frame_base, cfa, tls, exec_op_limit, entry_value_expr, reg_block, mem_read, mem_read_ud, &entry_value); - if (result != DW_ExprEvalResult_Ok) { goto exit; } - dw_expr_stack_push(scratch.arena, stack, entry_value); - } break; + push_vals[0].u512.u64[0] = (U64)(frame_base + operands[0].s64); + }break; - case DW_ExprOp_Addrx: { NotImplemented; } 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; - case DW_ExprOp_CallFrameCfa: { - dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_U64, .u64 = cfa }); - } break; + //- rjf: call frame CFA + case DW_ExprOp_CallFrameCfa: + { + push_vals[0].u512.u64[0] = cfa; + }break; - case DW_ExprOp_PushObjectAddress: { NotImplemented; } 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; - case DW_ExprOp_Plus: { dw_expr_stack_push(scratch.arena, stack, dw_expr_add(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Minus: { dw_expr_stack_push(scratch.arena, stack, dw_expr_minus(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Div: { dw_expr_stack_push(scratch.arena, stack, dw_expr_div(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Mul: { dw_expr_stack_push(scratch.arena, stack, dw_expr_mul(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Mod: { dw_expr_stack_push(scratch.arena, stack, dw_expr_mod(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - - case DW_ExprOp_Eq: { dw_expr_stack_push(scratch.arena, stack, dw_expr_eq(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Ge: { dw_expr_stack_push(scratch.arena, stack, dw_expr_ge(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Gt: { dw_expr_stack_push(scratch.arena, stack, dw_expr_gt(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Le: { dw_expr_stack_push(scratch.arena, stack, dw_expr_le(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Lt: { dw_expr_stack_push(scratch.arena, stack, dw_expr_lt(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Ne: { dw_expr_stack_push(scratch.arena, stack, dw_expr_ne(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - - case DW_ExprOp_Xor: { dw_expr_stack_push(scratch.arena, stack, dw_expr_xor(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_And: { dw_expr_stack_push(scratch.arena, stack, dw_expr_and(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Or: { dw_expr_stack_push(scratch.arena, stack, dw_expr_or(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Shl: { dw_expr_stack_push(scratch.arena, stack, dw_expr_shl(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Shr: { dw_expr_stack_push(scratch.arena, stack, dw_expr_shr(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Shra: { dw_expr_stack_push(scratch.arena, stack, dw_expr_shra(dw_expr_stack_pop(stack), dw_expr_stack_pop(stack))); } break; - - case DW_ExprOp_Abs: { dw_expr_stack_push(scratch.arena, stack, dw_expr_abs(dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Neg: { dw_expr_stack_push(scratch.arena, stack, dw_expr_neg(dw_expr_stack_pop(stack))); } break; - case DW_ExprOp_Not: { dw_expr_stack_push(scratch.arena, stack, dw_expr_not(dw_expr_stack_pop(stack))); } break; - - case DW_ExprOp_Dup: { - dw_expr_stack_push(scratch.arena, stack, dw_expr_stack_peek(stack)); - } break; - - case DW_ExprOp_Rot: { - DW_ExprValue first = dw_expr_stack_pop(stack); - DW_ExprValue second = dw_expr_stack_pop(stack); - DW_ExprValue third = dw_expr_stack_pop(stack); - dw_expr_stack_push(scratch.arena, stack, first); // -> third - dw_expr_stack_push(scratch.arena, stack, third); // -> second - dw_expr_stack_push(scratch.arena, stack, second); // -> first - } break; - - case DW_ExprOp_Swap: { - DW_ExprValue first = dw_expr_stack_pop(stack); - DW_ExprValue second = dw_expr_stack_pop(stack); - dw_expr_stack_push(scratch.arena, stack, first); // -> second - dw_expr_stack_push(scratch.arena, stack, second); // -> first - } break; - - case DW_ExprOp_Drop: { - dw_expr_stack_pop(stack); - } break; - - case DW_ExprOp_Deref: { - DW_ExprValue value = dw_expr_stack_pop(stack); - - // expression must be of an integral type - if (!DW_ExprValueType_IsInt(value.type)) { goto exit; } - - // treat value as an address - DW_ExprValue addr = dw_expr_cast(value, DW_ExprValueType_Addr); - - // read pointer size from the address - U64 addr_size = byte_size_from_arch(arch); - U8 *generic_value = push_array(scratch.arena, U8, addr_size); - MachineOpResult read_result = mem_read(addr.addr, generic_value, addr_size, mem_read_ud); - if (read_result != MachineOpResult_Ok) { goto exit; } - - // push generic data - dw_expr_stack_push(scratch.arena, stack, (DW_ExprValue){ .type = DW_ExprValueType_Generic, .generic = str8(generic_value, addr_size) }); - } break; - - case DW_ExprOp_StackValue: { - stack->top->v.type = dw_expr_unsigned_value_type_from_bit_size(bit_size_from_arch(arch)); - } break; - - case DW_ExprOp_GNU_PushTlsAddress: - case DW_ExprOp_FormTlsAddress: { - DW_ExprValue tls_off = dw_expr_stack_pop(stack); - DW_ExprValue tls_base = { .type = DW_ExprValueType_Addr, .addr = tls }; - DW_ExprValue tls_addr = dw_expr_add(tls_base, tls_off); - dw_expr_stack_push(scratch.arena, stack, tls_addr); - } break; - } - } - - // composite value - if (pieces.count > 0) { -#if 0 - U64 total_bit_size = 0; - for EachNode (n, DW_PieceNode, pieces.first) { - total_bit_size += n->v.bit_size; - } - - U64 value_size = CeilIntegerDiv(total_bit_size, 8); - U8 *value = push_array(arena, U8, value_size); - Rng1U64 *ranges = push_array(arena, Rng1U64, pieces.count); - U64 *offsets = push_array(arena, U64, pieces.count); - U64 value_idx = 0; - U64 value_cursor = 0; - U64 piece_cursor = 0; - for EachNode(n, DW_PieceNode, pieces.first) { - if (n->v.kind == DW_PieceKind_Value) { - ranges[value_idx] = r1u64(piece_cursor, piece_cursor + n->v.bit_size); - offsets[value_idx] = value_cursor; - for (U64 i = 0; i < n->v.bit_size; i += 8) { - U64 to_copy = Min(8, n->v.bit_size - i); - if (value_cursor % 8 == 0) { - value[value_cursor / 8] = n->v.value[i]; - } else { - value[value_cursor / 8] |= n->v.value[i] << (value_cursor % 8); - value[AlignPow2(value_cursor / 8, 8)] |= n->v.value[i] >> (value_cursor % 8); - } - value_cursor += to_copy; + //- rjf: conversions + case DW_ExprOp_Convert: + case DW_ExprOp_Reinterpret: + { + if(operands[0].u512.u64[0] == 0) + { + push_vals[0] = popped_vals[0]; } - value_idx += 1; - } - piece_cursor += n->v.bit_size; + 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; } - value_out->type = DW_ExprValueType_Generic; - value_out->ranges = (Rng1U64Array){ .count = pieces.count, .v = ranges }; - value_out->offsets = offsets; - value_out->generic = str8(value, value_size); -#else - NotImplemented; -#endif - } - // scalar - else { - if (stack->top) { - *value_out = stack->top->v; - if (value_out->type == DW_ExprValueType_Generic) { - value_out->generic = push_str8_copy(arena, value_out->generic); + //- 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); } - - Rng1U64 *range = push_array(arena, Rng1U64, 1); - *range = r1u64(0, max_U64); - value_out->ranges = (Rng1U64Array){ .count = 1, .v = range }; - value_out->offsets = push_array(arena, U64, 1); - } else { - MemoryZeroStruct(value_out); + } + + //- 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; } } - - result = DW_ExprEvalResult_Ok; - exit:; - scratch_end(scratch); return result; } diff --git a/src/dwarf/dwarf_expr.h b/src/dwarf/dwarf_expr.h index 432b5b22..5bb9630f 100644 --- a/src/dwarf/dwarf_expr.h +++ b/src/dwarf/dwarf_expr.h @@ -5,229 +5,62 @@ #define DWARF_EXPR_H //////////////////////////////// -// evaluator +//~ rjf: Evaluation Values -#define DW_ExprValueType_IsSigned(x) ((x) == DW_ExprValueType_S8 || (x) == DW_ExprValueType_S16 || (x) == DW_ExprValueType_S32 || (x) == DW_ExprValueType_S64 || (x) == DW_ExprValueType_S128 || (x) == DW_ExprValueType_S256 || (x) == DW_ExprValueType_S512) -#define DW_ExprValueType_IsUnsigned(x) ((x) == DW_ExprValueType_U8 || (x) == DW_ExprValueType_U16 || (x) == DW_ExprValueType_U32 || (x) == DW_ExprValueType_U64 || (x) == DW_ExprValueType_U128 || (x) == DW_ExprValueType_U256 || (x) == DW_ExprValueType_U512) -#define DW_ExprValueType_IsFloat(x) ((x) == DW_ExprValueType_F32 || (x) == DW_ExprValueType_F64) -#define DW_ExprValueType_IsInt(x) (DW_ExprValueType_IsSigned(x) || DW_ExprValueType_IsUnsigned(x) || (x) == DW_ExprValueType_Addr) -typedef enum +typedef struct DW_EvalVal DW_EvalVal; +struct DW_EvalVal { - DW_ExprValueType_Generic, - DW_ExprValueType_U8, - DW_ExprValueType_U16, - DW_ExprValueType_U32, - DW_ExprValueType_U64, - DW_ExprValueType_U128, - DW_ExprValueType_U256, - DW_ExprValueType_U512, - DW_ExprValueType_S8, - DW_ExprValueType_S16, - DW_ExprValueType_S32, - DW_ExprValueType_S64, - DW_ExprValueType_S128, - DW_ExprValueType_S256, - DW_ExprValueType_S512, - DW_ExprValueType_F32, - DW_ExprValueType_F64, - DW_ExprValueType_Addr, - DW_ExprValueType_Implicit, - DW_ExprValueType_Bool, -} DW_ExprValueType; - -typedef S8 DW_ExprBool; - -typedef struct DW_ExprValue -{ - DW_ExprValueType type; - Rng1U64Array ranges; - U64 *offsets; - union { - U8 u8; - U16 u16; - U32 u32; - U64 u64; - U128 u128; - U256 u256; - U512 u512; - S8 s8; - S16 s16; - S32 s32; - S64 s64; - F32 f32; - F64 f64; - U64 addr; - DW_ExprBool boolean; - String8 implicit; - String8 generic; + union + { + U512 u512; + S64 s64; }; -} DW_ExprValue; + String8 data; +}; -typedef struct DW_ExprValueNode +typedef struct DW_EvalValNode DW_EvalValNode; +struct DW_EvalValNode { - DW_ExprValue v; - struct DW_ExprValueNode *next; -} DW_ExprValueNode; - -typedef enum -{ - DW_PieceKind_Null, - DW_PieceKind_Value, - DW_PieceKind_Undefined, -} DW_PieceKind; - -typedef struct DW_Piece -{ - DW_PieceKind kind; - U64 bit_size; - U8 *value; -} DW_Piece; - -typedef struct DW_PieceNode -{ - DW_Piece v; - struct DW_PieceNode *next; -} DW_PieceNode; - -typedef struct DW_PieceList -{ - U64 count; - DW_PieceNode *first; - DW_PieceNode *last; -} DW_PieceList; - -typedef struct DW_ExprStack -{ - U64 count; - DW_ExprValueNode *top; -} DW_ExprStack; - -typedef enum -{ - DW_ExprEvalResult_Fail, - DW_ExprEvalResult_Ok, - DW_ExprEvalResult_Maybe, - DW_ExprEvalResult_ExecOpLimitReached, -} DW_ExprEvalResult; + DW_EvalValNode *next; + DW_EvalVal v; +}; //////////////////////////////// -// encoder +//~ rjf: Evaluation Results -typedef enum +typedef enum DW_EvalStatus { - DW_ExprEncType_Null, - DW_ExprEncType_Op, - DW_ExprEncType_U8, - DW_ExprEncType_U16, - DW_ExprEncType_U32, - DW_ExprEncType_U64, - DW_ExprEncType_S8, - DW_ExprEncType_S16, - DW_ExprEncType_S32, - DW_ExprEncType_S64, - DW_ExprEncType_ULEB128, - DW_ExprEncType_SLEB128, - DW_ExprEncType_Addr, - DW_ExprEncType_Block, - DW_ExprEncType_DwarfUInt, - DW_ExprEncType_Label, - DW_ExprEncType_DeclLabel, -} DW_ExprEncType; + DW_EvalStatus_Error, + DW_EvalStatus_FailedMemoryRead, + DW_EvalStatus_ExecOpLimitReached, + DW_EvalStatus_UnsupportedOp, + DW_EvalStatus_Good, +} +DW_EvalStatus; -typedef struct DW_ExprEnc +typedef struct DW_Eval DW_Eval; +struct DW_Eval { - DW_ExprEncType type; - union { - DW_ExprOp op; - U8 u8; - U16 u16; - U32 u32; - U64 u64; - S8 s8; - S16 s16; - S32 s32; - S64 s64; - U64 addr; - String8 block; - String8 label; - }; -} DW_ExprEnc; - -#define DW_ExprEnc_Op(v) { .type = DW_ExprEncType_Op, .op = DW_ExprOp_##v } -#define DW_ExprEnc_U8(v) { .type = DW_ExprEncType_U8, .u8 = v } -#define DW_ExprEnc_U16(v) { .type = DW_ExprEncType_U16, .u16 = v } -#define DW_ExprEnc_U32(v) { .type = DW_ExprEncType_U32, .u32 = v } -#define DW_ExprEnc_U64(v) { .type = DW_ExprEncType_U64, .u64 = v } -#define DW_ExprEnc_S8(v) { .type = DW_ExprEncType_S8, .s8 = v } -#define DW_ExprEnc_S16(v) { .type = DW_ExprEncType_S16, .s16 = v } -#define DW_ExprEnc_S32(v) { .type = DW_ExprEncType_S32, .s32 = v } -#define DW_ExprEnc_S64(v) { .type = DW_ExprEncType_S64, .s64 = v } -#define DW_ExprEnc_ULEB128(v) { .type = DW_ExprEncType_ULEB128, .u64 = v } -#define DW_ExprEnc_SLEB128(v) { .type = DW_ExprEncType_SLEB128, .s64 = v } -#define DW_ExprEnc_Addr(v) { .type = DW_ExprEncType_Addr, .addr = v } -#define DW_ExprEnc_Block(v) { .type = DW_ExprEncType_Block, .block = v } -#define DW_ExprEnc_UInt(v) { .type = DW_ExprEncType_DwarfUInt, .u64 = v } -#define DW_ExprEnc_Label(v) { .type = DW_ExprEncType_Label, .label = str8_lit_comp(v) } -#define DW_ExprEnc_DeclLabel(v) { .type = DW_ExprEncType_DeclLabel, .label = str8_lit_comp(v) } + DW_EvalVal val; + DW_EvalStatus status; + Rng1U64 missed_read_vaddr_range; +}; //////////////////////////////// +//~ rjf: Evaluation State Machine -// pieces -internal DW_PieceNode * dw_piece_list_push(Arena *arena, DW_PieceList *list, DW_Piece v); +typedef struct DW_EvalState DW_EvalState; +struct DW_EvalState +{ + U64 off; + U64 op_idx; + DW_EvalValNode *top_val; + DW_EvalValNode *free_val; +}; -// size -> type -internal DW_ExprValueType dw_expr_unsigned_value_type_from_bit_size(U64 bit_size); -internal DW_ExprValueType dw_expr_signed_value_type_from_bit_size(U64 bit_size); -internal DW_ExprValueType dw_expr_float_type_from_bit_size(U64 bit_size); +//////////////////////////////// +//~ rjf: Expression Evaluation Functions -// type -> size -internal U64 dw_expr_byte_size_from_value_type(U64 addr_size, DW_ExprValueType k); - -// typer -internal DW_ExprValueType dw_expr_pick_common_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs); -internal DW_ExprValueType dw_expr_pick_common_compar_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs); -internal DW_ExprValue dw_expr_cast(DW_ExprValue value, DW_ExprValueType type); - -// arithmetic operators -internal DW_ExprValue dw_expr_add (DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_minus(DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_mul (DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_div (DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_mod (DW_ExprValue rhs, DW_ExprValue lhs); - -// comparison operators -internal DW_ExprValue dw_expr_eq(DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_ge(DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_gt(DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_le(DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_lt(DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_ne(DW_ExprValue rhs, DW_ExprValue lhs); - -// bitwise operators -internal DW_ExprValue dw_expr_xor (DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_and (DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_or (DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_shl (DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_shr (DW_ExprValue rhs, DW_ExprValue lhs); -internal DW_ExprValue dw_expr_shra(DW_ExprValue rhs, DW_ExprValue lhs); - -// unary operators -internal DW_ExprValue dw_expr_abs(DW_ExprValue value); -internal DW_ExprValue dw_expr_neg(DW_ExprValue value); -internal DW_ExprValue dw_expr_not(DW_ExprValue value); - -// stack -internal DW_ExprValueNode * dw_expr_stack_push(Arena *arena, DW_ExprStack *stack, DW_ExprValue value); -internal DW_ExprValueNode * dw_expr_stack_push_unsigned(Arena *arena, DW_ExprStack *stack, void *value, U64 value_size); -internal DW_ExprValue dw_expr_stack_pop(DW_ExprStack *stack); -internal DW_ExprValue dw_expr_stack_peek(DW_ExprStack *stack); -internal DW_ExprValueNode * dw_expr_stack_pick(DW_ExprStack *stack, U64 idx); - -// value helpers -internal String8 dw_string_from_expr_value(Arena *arena, U64 addr_size, DW_ExprValue v); - -// 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); - -#endif //DWARF_EXPR_H +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_H diff --git a/src/dwarf/dwarf_expr_2.c b/src/dwarf/dwarf_expr_2.c deleted file mode 100644 index 3e3d6397..00000000 --- a/src/dwarf/dwarf_expr_2.c +++ /dev/null @@ -1,393 +0,0 @@ -// 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; -} diff --git a/src/dwarf/dwarf_expr_2.h b/src/dwarf/dwarf_expr_2.h deleted file mode 100644 index e68a9617..00000000 --- a/src/dwarf/dwarf_expr_2.h +++ /dev/null @@ -1,66 +0,0 @@ -// 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 diff --git a/src/dwarf/dwarf_inc.c b/src/dwarf/dwarf_inc.c index b5b9efb4..d36b4552 100644 --- a/src/dwarf/dwarf_inc.c +++ b/src/dwarf/dwarf_inc.c @@ -2,10 +2,10 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) #include "dwarf/dwarf.c" -#include "dwarf/dwarf_expr_2.c" -#include "dwarf/dwarf_parse_2.c" -#include "dwarf/dwarf_unwind_2.c" -#include "dwarf/dwarf_dump_2.c" +#include "dwarf/dwarf_parse.c" +#include "dwarf/dwarf_expr.c" +#include "dwarf/dwarf_unwind.c" +#include "dwarf/dwarf_dump.c" #if defined(COFF_H) # include "dwarf/dwarf_parse_coff.c" #endif diff --git a/src/dwarf/dwarf_inc.h b/src/dwarf/dwarf_inc.h index afc74828..fc9f24fe 100644 --- a/src/dwarf/dwarf_inc.h +++ b/src/dwarf/dwarf_inc.h @@ -5,10 +5,10 @@ #define DWARF_INC_H #include "dwarf/dwarf.h" -#include "dwarf/dwarf_expr_2.h" -#include "dwarf/dwarf_parse_2.h" -#include "dwarf/dwarf_unwind_2.h" -#include "dwarf/dwarf_dump_2.h" +#include "dwarf/dwarf_parse.h" +#include "dwarf/dwarf_expr.h" +#include "dwarf/dwarf_unwind.h" +#include "dwarf/dwarf_dump.h" #if defined(COFF_H) # include "dwarf/dwarf_parse_coff.h" #endif diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index a8898477..6b3f3fe5 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -1,3331 +1,1916 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -internal U64 -dw_hash_from_string(String8 string) -{ - XXH64_hash_t hash64 = XXH3_64bits(string.str, string.size); - return hash64; -} +//////////////////////////////// +//~ rjf: Basic Parsing Helpers internal U64 -str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_out) +dw2_read_initial_length(String8 data, U64 off, U64 *out, DW_Format *fmt_out) { - U64 bytes_read = 0; - U32 first_four_bytes; - if (str8_deserial_read_struct(string, off, &first_four_bytes) == sizeof(first_four_bytes)) { - if (first_four_bytes == max_U32) { - if (str8_deserial_read_struct(string, off+sizeof(U32), size_out) == sizeof(U64)) { - bytes_read = sizeof(U32) + sizeof(U64); - } - } else { - *size_out = first_four_bytes; - bytes_read = sizeof(U32); - } - } - return bytes_read; -} - -internal U64 -str8_deserial_read_dwarf_uint(String8 string, U64 off, DW_Format format, U64 *uint_out) -{ - U64 bytes_read = 0; - switch (format) { - case DW_Format_Null: break; - case DW_Format_32Bit: { - *uint_out &= (U64)max_U32; - bytes_read = str8_deserial_read(string, off, uint_out, sizeof(U32), sizeof(U32)); - } break; - case DW_Format_64Bit: { - bytes_read = str8_deserial_read_struct(string, off, uint_out); - } break; - } - return bytes_read; -} - -internal U64 -str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out) -{ - U64 value = 0; - U64 shift = 0; - U64 cursor = off; - for(;;) + DW_Format format = DW_Format_32Bit; + U64 size = 0; + U64 size_size = 0; { - U8 byte = 0; - U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte); - if(bytes_read != sizeof(byte)) + U32 size_or_header = 0; + size_size += str8_deserial_read_struct(data, off, &size_or_header); + if(size_or_header == max_U32) { - break; + size_size += str8_deserial_read_struct(data, off + size_size, &size); + format = DW_Format_64Bit; } - U8 val = byte & 0x7fu; - value |= ((U64)val) << shift; - cursor += bytes_read; - shift += 7u; - if((byte & 0x80u) == 0) + else { - break; + size = (U64)size_or_header; } } - if(value_out != 0) + if(out) { - *value_out = value; + out[0] = size; } - U64 bytes_read = cursor - off; - return bytes_read; + if(fmt_out) + { + fmt_out[0] = format; + } + return size_size; } internal U64 -str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out) +dw2_read_fmt_u64(String8 data, U64 off, DW_Format format, U64 *out) { - U64 value = 0; - U64 shift = 0; - U64 cursor = off; - for(;;) + U64 start_off = off; + switch(format) { - U8 byte; - U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte); - if(bytes_read != sizeof(byte)) + default: + case DW_Format_32Bit: { - break; - } - U8 val = byte & 0x7fu; - value |= ((U64)val) << shift; - cursor += bytes_read; - shift += 7u; - if((byte & 0x80u) == 0) + U32 out_32 = 0; + off += str8_deserial_read_struct(data, off, &out_32); + out[0] = (U64)out_32; + }break; + case DW_Format_64Bit: { - if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0) - { - value |= -(S64)(1ull << shift); - } - break; - } + off += str8_deserial_read_struct(data, off, out); + }break; } - if(value_out != 0) - { - *value_out = value; - } - U64 bytes_read = cursor - off; - return bytes_read; -} - -internal U64 -str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_out) -{ - Temp temp = temp_begin(arena); - - U64 *arr = push_array(arena, U64, count); - U64 i, cursor; - for (i = 0, cursor = off; i < count; ++i) { - U64 read_size = str8_deserial_read_uleb128(string, cursor, &arr[i]); - if (read_size == 0) { - break; - } - cursor += read_size; - } - - U64 bytes_read = 0; - if (i == count) { - *arr_out = arr; - bytes_read = cursor - off; - } else { - temp_end(temp); - *arr_out = 0; - } - - return bytes_read; -} - -internal U64 -str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out) -{ - Temp temp = temp_begin(arena); - - S64 *arr = push_array(arena, S64, count); - U64 i, cursor; - for (i = 0, cursor = off; i < count; ++i) { - U64 read_size = str8_deserial_read_sleb128(string, cursor, &arr[i]); - if (read_size == 0) { - break; - } - cursor += read_size; - } - - U64 bytes_read = 0; - if (i == count) { - *arr_out = arr; - bytes_read = cursor - off; - } else { - temp_end(temp); - *arr_out = 0; - } - + U64 bytes_read = (off - start_off); return bytes_read; } internal DW_SectionKind dw_section_kind_from_string(String8 string) { - DW_SectionKind s = DW_Section_Null; -#define X(_K,_L,_M,_W) \ -if (str8_match_lit(_L, string, 0)) { s = DW_Section_##_K; } \ -if (str8_match_lit(_M, string, 0)) { s = DW_Section_##_K; } + DW_SectionKind s = DW_SectionKind_Null; + if(0){} +#define X(name, regular_string, macho_string, dwo_string) else if(str8_match(string, s(regular_string), 0) || str8_match(string, s(macho_string), 0) || str8_match(string, s(dwo_string), 0)) { s = DW_SectionKind_##name; } DW_SectionKind_XList #undef X return s; } -internal DW_SectionKind -dw_section_dwo_kind_from_string(String8 string) -{ - DW_SectionKind s = DW_Section_Null; -#define X(_K,_L,_M,_W) if (str8_match_lit(_W, string, 0)) { s = DW_Section_##_K; } - DW_SectionKind_XList -#undef X - return s; -} - -internal Rng1U64List -dw_unit_ranges_from_data(Arena *arena, String8 data) -{ - Rng1U64List result = {0}; - - for (U64 cursor = 0; cursor < data.size; ) { - U64 start = cursor; - - // read unit size - U64 size; - U64 size_size = str8_deserial_read_dwarf_packed_size(data, cursor, &size); - if (size_size == 0) { break; } - cursor += size_size; - - // is unit size valid? - if (cursor + size > data.size) { break; } - cursor += size; - - // push unit range - if (size > 0) { - rng1u64_list_push(arena, &result, rng_1u64(start, cursor)); - } - } - - return result; -} +//////////////////////////////// +//~ rjf: Unit Range Set Parsing (Top-Level .debug_info, .debug_aranges) internal Rng1U64Array -dw_unit_ranges_from_data_arr(Arena *arena, String8 data) +dw2_unit_ranges_from_data(Arena *arena, String8 data) { Temp scratch = scratch_begin(&arena, 1); - Rng1U64List list = dw_unit_ranges_from_data(scratch.arena, data); - Rng1U64Array arr = rng1u64_array_from_list(arena, &list); - scratch_end(scratch); - return arr; -} - -internal U64 -dw_read_list_unit_header_addr(String8 unit_data, DW_ListUnit *lu_out) -{ - U64 header_size = 0; - - U64 unit_length = 0; - U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, 0, &unit_length); - - if (unit_length_size) { - DW_Version version = DW_Version_Null; - U64 version_size = str8_deserial_read_struct(unit_data, unit_length_size, &version); - - if (version_size) { - if (version >= DW_Version_5) { - U8 address_size = 0; - U64 address_size_size = str8_deserial_read_struct(unit_data, - unit_length_size + version_size, - &address_size); - - if (address_size_size && address_size) { - U8 segment_selector_size = 0; - U64 segment_selector_size_size = str8_deserial_read_struct(unit_data, - unit_length_size + version_size + address_size_size, - &segment_selector_size); - if (segment_selector_size_size) { - header_size = unit_length_size + version_size + address_size_size + segment_selector_size_size; - - lu_out->version = version; - lu_out->segment_selector_size = segment_selector_size; - lu_out->address_size = address_size; - lu_out->entry_size = segment_selector_size + address_size; - lu_out->entries = str8_skip(unit_data, header_size); - } - } - } - } - } - - return header_size; -} - -internal U64 -dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out) -{ - U64 header_size = 0; - - U32 first_four_bytes = 0; - if (str8_deserial_read_struct(unit_data, 0, &first_four_bytes) != sizeof(first_four_bytes)) { goto exit; } - DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit; - - U64 unit_length = 0; - U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, 0, &unit_length); - - if (unit_length_size) { - DW_Version version = DW_Version_Null; - U64 version_size = str8_deserial_read_struct(unit_data, unit_length_size, &version); - - if (version >= DW_Version_5) { - U16 padding = 0; - U64 padding_size = str8_deserial_read_struct(unit_data, unit_length_size + version_size, &padding); - - if (padding_size && padding == 0) { - header_size = unit_length_size + version_size + padding_size; - - lu_out->version = version; - lu_out->address_size = 0; - lu_out->segment_selector_size = 0; - lu_out->entry_size = dw_size_from_format(format); - lu_out->entries = str8_skip(unit_data, header_size); - } - } - } - - exit:; - return header_size; -} - -internal U64 -dw_read_list_unit_header_list(String8 unit_data, DW_ListUnit *lu_out) -{ - U64 header_size = 0; - - U32 first_four_bytes = 0; - if (str8_deserial_read_struct(unit_data, 0, &first_four_bytes) != sizeof(first_four_bytes)) { goto exit; } - DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit; - - U64 unit_length = 0; - U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, 0, &unit_length); - - if (unit_length_size) { - DW_Version version = DW_Version_Null; - U64 version_size = str8_deserial_read_struct(unit_data, unit_length_size, &version); - - if (version >= DW_Version_5) { - U8 address_size = 0; - U64 address_size_size = str8_deserial_read_struct(unit_data, unit_length_size + version_size, &address_size); - - if (address_size_size && address_size > 0) { - U8 segment_selector_size = 0; - U64 segment_selector_size_size = str8_deserial_read_struct(unit_data, unit_length_size + version_size + address_size_size, &segment_selector_size); - - if (segment_selector_size_size) { - U32 offset_entry_count = 0; - U64 offset_entry_count_size = str8_deserial_read_struct(unit_data, unit_length_size + version_size + address_size_size + segment_selector_size, &offset_entry_count); - - if (offset_entry_count_size) { - header_size = unit_length_size + version_size + address_size_size + segment_selector_size_size + offset_entry_count_size; - - lu_out->version = version; - lu_out->address_size = address_size; - lu_out->segment_selector_size = segment_selector_size; - lu_out->entry_size = dw_size_from_format(format); - lu_out->entries = str8_skip(unit_data, header_size); - } - } - } - } - } - - exit:; - return header_size; -} - -internal DW_ListUnitInput -dw_list_unit_input_from_input(Arena *arena, DW_Raw *input) -{ - Temp scratch = scratch_begin(&arena, 1); - - DW_ListUnitInput result = {0}; - - DW_Section debug_addr = input->sec[DW_Section_Addr]; + Rng1U64List unit_range_list = {0}; + for(U64 off = 0; off < data.size;) { - String8 data = debug_addr.data; - Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, data); + U64 start_off = off; - result.addr_ranges = rng1u64_array_from_list(arena, &unit_ranges); - result.addr_count = unit_ranges.count; - result.addrs = push_array(arena, DW_ListUnit, unit_ranges.count); + // rjf: read next unit size + U64 unit_size = 0; + U64 unit_size_size = dw2_read_initial_length(data, off, &unit_size, 0); - for (U64 unit_idx = 0; unit_idx < result.addr_ranges.count; ++unit_idx) { - String8 unit_data = str8_substr(debug_addr.data, result.addr_ranges.v[unit_idx]); - dw_read_list_unit_header_addr(unit_data, &result.addrs[unit_idx]); + // rjf: push + if(unit_size > 0) + { + rng1u64_list_push(scratch.arena, &unit_range_list, r1u64(off, off + unit_size_size + unit_size)); + } + + // rjf: advance + off += unit_size_size; + off += unit_size; + + // rjf: break if no movement + if(off == start_off) + { + break; } } - - DW_Section debug_str_offsets = input->sec[DW_Section_StrOffsets]; - { - String8 data = debug_str_offsets.data; - Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, data); - - result.str_offset_ranges = rng1u64_array_from_list(arena, &unit_ranges); - result.str_offset_count = unit_ranges.count; - result.str_offsets = push_array(arena, DW_ListUnit, unit_ranges.count); - - for (U64 unit_idx = 0; unit_idx < result.str_offset_ranges.count; ++unit_idx) { - String8 unit_data = str8_substr(data, result.str_offset_ranges.v[unit_idx]); - dw_read_list_unit_header_str_offsets(unit_data, &result.str_offsets[unit_idx]); - } - } - - DW_Section debug_rnglists = input->sec[DW_Section_RngLists]; - { - String8 data = debug_rnglists.data; - Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, data); - - result.rnglist_ranges = rng1u64_array_from_list(arena, &unit_ranges); - result.rnglist_count = unit_ranges.count; - result.rnglists = push_array(arena, DW_ListUnit, unit_ranges.count); - - for (U64 unit_idx = 0; unit_idx < result.rnglist_ranges.count; ++unit_idx) { - String8 unit_data = str8_substr(data, result.rnglist_ranges.v[unit_idx]); - dw_read_list_unit_header_list(unit_data, &result.rnglists[unit_idx]); - } - } - - DW_Section debug_loclists = input->sec[DW_Section_LocLists]; - { - String8 data = debug_loclists.data; - Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, data); - - result.loclist_ranges = rng1u64_array_from_list(arena, &unit_ranges); - result.loclist_count = unit_ranges.count; - result.loclists = push_array(arena, DW_ListUnit, unit_ranges.count); - - for (U64 unit_idx = 0; unit_idx < result.loclist_ranges.count; ++unit_idx) { - String8 unit_data = str8_substr(data, result.loclist_ranges.v[unit_idx]); - dw_read_list_unit_header_list(unit_data, &result.loclists[unit_idx]); - } - } - + Rng1U64Array result = rng1u64_array_from_list(arena, &unit_range_list); scratch_end(scratch); return result; } -internal U64 -dw_offset_from_list_unit(DW_ListUnit *lu, U64 index) -{ - U64 offset; - U64 entry_off = index * lu->entry_size; - if (entry_off + lu->entry_size <= lu->entries.size) { - offset = 0; - MemoryCopy(&offset, lu->entries.str + entry_off, lu->entry_size); - } else { - offset = max_U64; - } - return offset; -} +//////////////////////////////// +//~ rjf: Unit Header Parsing internal U64 -dw_addr_from_list_unit(DW_ListUnit *lu, U64 index) +dw2_read_unit_header(String8 data, U64 off, DW2_UnitHeader *out) { - U64 seg = 0; - U64 addr = max_U64; - U64 entry_count = lu->entries.size / lu->entry_size; - if (index < entry_count) { - U64 seg_off = lu->entry_size * index; - U64 addr_off = seg_off + lu->segment_selector_size; - MemoryCopy(&seg, lu->entries.str + seg_off, lu->segment_selector_size); - MemoryCopy(&addr, lu->entries.str + addr_off, lu->address_size); - // TODO: segment-based addressing - AssertAlways(seg == 0); - } else { - Assert(!"out of bounds index"); - } - return addr; -} - -internal U64 -dw_read_abbrev_tag(String8 data, U64 offset, DW_Abbrev *out_abbrev) -{ - U64 total_bytes_read = 0; - U64 cursor = offset; + U64 start_off = off; - // read tag ID and kind - U64 id = 0; - TryRead(str8_deserial_read_uleb128(data, cursor, &id), cursor, exit); + // rjf: read unit's .debug_info range size / format + U64 unit_info_size = 0; + DW_Format format = DW_Format_32Bit; + off += dw2_read_initial_length(data, off, &unit_info_size, &format); - // is this null terminator? - if (id == 0) { - total_bytes_read = cursor - offset; - MemoryZeroStruct(out_abbrev); - goto exit; - } + // rjf: read dwarf version + DW_Version version = 0; + off += str8_deserial_read_struct(data, off, &version); - U64 kind = 0; - TryRead(str8_deserial_read_uleb128(data, cursor, &kind), cursor, exit); - - // read child flag - U8 has_children = 0; - if (id != 0) { - TryRead(str8_deserial_read_struct(data, cursor, &has_children), cursor, exit); - } - - if (out_abbrev != 0) { - DW_Abbrev abbrev = { .kind = DW_Abbrev_Tag, .sub_kind = kind, .id = id}; - if (has_children) { - abbrev.flags |= DW_AbbrevFlag_HasChildren; - } - *out_abbrev = abbrev; - } - - total_bytes_read = cursor - offset; - exit:; - return total_bytes_read; -} - -internal U64 -dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev) -{ - U64 total_bytes_read = 0; - U64 cursor = offset; - - // read id and kind - U64 id, kind; - TryRead(str8_deserial_read_uleb128(data, cursor, &id), cursor, exit); - TryRead(str8_deserial_read_uleb128(data, cursor, &kind), cursor, exit); - - // read implicit const - S64 implicit_const = 0; - if (kind == DW_Form_ImplicitConst) { - TryRead(str8_deserial_read_sleb128(data, cursor, &implicit_const), cursor, exit); - } - - if (out_abbrev != 0) { - DW_Abbrev abbrev = { .kind = DW_Abbrev_Attrib, .sub_kind = kind, .id = id }; - if (kind == DW_Form_ImplicitConst) { - abbrev.flags |= DW_AbbrevFlag_HasImplicitConst; - abbrev.implicit_const = implicit_const; - } - *out_abbrev = abbrev; - } - - total_bytes_read = cursor - offset; - exit:; - return total_bytes_read; -} - -internal DW_AbbrevTable -dw_make_abbrev_table(Arena *arena, String8 abbrev_data, U64 abbrev_base) -{ - Temp temp = temp_begin(arena); - DW_AbbrevTable table = {0}; - B32 failed_to_make = 1; - - // count abbrev tags - for (U64 cursor = abbrev_base; cursor < abbrev_data.size; table.count += 1) { - DW_Abbrev tag; - TryRead(dw_read_abbrev_tag(abbrev_data, cursor, &tag), cursor, exit); - if (tag.id == 0) { break; } + // rjf: read header properties + U64 abbrev_off = max_U64; + U64 addr_size = 0; + DW_CompUnitKind kind = DW_CompUnitKind_Reserved; + U64 dwo_id = 0; + switch((DW_VersionEnum)version) + { + case DW_Version_Null: + case DW_Version_1: + {}break; - for (; cursor < abbrev_data.size; ) { - DW_Abbrev attrib; - TryRead(dw_read_abbrev_attrib(abbrev_data, cursor, &attrib), cursor, exit); - if(attrib.id == 0) { break; } - } - } - - // alloc entries - table.entries = push_array(arena, DW_AbbrevTableEntry, table.count); - table.count = 0; - - // fill out the table - for (U64 cursor = abbrev_base; cursor < abbrev_data.size;) { - U64 tag_abbrev_off = cursor; + // rjf: @dwarf2 + case DW_Version_2: + { + // rjf: read abbrev off + U32 abbrev_off_32 = 0; + off += str8_deserial_read_struct(data, off, &abbrev_off_32); + abbrev_off = (U64)abbrev_off_32; + + // rjf: read address size + U8 addr_size_8 = 0; + off += str8_deserial_read_struct(data, off, &addr_size_8); + addr_size = (U64)addr_size_8; + }break; - DW_Abbrev tag = {0}; - TryRead(dw_read_abbrev_tag(abbrev_data, cursor, &tag), cursor, exit); - if (tag.id == 0) { break; } + // rjf: @dwarf3 @dwarf4 + case DW_Version_3: + case DW_Version_4: + { + // rjf: read abbrev off + off += dw2_read_fmt_u64(data, off, format, &abbrev_off); + + // rjf: read address size + U8 addr_size_8 = 0; + off += str8_deserial_read_struct(data, off, &addr_size_8); + addr_size = (U64)addr_size_8; + }break; - // push new entry - table.entries[table.count].id = tag.id; - table.entries[table.count].off = tag_abbrev_off; - table.count += 1; - - for (; cursor < abbrev_data.size ;) { - DW_Abbrev attrib = {0}; - TryRead(dw_read_abbrev_attrib(abbrev_data, cursor, &attrib), cursor, exit); - if (attrib.id == 0) { break; } - } - } - - failed_to_make = 0; - exit:; - if (failed_to_make) { - MemoryZeroStruct(&table); - temp_end(temp); - } - return table; -} - -internal U64 -dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id) -{ - U64 abbrev_offset = max_U64; - if (table.count > 0) { - for (S64 l = 0, r = (S64)table.count - 1; l <= r; ) { - S64 m = l + (r - l) / 2; - if (abbrev_id > table.entries[m].id) { - l = m + 1; - } else if (abbrev_id < table.entries[m].id) { - r = m - 1; - } else { - abbrev_offset = table.entries[m].off; - break; + // rjf: @dwarf5 + case DW_Version_5: + { + // rjf: read unit kind + U8 comp_unit_kind_8 = 0; + off += str8_deserial_read_struct(data, off, &comp_unit_kind_8); + kind = (DW_CompUnitKind)comp_unit_kind_8; + + // rjf: read address size + U8 addr_size_8 = 0; + off += str8_deserial_read_struct(data, off, &addr_size_8); + addr_size = (U64)addr_size_8; + + // rjf: read abbrev off + off += dw2_read_fmt_u64(data, off, format, &abbrev_off); + + // rjf: read DWO ID, if applicable + if(kind == DW_CompUnitKind_Skeleton || + kind == DW_CompUnitKind_SplitCompile || + kind == DW_CompUnitKind_SplitType) + { + off += str8_deserial_read_struct(data, off, &dwo_id); } - } - } - return abbrev_offset; -} - -internal B32 -dw_read_form(String8 data, - DW_Version version, - DW_Format unit_format, - U64 address_size, - DW_FormKind form_kind, - S64 implicit_const, - DW_Form *form_out, - U64 *bytes_read_out) -{ - B32 is_ok = 0; - U64 cursor = 0; - DW_Form form = {0}; - switch (form_kind) { - case DW_Form_Null: break; - case DW_Form_Addr: { - TryRead(str8_deserial_read_block(data, cursor, address_size, &form.addr), cursor, exit); - } break; - case DW_Form_Block2: { - U16 size = 0; - TryRead(str8_deserial_read_struct(data, cursor, &size), cursor, exit); - TryRead(str8_deserial_read_block(data, cursor, size, &form.block), cursor, exit); - } break; - case DW_Form_Block4: { - U32 size = 0; - TryRead(str8_deserial_read_struct(data, cursor, &size), cursor, exit); - TryRead(str8_deserial_read_block(data, cursor + cursor, size, &form.block), cursor, exit); - } break; - case DW_Form_Data2: { - TryRead(str8_deserial_read_block(data, cursor, sizeof(U16), &form.data), cursor, exit); - } break; - case DW_Form_Data4: { - TryRead(str8_deserial_read_block(data, cursor, sizeof(U32), &form.data), cursor, exit); - } break; - case DW_Form_Data8: { - TryRead(str8_deserial_read_block(data, cursor, sizeof(U64), &form.data), cursor, exit); - } break; - case DW_Form_String: { - TryRead(str8_deserial_read_cstr(data, cursor, &form.string), cursor, exit); - } break; - case DW_Form_Block: { - U64 size = 0; - TryRead(str8_deserial_read_uleb128(data, cursor, &size), cursor, exit); - TryRead(str8_deserial_read_block(data, cursor, size, &form.block), cursor, exit); - } break; - case DW_Form_Block1: { - U8 size = 0; - TryRead(str8_deserial_read_struct(data, cursor, &size), cursor, exit); - TryRead(str8_deserial_read_block(data, cursor, size, &form.block), cursor, exit); - } break; - case DW_Form_Data1: { - TryRead(str8_deserial_read_block(data, cursor, sizeof(U8), &form.data), cursor, exit); - } break; - case DW_Form_Flag: { - TryRead(str8_deserial_read_struct(data, cursor, &form.flag), cursor, exit); - } break; - case DW_Form_SData: { - TryRead(str8_deserial_read_sleb128(data, cursor, &form.sdata), cursor, exit); - } break; - case DW_Form_UData: { - TryRead(str8_deserial_read_uleb128(data, cursor, &form.udata), cursor, exit); - } break; - case DW_Form_RefAddr: { - if (version < DW_Version_3) { - TryRead(str8_deserial_read(data, cursor, &form.ref, address_size, address_size), cursor, exit); - } else { - TryRead(str8_deserial_read_dwarf_uint(data, cursor, unit_format, &form.ref), cursor, exit); - } - } break; - case DW_Form_GNU_RefAlt: { - TryRead(str8_deserial_read_dwarf_uint(data, cursor, unit_format, &form.ref), cursor, exit); - } break; - case DW_Form_Ref1: { - TryRead(str8_deserial_read(data, cursor, &form.ref, 1, 1), cursor, exit); - } break; - case DW_Form_Ref2: { - TryRead(str8_deserial_read(data, cursor, &form.ref, 2, 2), cursor, exit); - } break; - case DW_Form_Ref4: { - TryRead(str8_deserial_read(data, cursor, &form.ref, 4, 4), cursor, exit); - } break; - case DW_Form_Ref8: { - TryRead(str8_deserial_read(data, cursor, &form.ref, 8, 8), cursor, exit); - } break; - case DW_Form_RefUData: { - TryRead(str8_deserial_read_uleb128(data, cursor, &form.ref), cursor, exit); - } break; - case DW_Form_SecOffset: - case DW_Form_LineStrp: - case DW_Form_GNU_StrpAlt: - case DW_Form_Strp: { - TryRead(str8_deserial_read_dwarf_uint(data, cursor, unit_format, &form.sec_offset), cursor, exit); - } break; - case DW_Form_ExprLoc: { - U64 expr_size = 0; - TryRead(str8_deserial_read_uleb128(data, cursor, &expr_size), cursor, exit); - TryRead(str8_deserial_read_block(data, cursor, expr_size, &form.exprloc), cursor, exit); - } break; - case DW_Form_FlagPresent: { - form.flag = 1; - } break; - case DW_Form_RefSig8: { - //U64 ref = 0; - //cursor = str8_deserial_read_struct(data, cursor, &ref); - NotImplemented; - } break; - case DW_Form_Addrx: - case DW_Form_RngListx: - case DW_Form_Strx: { - TryRead(str8_deserial_read_uleb128(data, cursor, &form.xval), cursor, exit); - } break; - case DW_Form_RefSup4: { - //U32 ref_sup4 = 0; - //cursor = str8_deserial_read_struct(data, cursor, &ref_sup4); - NotImplemented; - } break; - case DW_Form_StrpSup: { - TryRead(str8_deserial_read_dwarf_uint(data, cursor, unit_format, &form.strp_sup), cursor, exit); - } break; - case DW_Form_Data16: { - cursor = str8_deserial_read_block(data, cursor, 16, &form.data); - } break; - case DW_Form_ImplicitConst: { - // Special case. - // Unlike other forms that have their values stored in the .debug_info section, - // This one defines it's value in the .debug_abbrev section. - form.implicit_const = implicit_const; - } break; - case DW_Form_LocListx: { - TryRead(str8_deserial_read_uleb128(data, cursor, &form.xval), cursor, exit); - } break; - case DW_Form_RefSup8: { - NotImplemented; - } break; - case DW_Form_Strx1: { - TryRead(str8_deserial_read(data, cursor, &form.xval, 1, 1), cursor, exit); - } break; - case DW_Form_Strx2: { - TryRead(str8_deserial_read(data, cursor, &form.xval, 2, 2), cursor, exit); - } break; - case DW_Form_Strx3: { - TryRead(str8_deserial_read(data, cursor, &form.xval, 3, 3), cursor, exit); - } break; - case DW_Form_Strx4: { - TryRead(str8_deserial_read(data, cursor, &form.xval, 4, 4), cursor, exit); - } break; - case DW_Form_Addrx1: { - TryRead(str8_deserial_read(data, cursor, &form.xval, 1, 1), cursor, exit); - } break; - case DW_Form_Addrx2: { - TryRead(str8_deserial_read(data, cursor, &form.xval, 2, 2), cursor, exit); - } break; - case DW_Form_Addrx3: { - TryRead(str8_deserial_read(data, cursor, &form.xval, 3, 3), cursor, exit); - } break; - case DW_Form_Addrx4: { - TryRead(str8_deserial_read(data, cursor, &form.xval, 4, 4), cursor, exit); - } break; - default: InvalidPath; break; + }break; } - if (form_out) { - form.kind = form_kind; - *form_out = form; - } - if (bytes_read_out) { - *bytes_read_out = cursor; - } + // rjf: fill + out->version = version; + out->format = format; + out->abbrev_off = abbrev_off; + out->addr_size = addr_size; + out->kind = kind; + out->dwo_id = dwo_id; - is_ok = 1; - exit:; - Assert(is_ok); - return is_ok; -} - -internal U64 -dw_read_tag(Arena *arena, - DW_Raw *input, - DW_AbbrevTable abbrev_table, - DW_Version version, - DW_Format format, - U64 address_size, - Rng1U64 cu_info_range, - U64 tag_info_off, - DW_Tag *tag_out) -{ - U64 bytes_read = 0; - - String8 info_data = input->sec[DW_Section_Info].data; - String8 abbrev_data = input->sec[DW_Section_Abbrev].data; - - String8 tag_data = str8_substr(info_data, cu_info_range); - U64 tag_cursor = tag_info_off - cu_info_range.min; - - // read tag abbrev id - U64 tag_abbrev_id = 0; - TryRead(str8_deserial_read_uleb128(tag_data, tag_cursor, &tag_abbrev_id), tag_cursor, exit); - - B32 has_children = 0; - DW_TagKind tag_kind = DW_TagKind_Null; - DW_AttribList attribs = {0}; - if (tag_abbrev_id > 0) { - // map abbrev id -> .debug_abbrev offset - U64 abbrev_cursor = dw_abbrev_offset_from_abbrev_id(abbrev_table, tag_abbrev_id); - if (abbrev_cursor >= abbrev_data.size) { log_user_errorf("failed to find abbrev id 0x%I64x for tag 0x%I64x", tag_abbrev_id, tag_info_off); goto exit; } - - // read tag abbrev - DW_Abbrev tag_abbrev = {0}; - TryRead(dw_read_abbrev_tag(abbrev_data, abbrev_cursor, &tag_abbrev), abbrev_cursor, exit); - - has_children = !!(tag_abbrev.flags & DW_AbbrevFlag_HasChildren); - tag_kind = (DW_TagKind)tag_abbrev.sub_kind; - - // read attribs - for (; tag_cursor < tag_data.size && abbrev_cursor < abbrev_data.size; ) { - U64 attrib_tag_cursor = tag_cursor; - U64 attrib_abbrev_off = abbrev_cursor; - - // read attrib abbrev - DW_Abbrev attrib_abbrev = {0}; - TryRead(dw_read_abbrev_attrib(abbrev_data, abbrev_cursor, &attrib_abbrev), abbrev_cursor, exit); - - DW_AttribKind attrib_kind = (DW_AttribKind)attrib_abbrev.id; - DW_FormKind form_kind = (DW_FormKind)attrib_abbrev.sub_kind; - - // is this closing attrib? - if (attrib_kind == DW_AttribKind_Null) { break; } - - // special case, allows producer to embed form in .debug_info - if (form_kind == DW_Form_Indirect) { - TryRead(str8_deserial_read_uleb128(tag_data, tag_cursor, &form_kind), tag_cursor, exit); - } - - // read form value - DW_Form form = {0}; - U64 form_size = 0; - if (!dw_read_form(str8_skip(tag_data, tag_cursor), version, format, address_size, form_kind, attrib_abbrev.implicit_const, &form, &form_size)) { - goto exit; - } - tag_cursor += form_size; - - // fill out node - DW_AttribNode *attrib_n = push_array(arena, DW_AttribNode, 1); - attrib_n->v.info_off = cu_info_range.min + attrib_tag_cursor; - attrib_n->v.abbrev_off = attrib_abbrev_off; - attrib_n->v.abbrev_id = attrib_abbrev.id; - attrib_n->v.attrib_kind = attrib_kind; - attrib_n->v.form = form; - - // push node to list - SLLQueuePush(attribs.first, attribs.last, attrib_n); - attribs.count += 1; - } - } - - // fill out tag - tag_out->abbrev_id = tag_abbrev_id; - tag_out->has_children = has_children; - tag_out->kind = tag_kind; - tag_out->attribs = attribs; - tag_out->info_off = tag_info_off; - - bytes_read = tag_cursor - (tag_info_off - cu_info_range.min); - exit:; + // rjf: return # of bytes read + U64 bytes_read = (off - start_off); return bytes_read; } -internal U64 -dw_read_tag_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out) -{ - return dw_read_tag(arena, - input, - cu->abbrev_table, - cu->version, - cu->format, - cu->address_size, - cu->info_range, - info_off, - tag_out); -} - -internal B32 -dw_try_u64_from_const_value(U64 type_byte_size, DW_ATE type_encoding, String8 const_value, U64 *value_out) -{ - B32 is_parsed = 0; - if (const_value.size <= type_byte_size) { - U64 value_size = Min(type_byte_size, const_value.size); - if (value_size <= sizeof(*value_out)) { - MemoryZeroStruct(value_out); - MemoryCopy(value_out, const_value.str, value_size); - if (type_encoding == DW_ATE_Signed || type_encoding == DW_ATE_SignedChar) { - *value_out = extend_sign64(*value_out, value_size); - } - is_parsed = 1; - } else { - Assert(!"out value overflow"); - } - } - return is_parsed; -} +//////////////////////////////// +//~ rjf: Abbreviation Map Parsing internal U64 -dw_u64_from_const_value(String8 const_value) +dw2_read_abbrev(Arena *arena, String8 data, U64 off, DW2_AbbrevHeader *header_out, DW2_AbbrevAttribList *attribs_out) { - U64 result = 0; - B32 is_converted = dw_try_u64_from_const_value(sizeof(U64), DW_ATE_Unsigned, const_value, &result); - Assert(is_converted); // TODO: error handling - return result; -} - -internal U64 -dw_interp_sec_offset(DW_Form form) -{ - U64 sec_offset = 0; - if (form.kind == DW_Form_SecOffset) { - sec_offset = form.sec_offset; - } else if (form.kind != DW_Form_Null) { - AssertAlways(!"unexpected form"); - } - return sec_offset; -} - -internal String8 -dw_interp_exprloc(DW_Form form) -{ - String8 expr = {0}; - if (form.kind == DW_Form_ExprLoc) { - expr = form.exprloc; - } else if (form.kind != DW_Form_Null) { - AssertAlways(!"unexpected form"); - } - return expr; -} - -internal U128 -dw_interp_const_u128(DW_Form form) -{ - AssertAlways(form.data.size <= sizeof(U128)); - U128 result = {0}; - MemoryCopy(&result.u64[0], form.data.str, form.data.size); - return result; -} - -internal U64 -dw_interp_const64(U64 type_byte_size, DW_ATE type_encoding, DW_Form form) -{ - U64 result = max_U64; - if (form.kind == DW_Form_Data1 || form.kind == DW_Form_Data2 || form.kind == DW_Form_Data4 || form.kind == DW_Form_Data8 || form.kind == DW_Form_Data16) { - if (form.data.size <= sizeof(result)) { - if (!dw_try_u64_from_const_value(type_byte_size, type_encoding, form.data, &result)) { - Assert(!"unable to decode data"); - } - } else { - Assert(!"unable to cast U128 to U64"); - } - } else if (form.kind == DW_Form_UData) { - result = form.udata; - } else if (form.kind == DW_Form_SData) { - result = form.sdata; - } else if (form.kind == DW_Form_ImplicitConst) { - result = form.implicit_const; - } else if (form.kind == DW_Form_Null) { - // skip - } else { - AssertAlways(!"unexpected form"); - } - return result; -} - -internal U64 -dw_interp_const_u64(DW_Form form) -{ - return dw_interp_const64(sizeof(U64), DW_ATE_Unsigned, form); -} - -internal U32 -dw_interp_const_u32(DW_Form form) -{ - U64 const64 = dw_interp_const_u64(form); - U32 const32 = safe_cast_u32(const64); - return const32; -} - -internal S64 -dw_interp_const_s64(DW_Form form) -{ - U64 const_u64 = dw_interp_const_u64(form); - S64 const_s64 = (S64)const_u64; - return const_s64; -} - -internal S32 -dw_interp_const_s32(DW_Form form) -{ - U32 const_u32 = dw_interp_const_u32(form); - S32 const_s32 = (S32)const_u32; - return const_s32; -} - -internal U64 -dw_interp_address(U64 address_size, U64 base_addr, DW_ListUnit *addr_lu, DW_Form form) -{ - U64 address = 0; - if (form.kind == DW_Form_Addr) { - if (!dw_try_u64_from_const_value(address_size, DW_ATE_Address, form.addr, &address)) { - AssertAlways(!"unable to decode address"); - } - } else if (form.kind == DW_Form_Addrx || form.kind == DW_Form_Addrx1 || form.kind == DW_Form_Addrx2 || - form.kind == DW_Form_Addrx3 || form.kind == DW_Form_Addrx4) { - address = dw_addr_from_list_unit(addr_lu, form.xval); - } else if (form.kind == DW_Form_SecOffset) { - if (addr_lu->segment_selector_size > 0) { - AssertAlways(!"TODO: support for segmented address space"); - } - if (form.sec_offset + addr_lu->segment_selector_size + addr_lu->address_size <= addr_lu->entries.size) { - MemoryCopy(&address, addr_lu->entries.str + form.sec_offset, addr_lu->address_size); - } else { - Assert(!"out of bounds .debug_addr offset"); - } - } else if (form.kind != DW_Form_Null) { - AssertAlways(!"unexpected form"); - } - return address; -} - -internal String8 -dw_interp_block(DW_Raw *input, DW_CompUnit *cu, DW_Form form) -{ - NotImplemented; - return str8_zero(); -} - -internal String8 -dw_interp_string(DW_Raw *input, - DW_Format unit_format, - DW_ListUnit *str_offsets, - DW_Form form) -{ - String8 string = {0}; - if (form.kind == DW_Form_String) { - string = form.string; - } else if (form.kind == DW_Form_Strp) { - U64 bytes_read = str8_deserial_read_cstr(input->sec[DW_Section_Str].data, form.sec_offset, &string); - Assert(bytes_read > 0); - } else if (form.kind == DW_Form_LineStrp) { - U64 bytes_read = str8_deserial_read_cstr(input->sec[DW_Section_LineStr].data, form.sec_offset, &string); - Assert(bytes_read > 0); - } else if (form.kind == DW_Form_StrpSup) { - U64 bytes_read = str8_deserial_read_cstr(input->sec[DW_Section_Str].data, form.strp_sup, &string); - Assert(bytes_read > 0); - } else if (form.kind == DW_Form_Strx || form.kind == DW_Form_Strx1 || - form.kind == DW_Form_Strx2 || form.kind == DW_Form_Strx3 || - form.kind == DW_Form_Strx4) { - U64 sec_offset = dw_offset_from_list_unit(str_offsets, form.xval); - if (sec_offset < input->sec[DW_Section_Str].data.size) { - U64 bytes_read = str8_deserial_read_cstr(input->sec[DW_Section_Str].data, sec_offset, &string); - Assert(bytes_read > 0); - } else { - AssertAlways(!"unable to translate index to offset"); - } - } else if (form.kind == DW_Form_GNU_StrpAlt) { - NotImplemented; - } else if (form.kind == DW_Form_GNU_StrIndex) { - NotImplemented; - } else if (form.kind != DW_Form_Null) { - AssertAlways(!"unexpected form"); - } - return string; -} - -internal String8 -dw_interp_line_ptr(DW_Raw *input, DW_Form form) -{ - String8 result = {0}; - if (form.kind == DW_Form_SecOffset) { - result = str8_skip(input->sec[DW_Section_Line].data, form.sec_offset); - } else if (form.kind != DW_Form_Null) { - AssertAlways(!"unexpected form"); - } - return result; -} - -internal DW_LineFile * -dw_interp_file(DW_LineVM *line_vm, DW_Form form) -{ - U64 file_idx = dw_interp_const_u64(form); - DW_LineFile *result = dw_line_vm_find_file(line_vm, file_idx); - return result; -} - -internal DW_Reference -dw_interp_ref(DW_Raw *input, DW_CompUnit *cu, DW_Form form) -{ - DW_Reference ref = {0}; - if (form.kind == DW_Form_Ref1 || form.kind == DW_Form_Ref2 || - form.kind == DW_Form_Ref4 || form.kind == DW_Form_Ref8 || - form.kind == DW_Form_RefUData) { - ref.cu = cu; - ref.info_off = cu->info_range.min + form.ref; - } else if (form.kind == DW_Form_RefAddr) { - NotImplemented; - } else if (form.kind == DW_Form_RefSig8) { - NotImplemented; - } else if (form.kind == DW_Form_RefSup4 || form.kind == DW_Form_RefSup8) { - NotImplemented; - } else if (form.kind != DW_Form_Null) { - AssertAlways(!"unexpected form"); - } - return ref; -} - -internal DW_LocList -dw_interp_loclist(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form) -{ - DW_LocList loclist = {0}; + U64 start_off = off; - if (cu->version < DW_Version_5) { - if (form.kind == DW_Form_SecOffset) { - U64 sec_offset = max_U64; - if (form.kind == DW_Form_SecOffset) { - sec_offset = form.sec_offset; - } else if (form.kind == DW_Form_Data8 || form.kind == DW_Form_Data4 || - form.kind == DW_Form_Data2 || form.kind == DW_Form_Data1) { - if (!dw_try_u64_from_const_value(form.data.size, DW_ATE_Unsigned, form.data, &sec_offset)) { - Assert(!"unable to extract section offset"); - } - } else if (form.kind == DW_Form_Null) { - Assert(!"unexpected form"); - } - - String8 sec = str8_skip(input->sec[DW_Section_Loc].data, sec_offset); - U64 base_addr = cu->low_pc; - U64 base_sel = DW_SentinelFromSize(cu->address_size); - for (U64 cursor = 0; cursor < sec.size; ) { - U64 range_min = 0; - U64 range_min_off = cursor; - U64 range_min_size = str8_deserial_read(sec, range_min_off, &range_min, cu->address_size, cu->address_size); - if (range_min_size == 0) { - break; - } - U64 range_max = 0; - U64 range_max_off = cursor + cu->address_size; - U64 range_max_size = str8_deserial_read(sec, range_max_off, &range_max, cu->address_size, cu->address_size); - if (range_max_size == 0) { - break; - } - cursor += cu->address_size * 2; - - // series terminator - if (range_min == 0 && range_max == 0) { - break; - } - // set new base address - else if (range_min == base_sel) { - base_addr = range_max; - } - // location - else { - U16 expr_size = 0; - U64 expr_size_size = str8_deserial_read_struct(sec, cursor, &expr_size); - if (expr_size_size == 0) { - Assert(!"unable to read expression size"); - break; - } - cursor += expr_size_size; - - Assert(cursor + expr_size <= sec.size); - Rng1U64 expr_range = rng_1u64(cursor, ClampTop(cursor + expr_size, sec.size)); - - DW_LocNode *loc_n = push_array(arena, DW_LocNode, 1); - loc_n->v.range = rng_1u64(base_addr + range_min, base_addr + range_max); - loc_n->v.expr = str8_substr(sec, expr_range); - - SLLQueuePush(loclist.first, loclist.last, loc_n); - ++loclist.count; - - // advance past expression - cursor += expr_size; - } - } - } else if (form.kind != DW_Form_Null) { - AssertAlways(!"unexpected form"); - } - } else { - DW_Version version = DW_Version_Null; - String8 raw_lle = {0}; - if (form.kind == DW_Form_SecOffset) { - // offset is from beginning of the section - U64 sec_offset = form.sec_offset; - raw_lle = str8_skip(input->sec[DW_Section_LocLists].data, sec_offset); - } else if (form.kind == DW_Form_LocListx) { - // offset is from beginning of the entries - U64 entries_off = dw_offset_from_list_unit(cu->loclists_lu, form.xval); - raw_lle = str8_skip(cu->loclists_lu->entries, entries_off); - version = cu->loclists_lu->version; - } else if (form.kind != DW_Form_Null) { - AssertAlways(!"unexpected form"); - } - - for (U64 cursor = 0, keep_parsing = 1, base_addr = cu->low_pc; - cursor < raw_lle.size && keep_parsing; ) { - DW_LLE kind = DW_LLE_EndOfList; - cursor += str8_deserial_read_struct(raw_lle, cursor, &kind); - - Rng1U64 range = {0}; - switch (kind) { - default: - Assert(!"unknown kind"); - case DW_LLE_EndOfList: { - keep_parsing = 0; - } break; - case DW_LLE_BaseAddressx: { - if (!cu->addr_lu) { - keep_parsing = 0; - break; - } - - U64 addrx = 0; - U64 addrx_size = str8_deserial_read_uleb128(raw_lle, cursor, &addrx); - if (addrx_size == 0) { - keep_parsing = 0; - break; - } - - U64 base_addr_new = dw_addr_from_list_unit(cu->addr_lu, addrx); - if (base_addr_new == max_U64) { - InvalidPath; - break; - } - - base_addr = base_addr_new; - cursor += addrx_size; - } break; - case DW_LLE_StartxEndx: { - U64 start_addrx = 0; - U64 start_addrx_size = str8_deserial_read_uleb128(raw_lle, cursor, &start_addrx); - if (start_addrx_size == 0) { - keep_parsing = 0; - break; - } - U64 end_addrx = 0; - U64 end_addrx_size = str8_deserial_read_uleb128(raw_lle, cursor + start_addrx_size, &end_addrx); - if (end_addrx_size == 0) { - keep_parsing = 0; - break; - } - cursor += start_addrx_size; - cursor += end_addrx_size; - - U64 start = dw_addr_from_list_unit(cu->addr_lu, start_addrx); - U64 end = dw_addr_from_list_unit(cu->addr_lu, end_addrx); - Assert(start != max_U64); - Assert(end != max_U64); - - range = rng_1u64(start, end); - } break; - case DW_LLE_StartxLength: { - U64 start_addrx = 0; - U64 start_addrx_size = str8_deserial_read_uleb128(raw_lle, cursor, &start_addrx); - if (start_addrx_size == 0) { - keep_parsing = 0; - break; - } - - // parse pre-standard & standard length - U64 length_off = cursor + start_addrx_size; - U64 length = 0; - U64 length_size = str8_deserial_read_uleb128(raw_lle, length_off, &length); - if (length_size == 0) { - keep_parsing = 0; - break; - } - - cursor += start_addrx_size; - cursor += length_size; - - if (cu->addr_lu) { - U64 start = dw_addr_from_list_unit(cu->addr_lu, start_addrx); - Assert(start < max_U64); - - range = rng_1u64(start, start + length); - } else { - Assert(!".debug_addr section is missing -- unable to interpret address index"); - } - } break; - case DW_LLE_OffsetPair: { - U64 start = 0; - U64 start_size = str8_deserial_read_uleb128(raw_lle, cursor, &start); - if (start_size == 0) { - keep_parsing = 0; - break; - } - U64 end = 0; - U64 end_size = str8_deserial_read_uleb128(raw_lle, cursor + start_size, &end); - if (end_size == 0) { - keep_parsing = 0; - break; - } - cursor += start_size; - cursor += end_size; - - range = rng_1u64(base_addr + start, base_addr + end); - } break; - case DW_LLE_DefaultLocation: { - // no range - int x = 0; - } break; - case DW_LLE_BaseAddress: { - U64 base_addr_size = str8_deserial_read(raw_lle, cursor, &base_addr, cu->address_size, cu->address_size); - if (base_addr_size == 0) { - keep_parsing = 0; - break; - } - cursor += base_addr_size; - } break; - case DW_LLE_StartEnd: { - U64 start = 0; - U64 start_size = str8_deserial_read(raw_lle, cursor, &start, cu->address_size, cu->address_size); - if (start_size == 0) { - keep_parsing = 0; - break; - } - - U64 end = 0; - U64 end_size = str8_deserial_read(raw_lle, cursor + start_size, &end, cu->address_size, cu->address_size); - if (end_size == 0) { - keep_parsing = 0; - break; - } - cursor += start_size; - cursor += end_size; - - range = rng_1u64(start, end); - } break; - case DW_LLE_StartLength: { - U64 start = 0; - U64 start_size = str8_deserial_read(raw_lle, cursor, &start, cu->address_size, cu->address_size); - if (start_size == 0) { - keep_parsing = 0; - break; - } - U64 length = 0; - U64 length_size = str8_deserial_read_uleb128(raw_lle, cursor + start_size, &length); - if (length_size == 0) { - keep_parsing = 0; - break; - } - cursor += start_size; - cursor += length_size; - - range = rng_1u64(start, start + length); - } break; - } - - B32 has_expr = keep_parsing && kind != DW_LLE_BaseAddressx && kind != DW_LLE_BaseAddress; - if (has_expr) { - U64 expr_size = 0; - U64 expr_size_size = str8_deserial_read_uleb128(raw_lle, cursor, &expr_size); - if (expr_size_size == 0) { - keep_parsing = 0; - break; - } - - String8 expr = {0}; - U64 expr_read_size = str8_deserial_read_block(raw_lle, cursor + expr_size_size, expr_size, &expr); - if (expr_read_size != expr_size) { - keep_parsing = 0; - break; - } - - cursor += expr_size_size; - cursor += expr_size; - - DW_LocNode *loc_n = push_array(arena, DW_LocNode, 1); - loc_n->v.range = range; - loc_n->v.expr = expr; - - SLLQueuePush(loclist.first, loclist.last, loc_n); - ++loclist.count; - } - } - } - - return loclist; -} - -internal B32 -dw_interp_flag(DW_Form form) -{ - B32 flag = 0; - if (form.kind == DW_Form_Flag || form.kind == DW_Form_FlagPresent) { - flag = form.flag; - } else if (form.kind != DW_Form_Null) { - AssertAlways(!"unexpected form"); - } - return flag; -} - -internal Rng1U64List -dw_interp_rnglist(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form) -{ - Rng1U64List rnglist = {0}; - - if (cu->version < DW_Version_5) { - // decode section offset - U64 sec_offset = max_U64; - if (form.kind == DW_Form_SecOffset) { - sec_offset = form.sec_offset; - } else if (form.kind == DW_Form_Data8 || form.kind == DW_Form_Data4 || - form.kind == DW_Form_Data2 || form.kind == DW_Form_Data1) { - if (!dw_try_u64_from_const_value(form.data.size, DW_ATE_Unsigned, form.data, &sec_offset)) { - Assert(!"unable to extract section offset"); - } - } else if (form.kind != DW_Form_Null) { - Assert(!"unexpected form"); - } - - String8 sec = str8_skip(input->sec[DW_Section_Ranges].data, sec_offset); - U64 base_addr = cu->low_pc; - U64 base_sel = DW_SentinelFromSize(cu->address_size); - for (U64 cursor = 0; cursor < sec.size; ) { - U64 range_min = 0; - U64 range_min_off = cursor; - U64 range_min_size = str8_deserial_read(sec, range_min_off, &range_min, cu->address_size, cu->address_size); - if (range_min_size == 0) { - break; - } - U64 range_max = 0; - U64 range_max_off = cursor + cu->address_size; - U64 range_max_size = str8_deserial_read(sec, range_max_off, &range_max, cu->address_size, cu->address_size); - if (range_max_size == 0) { - break; - } - cursor += cu->address_size * 2; - - // series terminator - if (range_min == 0 && range_max == 0) { - break; - } - // set new base address - else if (range_min == base_sel) { - base_addr = range_max; - } - // range - else { - Rng1U64 range = rng_1u64(base_addr + range_min, base_addr + range_max); - rng1u64_list_push(arena, &rnglist, range); - } - } - } else { - String8 raw_rle = {0}; - if (form.kind == DW_Form_SecOffset) { - // offset is from beginning of the section - U64 sec_offset = form.sec_offset; - raw_rle = str8_skip(input->sec[DW_Section_RngLists].data, sec_offset); - } else if (form.kind == DW_Form_RngListx) { - // offset is from beginning of the entries - U64 sec_offset = dw_offset_from_list_unit(cu->rnglists_lu, form.xval); - raw_rle = str8_skip(cu->rnglists_lu->entries, sec_offset); - } else if (form.kind != DW_Form_Null) { - AssertAlways(!"unexpected form"); - } - - U64 rle_invalid_value = DW_SentinelFromSize(cu->address_size); - U64 base_addr = cu->low_pc; - for (U64 cursor = 0, keep_parsing = 1; cursor < raw_rle.size && keep_parsing; ) { - DW_RLE kind = DW_RLE_EndOfList; - cursor += str8_deserial_read_struct(raw_rle, cursor, &kind); - - Rng1U64 range = rng_1u64(rle_invalid_value, rle_invalid_value); - switch (kind) { - default: - case DW_RLE_EndOfList: { - keep_parsing = 0; - } break; - case DW_RLE_BaseAddressx: { - U64 addrx = 0; - U64 addrx_size = str8_deserial_read_uleb128(raw_rle, cursor, &addrx); - if (addrx_size == 0) { - keep_parsing = 0; - break; - } - if (cu->addr_lu == 0) { - keep_parsing = 0; - break; - } - U64 base_addr_new = dw_addr_from_list_unit(cu->addr_lu, addrx); - if (base_addr_new < max_U64) { - base_addr = base_addr_new; - cursor += addrx_size; - } else { - keep_parsing = 0; - Assert(!"invalid addrx"); - } - } break; - case DW_RLE_StartxLength: { - U64 start_addrx = 0; - U64 start_addrx_size = str8_deserial_read_uleb128(raw_rle, cursor, &start_addrx); - if (start_addrx_size == 0) { - keep_parsing = 0; - break; - } - U64 length = 0; - U64 length_size = str8_deserial_read_uleb128(raw_rle, cursor + start_addrx_size, &length); - if (length_size == 0) { - keep_parsing = 0; - break; - } - cursor += start_addrx_size; - cursor += length_size; - - if (cu->addr_lu) { - U64 start = dw_addr_from_list_unit(cu->addr_lu, start_addrx); - AssertAlways(start < max_U64); - range = rng_1u64(start, start + length); - } - } break; - case DW_RLE_OffsetPair: { - U64 offset_start, offset_end = 0; - U64 offset_start_size = str8_deserial_read_uleb128(raw_rle, cursor, &offset_start); - if (offset_start_size == 0) { - keep_parsing = 0; - break; - } - U64 offset_end_size = str8_deserial_read_uleb128(raw_rle, cursor + offset_start_size, &offset_end); - if (offset_end_size == 0) { - keep_parsing = 0; - break; - } - cursor += offset_start_size; - cursor += offset_end_size; - - range = rng_1u64(base_addr + offset_start, base_addr + offset_end); - } break; - case DW_RLE_BaseAddress: { - U64 base_addr_size = str8_deserial_read(raw_rle, cursor, &base_addr, cu->address_size, cu->address_size); - if (base_addr_size == 0) { - keep_parsing = 0; - break; - } - cursor += base_addr_size; - } break; - case DW_RLE_StartEnd: { - U64 start = 0, end = 0; - - U64 start_size = str8_deserial_read(raw_rle, cursor, &start, cu->address_size, cu->address_size); - if (start_size == 0) { - keep_parsing = 0; - break; - } - U64 end_size = str8_deserial_read(raw_rle, cursor + start_size, &end, cu->address_size, cu->address_size); - if (end_size == 0) { - keep_parsing = 0; - break; - } - cursor += start_size; - cursor += end_size; - - range = rng_1u64(start, end); - } break; - case DW_RLE_StartLength: { - U64 start = 0, length = 0; - - U64 start_size = str8_deserial_read(raw_rle, cursor, &start, cu->address_size, cu->address_size); - if (start_size == 0) { - keep_parsing = 0; - break; - } - U64 length_size = str8_deserial_read_uleb128(raw_rle, cursor + start_size, &length); - if (length_size == 0) { - keep_parsing = 0; - break; - } - cursor += start_size; - cursor += length_size; - - range = rng_1u64(start, start + length); - } break; - } - - if (range.min != rle_invalid_value) { - rng1u64_list_push(arena, &rnglist, range); - } - } - } - - return rnglist; -} - -internal String8 -dw_interp_secptr(DW_Raw *input, DW_SectionKind section, DW_Form form) -{ - String8 secptr = {0}; - if (form.kind == DW_Form_SecOffset) { - String8 sect = input->sec[section].data; - Rng1U64 range = rng_1u64(form.sec_offset, sect.size); - secptr = str8_substr(sect, range); - } else if (form.kind != DW_Form_Null) { - Assert(!"unexpected form"); - } - return secptr; -} - -internal String8 -dw_interp_addrptr(DW_Raw *input, DW_Form form) -{ - return dw_interp_secptr(input, DW_Section_Addr, form); -} - -internal String8 -dw_interp_str_offsets_ptr(DW_Raw *input, DW_Form form) -{ - return dw_interp_secptr(input, DW_Section_StrOffsets, form); -} - -internal String8 -dw_interp_rnglists_ptr(DW_Raw *input, DW_Form form) -{ - return dw_interp_secptr(input, DW_Section_RngLists, form); -} - -internal String8 -dw_interp_loclists_ptr(DW_Raw *input, DW_Form form) -{ - return dw_interp_secptr(input, DW_Section_LocLists, form); -} - -internal DW_AttribClass -dw_value_class_from_attrib(DW_CompUnit *cu, DW_Attrib *attrib) -{ - return dw_pick_attrib_value_class(cu->version, cu->ext, cu->relaxed, attrib->attrib_kind, attrib->form.kind); -} - -internal String8 -dw_exprloc_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_ExprLoc || value_class == DW_AttribClass_Block); - return dw_interp_exprloc(attrib->form); -} - -internal U128 -dw_const_u128_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); - return dw_interp_const_u128(attrib->form); -} - -internal U64 -dw_const_u64_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); - return dw_interp_const_u64(attrib->form); -} - -internal U32 -dw_const_u32_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); - return dw_interp_const_u32(attrib->form); -} - -internal S64 -dw_const_s64_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); - return dw_interp_const_s64(attrib->form); -} - -internal S32 -dw_const_s32_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); - return dw_interp_const_s32(attrib->form); -} - -internal B32 -dw_flag_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Flag); - return dw_interp_flag(attrib->form); -} - -internal U64 -dw_address_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || - value_class == DW_AttribClass_Address || - value_class == DW_AttribClass_AddrPtr); - DW_Form form = attrib->form; - if (value_class == DW_AttribClass_AddrPtr) { - if (attrib->form.kind == DW_Form_SecOffset) { - NotImplemented; - } else { - AssertAlways(!"unexpected form"); - } - - form.kind = DW_Form_Addr; - form.addr = dw_interp_addrptr(input, attrib->form); - } - return dw_interp_address(cu->address_size, cu->low_pc, cu->addr_lu, form); -} - -internal String8 -dw_block_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Block); - return dw_interp_block(input, cu, attrib->form); -} - -internal String8 -dw_string_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_String || value_class == DW_AttribClass_StrOffsetsPtr); - return dw_interp_string(input, cu->format, cu->str_offsets_lu, attrib->form); -} - -internal String8 -dw_line_ptr_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_LinePtr); - return dw_interp_line_ptr(input, attrib->form); -} - -internal DW_LineFile * -dw_file_from_attrib(DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); - return dw_interp_file(line_vm, attrib->form); -} - -internal DW_Reference -dw_ref_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Reference); - return dw_interp_ref(input, cu, attrib->form); -} - -internal DW_LocList -dw_loclist_from_attrib(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - AssertAlways(value_class == DW_AttribClass_Null || - value_class == DW_AttribClass_LocList || - value_class == DW_AttribClass_LocListPtr); - return dw_interp_loclist(arena, input, cu, attrib->form); -} - -internal Rng1U64List -dw_rnglist_from_attrib(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - Rng1U64List rnglist = {0}; - DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); - if (value_class == DW_AttribClass_RngListPtr || value_class == DW_AttribClass_RngList) { - rnglist = dw_interp_rnglist(arena, input, cu, attrib->form); - } else if (value_class != DW_AttribClass_Null) { - Assert(!"unexpected value class"); - } - return rnglist; -} - -internal DW_Attrib * -dw_attrib_from_tag_(DW_Tag tag, DW_AttribKind kind) -{ - local_persist read_only DW_Attrib null_attrib; - DW_Attrib *attrib = &null_attrib; - for (DW_AttribNode *attrib_n = tag.attribs.first; attrib_n != 0; attrib_n = attrib_n->next) { - if (attrib_n->v.attrib_kind == kind) { - attrib = &attrib_n->v; - break; - } - } - return attrib; -} - -internal DW_Attrib * -dw_attrib_from_tag(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - DW_Attrib *attrib = dw_attrib_from_tag_(tag, kind); - - if (attrib->attrib_kind == DW_AttribKind_Null) { - if (cu && cu->tag_ht) { - DW_Attrib *ao_attrib = dw_attrib_from_tag_(tag, DW_AttribKind_AbstractOrigin); - if (ao_attrib->attrib_kind == DW_AttribKind_AbstractOrigin) { - DW_Reference ref = dw_interp_ref(input, cu, ao_attrib->form); - DW_TagNode *ref_tag = dw_tag_node_from_info_off(ref.cu, ref.info_off); - attrib = dw_attrib_from_tag_(ref_tag->tag, kind); - } - } - } - - return attrib; -} - -internal B32 -dw_tag_has_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); - B32 has_attrib = attrib->attrib_kind != DW_AttribKind_Null; - return has_attrib; -} - -internal String8 -dw_exprloc_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - return dw_exprloc_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal String8 -dw_block_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - return dw_block_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal U128 -dw_const_u128_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - return dw_const_u128_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal U64 -dw_const_u64_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - return dw_const_u64_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal U32 -dw_const_u32_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - return dw_const_u32_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal U64 -dw_address_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - return dw_address_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal String8 -dw_string_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - return dw_string_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal String8 -dw_line_ptr_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - return dw_line_ptr_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal DW_Reference -dw_ref_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - return dw_ref_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal DW_LocList -dw_loclist_from_tag_attrib_kind(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - return dw_loclist_from_attrib(arena, input, cu, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal Rng1U64List -dw_rnglist_from_tag_attrib_kind(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - return dw_rnglist_from_attrib(arena, input, cu, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal B32 -dw_flag_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - return dw_flag_from_attrib(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal DW_LineFile * -dw_file_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Tag tag, DW_AttribKind kind) -{ - return dw_file_from_attrib(cu, line_vm, dw_attrib_from_tag(input, cu, tag, kind)); -} - -internal B32 -dw_try_byte_size_from_tag(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, U64 *byte_size_out) -{ - B32 has_byte_size = dw_tag_has_attrib(input, cu, tag, DW_AttribKind_ByteSize); - B32 has_bit_size = dw_tag_has_attrib(input, cu, tag, DW_AttribKind_BitSize ); - - if (has_byte_size && has_bit_size) { - Assert(!"ill formated byte size"); - } - - if (has_byte_size) { - *byte_size_out = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_ByteSize); - return 1; - } else if (has_bit_size) { - U64 bit_size = dw_const_u64_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_BitSize); - *byte_size_out = bit_size / 8; - return 1; - } - - return 0; -} - -internal U64 -dw_byte_size_from_tag(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag) -{ - U64 byte_size = max_U64; - dw_try_byte_size_from_tag(input, cu, tag, &byte_size); - return byte_size; -} - -internal U32 -dw_byte_size_32_from_tag(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag) -{ - U32 byte_size32 = 0; - U64 byte_size64; - if (dw_try_byte_size_from_tag(input, cu, tag, &byte_size64)) { - byte_size32 = safe_cast_u32(byte_size64); - } - return byte_size32; -} - -internal U64 -dw_u64_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) -{ - U64 result = 0; - DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); - DW_AttribClass attrib_class = dw_value_class_from_attrib(cu, attrib); - if (attrib_class == DW_AttribClass_Const || attrib_class == DW_AttribClass_Block) { - if (dw_tag_has_attrib(input, cu, tag, DW_AttribKind_Type)) { - Temp scratch = scratch_begin(0,0); - DW_Reference type_ref = dw_ref_from_tag_attrib_kind(input, cu, tag, DW_AttribKind_Type); - DW_Tag type_tag = {0}; - dw_read_tag_cu(scratch.arena, input, type_ref.cu, type_ref.info_off, &type_tag); - U64 type_byte_size = dw_byte_size_from_tag(input, cu, type_tag); - DW_ATE type_encoding = dw_const_u64_from_tag_attrib_kind(input, type_ref.cu, type_tag, DW_AttribKind_Encoding); - if (type_encoding == DW_ATE_Unsigned || type_encoding == DW_ATE_UnsignedChar) { - result = dw_interp_const64(type_byte_size, type_encoding, attrib->form); - } - scratch_end(scratch); - } else { - result = dw_interp_const_u64(attrib->form); - } - } else if (attrib_class == DW_AttribClass_Address) { - result = dw_address_from_attrib(input, cu, attrib); - } else if (attrib_class == DW_AttribClass_Reference) { - NotImplemented; - } else if (attrib_class != DW_AttribClass_Null) { - AssertAlways(!"unexpected attrib class"); - } - return result; -} - -internal B32 -dw_is_attrib_var_ref(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib) -{ - B32 is_var_ref = 0; - if (dw_is_form_kind_ref(cu->version, cu->ext, attrib->form.kind)) { - Temp scratch = scratch_begin(0,0); - DW_Reference ref = dw_ref_from_attrib(input, cu, attrib); - DW_Tag ref_tag = {0}; - if (dw_read_tag_cu(scratch.arena, input, ref.cu, ref.info_off, &ref_tag)) { - is_var_ref = ref_tag.kind == DW_TagKind_Variable; - } - scratch_end(scratch); - } - return is_var_ref; -} - -internal DW_CompUnit -dw_cu_from_info_off(Arena *arena, DW_Raw *input, DW_ListUnitInput lu_input, U64 cu_header_offset, B32 relaxed) -{ - DW_CompUnit cu = {0}; - - U32 first_four_bytes = 0; - if (str8_deserial_read_struct(input->sec[DW_Section_Info].data, 0, &first_four_bytes) != sizeof(first_four_bytes)) { goto exit; } - DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit; - - // read unit size in bytes - U64 length = 0; - U64 length_size = str8_deserial_read_dwarf_packed_size(input->sec[DW_Section_Info].data, cu_header_offset, &length); - if (length_size == 0) { goto exit; } - - // compute unit range - Rng1U64 info_range = rng_1u64(cu_header_offset, cu_header_offset + length_size + length); - String8 info = str8_substr(input->sec[DW_Section_Info].data, info_range); - U64 info_cursor = length_size; - - // read version - DW_Version version; - TryRead(str8_deserial_read_struct(info, info_cursor, &version), info_cursor, exit); - - U64 abbrev_base = max_U64; - U8 address_size = 0; - DW_CompUnitKind unit_kind = DW_CompUnitKind_Reserved; - U64 spec_dwo_id = max_U64; - B32 is_header_ok = 0; - switch (version) { - default: - case DW_Version_Null: { - } break; - case DW_Version_1: { - NotImplemented; - } break; - case DW_Version_2: { - U32 abbrev_base32; - TryRead(str8_deserial_read_struct(info, info_cursor, &abbrev_base32), info_cursor, exit); - TryRead(str8_deserial_read_struct(info, info_cursor, &address_size), info_cursor, exit); - abbrev_base = abbrev_base32; - is_header_ok = 1; - } break; - case DW_Version_3: - case DW_Version_4: { - TryRead(str8_deserial_read_dwarf_uint(info, info_cursor, format, &abbrev_base), info_cursor, exit); - TryRead(str8_deserial_read_struct (info, info_cursor, &address_size), info_cursor, exit); - is_header_ok = 1; - } break; - case DW_Version_5: { - TryRead(str8_deserial_read_struct (info, info_cursor, &unit_kind), info_cursor, exit); - TryRead(str8_deserial_read_struct (info, info_cursor, &address_size), info_cursor, exit); - TryRead(str8_deserial_read_dwarf_uint(info, info_cursor, format, &abbrev_base), info_cursor, exit); - if (unit_kind == DW_CompUnitKind_Skeleton || input->sec[DW_Section_Info].is_dwo) { - TryRead(str8_deserial_read_struct(info, info_cursor, &spec_dwo_id), info_cursor, exit); - } - is_header_ok = 1; - } break; - } - - U64 header_size = info_cursor; - - if (is_header_ok) { - Temp temp = temp_begin(arena); - - // TODO: cache abbrev tables with identical offsets - DW_AbbrevTable abbrev_table = dw_make_abbrev_table(arena, input->sec[DW_Section_Abbrev].data, abbrev_base); - - DW_Tag cu_tag = {0}; - dw_read_tag(arena, input, abbrev_table, version, format, address_size, info_range, cu_header_offset + header_size, &cu_tag); - - // TODO: handle these unit types - if (cu_tag.kind == DW_TagKind_SkeletonUnit) { log_user_errorf("TODO: Skeleton Unit"); } - if (cu_tag.kind == DW_TagKind_TypeUnit) { log_user_errorf("TODO Type Unit"); } - - if (cu_tag.kind != DW_TagKind_CompileUnit && cu_tag.kind != DW_TagKind_PartialUnit) { - // unexpected tag, release memory and exit - temp_end(temp); - goto exit; - } - - // fetch attribs for list sections - DW_Attrib *addr_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_AddrBase ); - DW_Attrib *str_offsets_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_StrOffsetsBase); - DW_Attrib *rnglists_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_RngListsBase ); - DW_Attrib *loclists_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_LocListsBase ); - - // interp attribs as section offsets - U64 addr_sec_off = dw_interp_sec_offset(addr_base_attrib->form ); - U64 str_offsets_sec_off = dw_interp_sec_offset(str_offsets_base_attrib->form); - U64 rnglists_sec_off = dw_interp_sec_offset(rnglists_base_attrib->form ); - U64 loclists_sec_off = dw_interp_sec_offset(loclists_base_attrib->form ); - - // map section offset to unit index - U64 addr_lu_num = rng1u64_array_num_from_value__binary_search(&lu_input.addr_ranges, addr_sec_off ); - U64 str_offsets_lu_num = rng1u64_array_num_from_value__binary_search(&lu_input.str_offset_ranges, str_offsets_sec_off); - U64 rnglists_lu_num = rng1u64_array_num_from_value__binary_search(&lu_input.rnglist_ranges, rnglists_sec_off ); - U64 loclists_lu_num = rng1u64_array_num_from_value__binary_search(&lu_input.loclist_ranges, loclists_sec_off ); - - // map index to unit - DW_ListUnit *addr_lu = 0 < (addr_lu_num && addr_lu_num <= lu_input.addr_count) ? &lu_input.addrs[addr_lu_num-1] : 0; - DW_ListUnit *str_offsets_lu = 0 < (str_offsets_lu_num && str_offsets_lu_num <= lu_input.str_offset_count) ? &lu_input.str_offsets[str_offsets_lu_num-1] : 0; - DW_ListUnit *rnglists_lu = 0 < (rnglists_lu_num && rnglists_lu_num <= lu_input.rnglist_count) ? &lu_input.rnglists[rnglists_lu_num-1] : 0; - DW_ListUnit *loclists_lu = 0 < (loclists_lu_num && loclists_lu_num <= lu_input.loclist_count) ? &lu_input.loclists[loclists_lu_num-1] : 0; - - // find compile unit base address - DW_Attrib *low_pc_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_AttribKind_LowPc); - U64 low_pc = dw_interp_address(address_size, max_U64, addr_lu, low_pc_attrib->form); - - // fill out compile unit - cu.relaxed = relaxed; - cu.ext = DW_Ext_All; - cu.kind = unit_kind; - cu.version = version; - cu.format = format; - cu.address_size = address_size; - cu.abbrev_off = abbrev_base; - cu.info_range = info_range; - cu.first_tag_info_off = cu_header_offset + header_size; - cu.abbrev_table = abbrev_table; - cu.addr_lu = addr_lu; - cu.str_offsets_lu = str_offsets_lu; - cu.rnglists_lu = rnglists_lu; - cu.loclists_lu = loclists_lu; - cu.low_pc = low_pc; - cu.tag = cu_tag; - } - - exit:; - return cu; -} - -internal void -dw_tag_tree_from_data(Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_TagNode *parent, U64 *cursor, U64 *tag_count) -{ - while (*cursor < cu->info_range.max) { - // read tag - DW_Tag tag = {0}; - TryRead(dw_read_tag(arena, input, cu->abbrev_table, cu->version, cu->format, cu->address_size, cu->info_range, *cursor, &tag), *cursor, exit); - - // reached of the CU? - if (tag.kind == DW_TagKind_Null) { break; } - - // normal tag - DW_TagNode *tag_n = push_array(arena, DW_TagNode, 1); - tag_n->tag = tag; - - SLLQueuePush_N(parent->first_child, parent->last_child, tag_n, sibling); - - // update tag count - *tag_count += 1; - - if (tag.has_children) { - dw_tag_tree_from_data(arena, input, cu, tag_n, cursor, tag_count); - } - } - exit:; -} - -internal DW_TagTree -dw_tag_tree_from_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu) -{ - DW_TagNode root = {0}; - U64 cursor = cu->first_tag_info_off; - U64 tag_count = 0; - dw_tag_tree_from_data(arena, input, cu, &root, &cursor, &tag_count); - Assert(cursor == cu->info_range.max); - return (DW_TagTree){ .root = root.first_child, .tag_count = tag_count }; -} - -internal HashTable * -dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree) -{ - Temp scratch = scratch_begin(&arena, 1); - - struct Frame { - struct Frame *next; - DW_TagNode *node; - }; - - struct Frame *free_frames = 0; - struct Frame *stack = push_array(scratch.arena, struct Frame, 1); - stack->node = tag_tree.root; - - HashTable *ht = hash_table_init(arena, (U64)((F64)tag_tree.tag_count * 1.3)); - - while (stack) { - while (stack->node) { - hash_table_push_u64_raw(arena, ht, stack->node->tag.info_off, stack->node); - - if (stack->node->first_child) { - struct Frame *frame = free_frames; - if (frame) { - SLLStackPop(free_frames); - MemoryZeroStruct(frame); - } else { - frame = push_array(scratch.arena, struct Frame, 1); - } - frame->node = stack->node->first_child; - SLLStackPush(stack, frame); - } else { - stack->node = stack->node->sibling; - } - } - - // recycle free frame - struct Frame *frame = stack; - SLLStackPop(stack); - SLLStackPush(free_frames, frame); - - if (stack) { - stack->node = stack->node->sibling; - } - } - - scratch_end(scratch); - return ht; -} - -internal DW_TagNode * -dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off) -{ - DW_TagNode *tag_node = hash_table_search_u64_raw(cu->tag_ht, info_off); - return tag_node; -} - -internal U64 -dw_read_line_vm_header(Arena *arena, - DW_Raw *input, - String8 cu_stmt_list, - String8 cu_dir, - String8 cu_name, - U8 cu_address_size, - DW_ListUnit *cu_str_offsets, - DW_LineVMHeader *header_out) -{ - Temp scratch = scratch_begin(&arena, 1); - - U64 cursor = 0; - - U32 first_four_bytes = 0; - if (str8_deserial_read_struct(cu_stmt_list, 0, &first_four_bytes) != sizeof(U32)) { goto exit; } - - // read unit length - U64 length = 0; - U64 length_size = str8_deserial_read_dwarf_packed_size(cu_stmt_list, 0, &length); - DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit; - - cursor = length_size; - String8 data = str8_substr(cu_stmt_list, r1u64(0, length + length_size)); - - // read unit version - DW_Version version = DW_Version_Null; - TryRead(str8_deserial_read_struct(data, cursor, &version), cursor, exit); - - // read DWARF5 address & segment selector - U8 address_size = cu_address_size; - U8 segsel_size = 0; - if (version == DW_Version_5) { - TryRead(str8_deserial_read_struct(data, cursor, &address_size), cursor, exit); - TryRead(str8_deserial_read_struct(data, cursor, &segsel_size), cursor, exit); - } - - U64 header_length = 0; - TryRead(str8_deserial_read_dwarf_uint(data, cursor, format, &header_length), cursor, exit); - U64 line_program_off = cursor + header_length; - - // substring header so we dont overread into the line program - data = str8_prefix(data, cursor + header_length); - - U8 min_inst_len = 0; - TryRead(str8_deserial_read_struct(data, cursor, &min_inst_len), cursor, exit); - - U8 max_ops_for_inst = 1; - if (version > DW_Version_3) { - TryRead(str8_deserial_read_struct(data, cursor, &max_ops_for_inst), cursor, exit); - Assert(max_ops_for_inst > 0); - } - - U8 default_is_stmt = 0; - TryRead(str8_deserial_read_struct(data, cursor, &default_is_stmt), cursor, exit); - - S8 line_base = 0; - TryRead(str8_deserial_read_struct(data, cursor, &line_base), cursor, exit); - - U8 line_range = 0; - TryRead(str8_deserial_read_struct(data, cursor, &line_range), cursor, exit); - - U8 opcode_base = 0; - TryRead(str8_deserial_read_struct(data, cursor, &opcode_base), cursor, exit); - - U64 num_opcode_lens = opcode_base > 0 ? opcode_base - 1 : 0; - String8 opcode_lens; - TryRead(str8_deserial_read_block(data, cursor, num_opcode_lens * sizeof(U8), &opcode_lens), cursor, exit); - - String8Array dir_table = {0}; - DW_LineFileArray file_table = {0}; - if (version < DW_Version_5) { - // read directory table - String8List dir_list = {0}; - - // compile directory is always first in the table - str8_list_push(scratch.arena, &dir_list, cu_dir); - - // parse additional directories - while (cursor < data.size) { - String8 dir = {0}; - TryRead(str8_deserial_read_cstr(data, cursor, &dir), cursor, exit); - if (dir.size == 0) { break; } - str8_list_push(scratch.arena, &dir_list, dir); - } - - DW_LineFileList file_list = {0}; - { - // compile unit name is always first in the file table - { - DW_LineFileNode *node = push_array(scratch.arena, DW_LineFileNode, 1); - node->file.path = cu_name; - SLLQueuePush(file_list.first, file_list.last, node); - file_list.node_count += 1; - } - - // read file table - while (cursor < data.size) { - U8 first_byte = 0; - if (str8_deserial_read_struct(data, cursor, &first_byte) == 0) { goto exit; } - if (first_byte == 0) { break; } - - DW_LineFile file = {0}; - TryRead(str8_deserial_read_cstr (data, cursor, &file.path), cursor, exit); - TryRead(str8_deserial_read_uleb128(data, cursor, &file.dir_idx), cursor, exit); - TryRead(str8_deserial_read_uleb128(data, cursor, &file.time_stamp), cursor, exit); - TryRead(str8_deserial_read_uleb128(data, cursor, &file.size), cursor, exit); - - DW_LineFileNode *node = push_array(scratch.arena, DW_LineFileNode, 1); - node->file = file; - - SLLQueuePush(file_list.first, file_list.last, node); - file_list.node_count += 1; - } - } - - // dir list -> array - dir_table = str8_array_from_list(arena, &dir_list); - - // file list -> array - file_table.count = 0; - file_table.v = push_array(arena, DW_LineFile, file_list.node_count); - for EachNode(n, DW_LineFileNode, file_list.first) { - DW_LineFile *dst = &file_table.v[file_table.count++]; - dst->path = push_str8_copy(arena, n->file.path); - dst->dir_idx = n->file.dir_idx; - dst->time_stamp = n->file.time_stamp; - dst->size = n->file.size; - } - } - // DWARF5 - else { - // directory table - { - // read table entry encoding count - U8 enc_count = 0; - TryRead(str8_deserial_read_struct(data, cursor, &enc_count), cursor, exit); - - // read table entry encodings - U64 *enc_arr = 0; - TryRead(str8_deserial_read_uleb128_array(scratch.arena, data, cursor, enc_count*2, &enc_arr), cursor, exit); - - // read table count - U64 table_count = 0; - TryRead(str8_deserial_read_uleb128(data, cursor, &table_count), cursor, exit); - - // validate encoding - if (table_count > 0) { - if (enc_count != 1) { goto exit; } - if (enc_arr[0] != DW_LNCT_Path) { goto exit; } - } - - // read table - dir_table.count = table_count; - dir_table.v = push_array(arena, String8, table_count); - for EachIndex(i, table_count) { - DW_FormKind form_kind = enc_arr[1]; - DW_Form form = {0}; - U64 form_size = 0; - if (!dw_read_form(str8_skip(data, cursor), version, format, address_size, form_kind, max_U64, &form, &form_size)) { goto exit; } - cursor += form_size; - dir_table.v[i] = dw_interp_string(input, format, cu_str_offsets, form); - } - } - - // file table - { - // read table entry encoding count - U8 enc_count = 0; - TryRead(str8_deserial_read_struct(data, cursor, &enc_count), cursor, exit); - - // read table entry encodings - U64 *enc_arr = 0; - TryRead(str8_deserial_read_uleb128_array(scratch.arena, data, cursor, enc_count*2, &enc_arr), cursor, exit); - - // read table count - U64 table_count = 0; - TryRead(str8_deserial_read_uleb128(data, cursor, &table_count), cursor, exit); - - file_table.count = table_count; - file_table.v = push_array(arena, DW_LineFile, table_count); - - for EachIndex(i, table_count) { - DW_LineFile *file = &file_table.v[i]; - for EachIndex(enc_idx, enc_count) { - DW_LNCT lnct = enc_arr[enc_idx*2 + 0]; - - DW_FormKind form_kind = enc_arr[enc_idx*2 + 1]; - DW_Form form = {0}; - U64 form_size = 0; - if (!dw_read_form(str8_skip(data, cursor), version, format, address_size, form_kind, max_U64, &form, &form_size)) { goto exit; } - cursor += form_size; - - switch (lnct) { - case DW_LNCT_Path: { file->path = dw_interp_string(input, format, cu_str_offsets, form); } break; - case DW_LNCT_DirectoryIndex: { file->dir_idx = dw_interp_const_u64(form); } break; - case DW_LNCT_TimeStamp: { file->time_stamp = dw_interp_const_u64(form); } break; - case DW_LNCT_Size: { file->size = dw_interp_const_u64(form); } break; - case DW_LNCT_MD5: { file->md5 = dw_interp_const_u128(form); } break; - case DW_LNCT_LLVM_Source: { file->source = dw_interp_string(input, format, cu_str_offsets, form); } break; - default: { - Assert(!"unexpected LNTC encoding"); - } break; - } - } - } - } - } - - if (header_out) { - header_out->unit_length = length_size + length; - header_out->version = version; - header_out->address_size = address_size; - header_out->segment_selector_size = segsel_size; - header_out->header_length = header_length; - header_out->min_inst_len = min_inst_len; - header_out->max_ops_for_inst = max_ops_for_inst; - header_out->default_is_stmt = default_is_stmt; - header_out->line_base = line_base; - header_out->line_range = line_range; - header_out->opcode_base = opcode_base; - header_out->num_opcode_lens = num_opcode_lens; - header_out->opcode_lens = opcode_lens.str; - header_out->line_program_off = line_program_off; - header_out->dir_table = dir_table; - header_out->file_table = file_table; - } - - exit:; - scratch_end(scratch); - return cursor; -} - -internal DW_LineVM * -dw_line_vm_init(DW_Raw *input, DW_CompUnit *cu) -{ - DW_LineVM *vm = 0; - - Arena *arena = arena_alloc(.reserve_size = KB(64), .commit_size = KB(1)); - - String8 cu_stmt_list = dw_line_ptr_from_tag_attrib_kind(input, cu, cu->tag, DW_AttribKind_StmtList); - String8 cu_dir = dw_string_from_tag_attrib_kind(input, cu, cu->tag, DW_AttribKind_CompDir); - String8 cu_name = dw_string_from_tag_attrib_kind(input, cu, cu->tag, DW_AttribKind_Name); - - // read the line table header - DW_LineVMHeader header = {0}; - if (cu_stmt_list.size) { - if ( ! dw_read_line_vm_header(arena, input, cu_stmt_list, cu_dir, cu_name, cu->address_size, cu->str_offsets_lu, &header)) { - goto exit; - } - } - - vm = push_array(arena, DW_LineVM, 1); - *vm = (DW_LineVM){ - .arena = arena, - .cursor = header.line_program_off, - .program = str8_prefix(cu_stmt_list, header.unit_length), - .header = header, - .state.end_sequence = 1, - }; - - exit:; - if (vm == 0) { arena_release(arena); } - return vm; -} - -internal void -dw_line_vm_release(DW_LineVM *vm) -{ - arena_release(vm->arena); -} - -internal void -dw_line_vm_advance(DW_LineVM *vm, U64 advance) -{ - U64 op_index = vm->state.op_index + advance; - vm->state.address += vm->header.min_inst_len * (op_index / vm->header.max_ops_for_inst); - vm->state.op_index = op_index % vm->header.max_ops_for_inst; - vm->advance = advance; -} - -internal B32 -dw_line_vm_step(DW_LineVM *vm) -{ - B32 is_ok = 0; - - if (vm->cursor >= vm->program.size) { goto exit; } - - vm->new_line = 0; - - // reset VM state - if (vm->state.end_sequence) { - vm->state.address = 0; - vm->state.op_index = 0; - vm->state.file_index = 1; - vm->state.line = 1; - vm->state.column = 0; - vm->state.is_stmt = vm->header.default_is_stmt; - vm->state.basic_block = 0; - vm->state.end_sequence = 0; - vm->state.prologue_end = 0; - vm->state.epilogue_begin = 0; - vm->state.isa = 0; - vm->state.discriminator = 0; - } - - // read opcode - TryRead(str8_deserial_read_struct(vm->program, vm->cursor, &vm->opcode), vm->cursor, exit); - - // special opcodes - if (vm->opcode >= vm->header.opcode_base) { - U32 adjusted_opcode = (U32)(vm->opcode - vm->header.opcode_base); - U32 op_advance = adjusted_opcode / vm->header.line_range; - S32 line_advance = (S64)vm->header.line_base + ((S64)adjusted_opcode) % (S64)vm->header.line_range; - U64 addr_advance = vm->header.min_inst_len * ((vm->state.op_index + op_advance) / vm->header.max_ops_for_inst); - - if (vm->header.line_range > 0 && vm->header.max_ops_for_inst > 0) { - adjusted_opcode = (U32)(vm->opcode - vm->header.opcode_base); - op_advance = adjusted_opcode / vm->header.line_range; - line_advance = (S32)vm->header.line_base + ((S32)adjusted_opcode) % (S32)vm->header.line_range; - addr_advance = vm->header.min_inst_len * ((vm->state.op_index+op_advance) / vm->header.max_ops_for_inst); - } - - vm->state.address += addr_advance; - vm->state.op_index = (vm->state.op_index + op_advance) % vm->header.max_ops_for_inst; - vm->state.line = (U64)((S64)vm->state.line + line_advance); - vm->state.basic_block = 0; - vm->state.prologue_end = 0; - vm->state.epilogue_begin = 0; - vm->state.discriminator = 0; - - vm->line_advance = line_advance; - vm->addr_advance = addr_advance; - vm->new_line = 1; - } else { - // standard opcodes - switch (vm->opcode) { - case DW_StdOpcode_Copy: { - vm->new_line = 1; - - vm->state.discriminator = 0; - vm->state.basic_block = 0; - vm->state.prologue_end = 0; - vm->state.epilogue_begin = 0; - } break; - - case DW_StdOpcode_AdvancePc: { - TryRead(str8_deserial_read_uleb128(vm->program, vm->cursor, &vm->operands[0].u64), vm->cursor, exit); - dw_line_vm_advance(vm, vm->operands[0].u64); - } break; - - case DW_StdOpcode_AdvanceLine: { - TryRead(str8_deserial_read_sleb128(vm->program, vm->cursor, &vm->operands[0].s64), vm->cursor, exit); - vm->state.line += vm->operands[0].s64; - } break; - - case DW_StdOpcode_SetFile: { - TryRead(str8_deserial_read_uleb128(vm->program, vm->cursor, &vm->operands[0].u64), vm->cursor, exit); - vm->state.file_index = vm->operands[0].u64; - } break; - - case DW_StdOpcode_SetColumn: { - TryRead(str8_deserial_read_uleb128(vm->program, vm->cursor, &vm->operands[0].u64), vm->cursor, exit); - vm->state.column = vm->operands[0].u64; - } break; - - case DW_StdOpcode_NegateStmt: { - vm->state.is_stmt = !vm->state.is_stmt; - } break; - - case DW_StdOpcode_SetBasicBlock: { - vm->state.basic_block = 1; - } break; - - case DW_StdOpcode_ConstAddPc: { - U64 advance = (0xffu - vm->header.opcode_base) / vm->header.line_range; - dw_line_vm_advance(vm, advance); - } break; - - case DW_StdOpcode_FixedAdvancePc: { - U16 fixed_advance = 0; - TryRead(str8_deserial_read_struct(vm->program, vm->cursor, &fixed_advance), vm->cursor, exit); - vm->operands[0].u64 = fixed_advance; - vm->state.address += vm->operands[0].u64; - vm->state.op_index = 0; - } 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: { - TryRead(str8_deserial_read_uleb128(vm->program, vm->cursor, &vm->operands[0].u64), vm->cursor, exit); - vm->state.isa = vm->operands[0].u64; - } break; - - // extended opcodes - case DW_StdOpcode_ExtendedOpcode: { - TryRead(str8_deserial_read_uleb128(vm->program, vm->cursor, &vm->ext_length), vm->cursor, exit); - String8 ext_data = str8_substr(vm->program, r1u64(vm->cursor, vm->cursor + vm->ext_length)); - vm->cursor += vm->ext_length; - - U64 ext_cursor = 0; - TryRead(str8_deserial_read_struct(ext_data, ext_cursor, &vm->ext_opcode), ext_cursor, exit); - - switch (vm->ext_opcode) { - case DW_ExtOpcode_EndSequence: { - vm->new_seq = 1; - vm->new_line = 1; - vm->state.end_sequence = 1; - } break; - - case DW_ExtOpcode_SetAddress: { - TryRead(str8_deserial_read(ext_data, ext_cursor, &vm->operands[0].u64, vm->header.address_size, vm->header.address_size), ext_cursor, exit); - vm->state.address = vm->operands[0].u64; - vm->state.op_index = 0; - } break; - - case DW_ExtOpcode_DefineFile: { - TryRead(str8_deserial_read_cstr (ext_data, ext_cursor, &vm->operands[0].string), ext_cursor, exit); // file name - TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[1].u64), ext_cursor, exit); // dir index - TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[2].u64), ext_cursor, exit); // modify time - TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[3].u64), ext_cursor, exit); // file size - - if (vm->ext_file_ht == 0) { - vm->ext_file_ht = hash_table_init(vm->arena, 512); - } - - DW_LineFile *file = push_array(vm->arena, DW_LineFile, 1); - file->path = vm->operands[0].string; - file->dir_idx = vm->operands[1].u64; - file->time_stamp = vm->operands[2].u64; - file->size = vm->operands[3].u64; - - if (hash_table_search_u64_raw(vm->ext_file_ht, vm->state.file_index) == 0) { - vm->error = push_str8f(vm->arena, "file with index %I64d was already defined", vm->state.file_index); - goto exit; - } - - hash_table_push_u64_raw(vm->arena, vm->ext_file_ht, vm->state.file_index, file); - } break; - - case DW_ExtOpcode_SetDiscriminator: { - TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[0].u64), ext_cursor, exit); - vm->state.discriminator = vm->operands[0].u64; - } break; - - default: { NotImplemented; } break; - } - } break; - - default: { - // skip unknown opcode - if (0 == vm->opcode || vm->opcode > vm->header.num_opcode_lens) { goto exit; } - for EachIndex(i, vm->header.opcode_lens[vm->opcode - 1]) { - U64 v = 0; - TryRead(str8_deserial_read_uleb128(vm->program, vm->cursor, &v), vm->cursor, exit); - } - } break; - } - } - - is_ok = 1; - exit:; - return is_ok; -} - -internal DW_LineFile * -dw_line_vm_find_file(DW_LineVM *vm, U64 file_idx) -{ - DW_LineFile *file = 0; - if (file == 0 && file_idx < vm->header.file_table.count) { - file = &vm->header.file_table.v[file_idx]; - } else if (vm->ext_file_ht) { - file = hash_table_search_u64_raw(vm->ext_file_ht, file_idx); - } - return file; -} - -internal String8 -dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file) -{ - Temp scratch = scratch_begin(&arena, 1); - - // directory table must contain at least compile unit directory - Assert(dir_table.count > 0); - - // find directory and file name associated with the file index - String8 dir = dir_table.v[file->dir_idx]; - String8 path = file->path; - - // infer path style if directory is empty use file name - PathStyle style = path_style_from_str8(dir); - if (style == PathStyle_Null || style == PathStyle_Relative) { - style = path_style_from_str8(file->path); - } - - String8List path_list = {0}; - { - // directories that start with ".." are relative to the compile unit directory - if (str8_match_lit("..", dir, StringMatchFlag_RightSideSloppy)) { - String8List comp_dir = str8_split_path(scratch.arena, dir_table.v[0]); - str8_list_concat_in_place(&path_list, &comp_dir); - } - - // push directory - String8List dir_list = str8_split_path(scratch.arena, dir); - str8_list_concat_in_place(&path_list, &dir_list); - - // push file name - str8_list_push(scratch.arena, &path_list, file->path); - - // resolve dots in the path - str8_path_list_resolve_dots_in_place(&path_list, style); - } - - // join path - String8 result = str8_path_list_join_by_style(arena, &path_list, style); - - scratch_end(scratch); - return result; -} - -internal DW_PubStringsTable -dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Raw *input, DW_SectionKind section_kind) -{ - Temp scratch = scratch_begin(&arena, 1); - - DW_PubStringsTable names_table = {0}; - names_table.size = 16384; - names_table.buckets = push_array(arena, DW_PubStringsBucket*, names_table.size); - - String8 section_data = input->sec[section_kind].data; - for(U64 cursor = 0; cursor < section_data.size; ) { - U32 first_four_bytes = 0; - if (str8_deserial_read_struct(input->sec[DW_Section_Info].data, 0, &first_four_bytes) != sizeof(first_four_bytes)) { break; } - DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit; - - U64 unit_length = 0; - U64 unit_length_size = str8_deserial_read_dwarf_packed_size(section_data, cursor, &unit_length); - if (unit_length_size == 0) { - break; - } - cursor += unit_length_size; - - U64 cursor_opl = Min(cursor + unit_length, section_data.size); - if (cursor >= cursor_opl) { - break; - } - - DW_Version unit_version = 0; - cursor += str8_deserial_read_struct(section_data, cursor, &unit_version); - if (cursor >= cursor_opl) { - break; - } - - U64 debug_info_off = 0; - cursor += str8_deserial_read_dwarf_uint(section_data, cursor, format, &debug_info_off); - if (cursor >= cursor_opl) { - break; - } - - U64 debug_info_length = 0; - cursor += str8_deserial_read_dwarf_packed_size(section_data, cursor, &debug_info_length); - if (cursor >= cursor_opl) { - break; - } - - U64 off_size = dw_size_from_format(format); - for (; (cursor + off_size) <= cursor_opl;) { - U64 info_off = 0; - U64 info_off_size = str8_deserial_read_dwarf_uint(section_data, cursor, format, &info_off); - cursor += info_off_size; - - if (info_off_size == 0 || info_off == 0) { - break; - } - - String8 string = {0}; - cursor += str8_deserial_read_cstr(section_data, cursor, &string); - - U64 hash = dw_hash_from_string(string); - U64 bucket_idx = hash % names_table.size; - - DW_PubStringsBucket *bucket = push_array(arena, DW_PubStringsBucket, 1); - bucket->next = names_table.buckets[bucket_idx]; - bucket->string = string; - bucket->info_off = info_off; - bucket->cu_info_off = debug_info_off; - names_table.buckets[bucket_idx] = bucket; - } - } - - scratch_end(scratch); - return names_table; -} - -internal DW_Expr -dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data) -{ - DW_Expr expr = {0}; - for (U64 cursor = 0, inst_start = 0; cursor < data.size; inst_start = cursor) { - // read opcode - DW_ExprOp opcode = 0; - U64 opcode_size = str8_deserial_read_struct(data, cursor, &opcode); - if (opcode_size == 0) { break; } - cursor += opcode_size; - - // read operands - U64 operand_count = dw_operand_count_from_expr_op(opcode); - DW_ExprOperandType *operand_types = dw_operand_types_from_expr_opcode(opcode); - DW_ExprOperand operands[2] = {0}; - for EachIndex(operand_idx, operand_count) { - U64 operand_size = 0; - switch (operand_types[operand_idx]) { - case DW_ExprOperandType_Null: { } break; - case DW_ExprOperandType_U8: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].u8); } break; - case DW_ExprOperandType_U16: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].u16); } break; - case DW_ExprOperandType_U32: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].u32); } break; - case DW_ExprOperandType_U64: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].u64); } break; - case DW_ExprOperandType_S8: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].s8); } break; - case DW_ExprOperandType_S16: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].s16); } break; - case DW_ExprOperandType_S32: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].s32); } break; - case DW_ExprOperandType_S64: { operand_size = str8_deserial_read_struct(data, cursor, &operands[operand_idx].s64); } break; - case DW_ExprOperandType_ULEB128: { operand_size = str8_deserial_read_uleb128(data, cursor, &operands[operand_idx].u64); } break; - case DW_ExprOperandType_SLEB128: { operand_size = str8_deserial_read_sleb128(data, cursor, &operands[operand_idx].s64); } break; - case DW_ExprOperandType_Addr: { operand_size = str8_deserial_read(data, cursor, &operands[operand_idx].u64, addr_size, addr_size); } break; - case DW_ExprOperandType_DwarfUInt: { operand_size = str8_deserial_read_dwarf_uint(data, cursor, format, &operands[operand_idx].u64); } break; - case DW_ExprOperandType_Block: { - U8 block_size; - U64 block_size_size = str8_deserial_read_struct(data, cursor, &block_size); - U64 block_read_size = str8_deserial_read_block(data, cursor + block_size_size, block_size, &operands[operand_idx].block); - if(block_read_size == block_size_size) { - operand_size = block_size_size + block_read_size; - } - } break; - default: { InvalidPath; } break; - } - if (operand_size == 0) { goto exit; } - cursor += operand_size; - } - - // fill out instruction - DW_ExprInst *inst = push_array(arena, DW_ExprInst, 1); - inst->opcode = opcode; - inst->size = cursor - inst_start; - inst->operands = operand_count ? push_array(arena, DW_ExprOperand, operand_count) : 0; - MemoryCopy(inst->operands, operands, operand_count * sizeof(DW_ExprOperand)); - - // push instruction - DLLPushBack(expr.first, expr.last, inst); - expr.count += 1; - } - exit:; - return expr; -} - -internal void -dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n) -{ - SLLQueuePush(list->first, list->last, n); - list->count += 1; -} - -internal DW_CFA_InstNode * -dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v) -{ - DW_CFA_InstNode *n = push_array(arena, DW_CFA_InstNode, 1); - n->v = v; - dw_cfa_inst_list_push_node(list, n); - return n; -} - -internal U64 -dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out) -{ - U64 read_size = 0; - if (cie->segment_selector_size) { - NotImplemented; - } else { - read_size = str8_deserial_read(data, 0, ptr_out, cie->address_size, cie->address_size); - } - return read_size; -} - -internal U64 -dw_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); + // rjf: read tag abbrev U64 id = 0; - U64 id_size = str8_deserial_read_dwarf_uint(entry_data, length_size, format, &id); - if (id_size == 0) { goto exit; } - - U64 id_type = format == DW_Format_32Bit ? max_U32 : max_U64; - desc_out->format = format; - 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; - - exit:; - return length + length_size; -} - -internal B32 -dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out) -{ - B32 is_parsed = 0; - U64 cursor = format == DW_Format_32Bit ? 4 : 12; - - U64 cie_id = 0; - TryRead(str8_deserial_read_dwarf_uint(data, cursor, format, &cie_id), cursor, exit); - - U8 version = 0; - TryRead(str8_deserial_read_struct(data, cursor, &version), cursor, exit); - - String8 aug_string = {0}; - TryRead(str8_deserial_read_cstr(data, cursor, &aug_string), cursor, exit); - - U8 address_size = 0; - U8 segment_selector_size = 0; - if (version >= DW_Version_4) { - TryRead(str8_deserial_read_struct(data, cursor, &address_size), cursor, exit); - TryRead(str8_deserial_read_struct(data, cursor, &segment_selector_size), cursor, exit); - } else { - address_size = byte_size_from_arch(arch); + U64 tag_kind = 0; + U8 has_children = 0; + { + off += str8_deserial_read_uleb128(data, off, &id); + if(id != 0) + { + off += str8_deserial_read_uleb128(data, off, &tag_kind); + off += str8_deserial_read_struct(data, off, &has_children); + } } - U64 code_align_factor = 0; - TryRead(str8_deserial_read_uleb128(data, cursor, &code_align_factor), cursor, exit); - - S64 data_align_factor = 0; - TryRead(str8_deserial_read_sleb128(data, cursor, &data_align_factor), cursor, exit); - - U64 ret_addr_reg = 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); } - - if (aug_string.size > 0) { goto exit; } - - cie_out->insts = str8_skip(data, cursor); - cie_out->aug_string = aug_string; - 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 = address_size; - cie_out->segment_selector_size = segment_selector_size; - - is_parsed = 1; - exit:; - return is_parsed; -} - -internal B32 -dw_parse_fde(String8 data, DW_Format format, DW_CIE *cie, DW_FDE *fde_out) -{ - B32 is_parsed = 0; - U64 cursor = format == DW_Format_32Bit ? 4 : 12; - - // extract CIE pointer - U64 cie_pointer = 0; - TryRead(str8_deserial_read_dwarf_uint(data, cursor, format, &cie_pointer), cursor, exit); - - // extract address of first instruction - U64 pc_begin = 0; - TryRead(dw_read_debug_frame_ptr(str8_skip(data, cursor), cie, &pc_begin), cursor, exit); - - // extract instruction range size - U64 pc_range = 0; - TryRead(dw_read_debug_frame_ptr(str8_skip(data, cursor), cie, &pc_range), cursor, exit); - - // parse augmentation data - String8 aug_data = str8_substr(data, rng_1u64(cursor, cursor + cie->aug_data.size)); - cursor += cie->aug_data.size; - - // commit values to out - fde_out->format = format; - fde_out->cie_pointer = cie_pointer; - fde_out->pc_range = rng_1u64(pc_begin, pc_begin + pc_range); - fde_out->insts = str8_skip(data, cursor); - - is_parsed = 1; - exit:; - return is_parsed; -} - -internal B32 -dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out) -{ - B32 is_parsed = 0; - DW_DescriptorEntry fde_desc = {0}; - dw_parse_descriptor_entry_header(data, fde_offset, &fde_desc); - 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_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; - } - } + // rjf: read all tag attribute abbreviations + DW2_AbbrevAttribList attribs = {0}; + if(id != 0) + { + for(;;) + { + U64 attrib_start_off = off; + U64 attrib_kind = 0; + U64 attrib_form_kind = 0; + U64 implicit_const = 0; + off += str8_deserial_read_uleb128(data, off, &attrib_kind); + off += str8_deserial_read_uleb128(data, off, &attrib_form_kind); + if(attrib_form_kind == DW_FormKind_ImplicitConst) + { + off += str8_deserial_read_uleb128(data, off, &implicit_const); + } + if(attrib_kind != 0 && attribs_out != 0) + { + DW2_AbbrevAttribNode *n = push_array(arena, DW2_AbbrevAttribNode, 1); + SLLQueuePush(attribs.first, attribs.last, n); + attribs.count += 1; + n->v.attrib_kind = attrib_kind; + n->v.form_kind = attrib_form_kind; + n->v.implicit_const = implicit_const; + } + if(off == attrib_start_off || attrib_kind == 0) + { + break; } } } - return is_parsed; -} - -internal DW_CFA_ParseErrorCode -dw_parse_cfa_inst(String8 data, - U64 code_align_factor, - S64 data_align_factor, - DW_DecodePtr *decode_ptr_func, - void *decode_ptr_ud, - U64 *bytes_read_out, - DW_CFA_Inst *inst_out) -{ - *bytes_read_out = 0; - - DW_CFA_ParseErrorCode error_code = DW_CFA_ParseErrorCode_End; - U64 cursor = 0; - - // read opcode - DW_CFA_Opcode raw_opcode = 0; - TryRead(str8_deserial_read_struct(data, cursor, &raw_opcode), cursor, exit); - - // decode opcode implicit operand - U64 opcode = raw_opcode & ~DW_CFA_Mask_OpcodeHi; - U64 implicit_operand = 0; - if ((raw_opcode & DW_CFA_Mask_OpcodeHi) != 0) { - opcode = raw_opcode & DW_CFA_Mask_OpcodeHi; - implicit_operand = raw_opcode & DW_CFA_Mask_Operand; + // rjf: fill + if(header_out != 0) + { + header_out->id = id; + header_out->tag_kind = tag_kind; + header_out->has_children = has_children; + } + if(attribs_out != 0) + { + MemoryCopyStruct(attribs_out, &attribs); } - // decode operands - DW_CFA_Operand operands[DW_CFA_OperandMax] = {0}; - switch (opcode) { - case DW_CFA_SetLoc: { - U64 address_size = decode_ptr_func(str8_skip(data, cursor), decode_ptr_ud, &operands[0].u64); - if (address_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += address_size; - } break; - case DW_CFA_AdvanceLoc: { - operands[0].u64 = implicit_operand * code_align_factor; - } break; - case DW_CFA_AdvanceLoc1: { - U8 delta = 0; - U64 delta_size = str8_deserial_read_struct(data, cursor, &delta); - if (delta_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += delta_size; - operands[0].u64 = delta * code_align_factor; - } break; - case DW_CFA_AdvanceLoc2: { - U16 delta = 0; - U64 delta_size = str8_deserial_read_struct(data, cursor, &delta); - if (delta_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += delta_size; - operands[0].u64 = delta * code_align_factor; - } break; - case DW_CFA_AdvanceLoc4: { - U32 delta = 0; - U64 delta_size = str8_deserial_read_struct(data, cursor, &delta); - if (delta_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += delta_size; - operands[0].u64 = delta * code_align_factor; - } break; - case DW_CFA_DefCfa: { - U64 reg = 0; - U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); - if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += reg_size; - - U64 offset = 0; - U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); - if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += offset_size; - - operands[0].u64 = reg; - operands[1].u64 = offset; - } break; - case DW_CFA_DefCfaSf: { - U64 reg = 0; - U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); - if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += reg_size; - - S64 offset = 0; - U64 offset_size = str8_deserial_read_sleb128(data, cursor, &offset); - if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += offset_size; - - operands[0].u64 = reg; - operands[1].s64 = offset * data_align_factor; - } break; - case DW_CFA_DefCfaRegister: { - U64 reg = 0; - U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); - if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += reg_size; - - operands[0].u64 = reg; - } break; - case DW_CFA_DefCfaOffset: { - U64 offset = 0; - U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); - if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += offset_size; - - operands[0].u64 = offset; - } break; - case DW_CFA_DefCfaOffsetSf: { - U64 offset = 0; - U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); - if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += offset_size; - - operands[0].u64 = offset * data_align_factor; - } break; - case DW_CFA_DefCfaExpr: { - U64 expr_size = 0; - U64 expr_size_size = str8_deserial_read_uleb128(data, cursor, &expr_size); - if (expr_size_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += expr_size_size; - - if (cursor + expr_size > data.size) { goto exit; } - String8 expr = str8_prefix(str8_skip(data, cursor), expr_size); - - operands[0].block = expr; - cursor += expr_size; - } break; - case DW_CFA_Undefined: { - U64 reg = 0; - U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); - if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += reg_size; - - operands[0].u64 = reg; - } break; - case DW_CFA_SameValue: { - U64 reg = 0; - U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); - if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += reg_size; - - operands[0].u64 = reg; - } break; - case DW_CFA_Offset: { - U64 offset = 0; - U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); - if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += offset_size; - - operands[0].u64 = implicit_operand; - operands[1].s64 = (S64)offset * data_align_factor; - } break; - case DW_CFA_OffsetExt: { - U64 reg = 0; - U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); - if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += reg_size; - - U64 offset = 0; - U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); - if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += offset_size; - - operands[0].u64 = reg; - operands[1].u64 = offset * data_align_factor; - } break; - case DW_CFA_OffsetExtSf: { - U64 reg = 0; - U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); - if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += reg_size; - - S64 offset = 0; - U64 offset_size = str8_deserial_read_sleb128(data, cursor, &offset); - if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += offset_size; - - operands[0].u64 = reg; - operands[1].s64 = offset * data_align_factor; - } break; - case DW_CFA_ValOffset: { - U64 val = 0; - U64 val_size = str8_deserial_read_uleb128(data, cursor, &val); - if (val_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += val_size; - - U64 offset = 0; - U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset); - if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += offset_size; - - operands[0].u64 = val; - operands[1].u64 = offset * data_align_factor; - } break; - case DW_CFA_ValOffsetSf: { - U64 val = 0; - U64 val_size = str8_deserial_read_uleb128(data, cursor, &val); - if (val_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += val_size; - - S64 offset = 0; - U64 offset_size = str8_deserial_read_sleb128(data, cursor, &offset); - if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += offset_size; - - operands[0].u64 = val; - operands[1].s64 = offset; - } break; - case DW_CFA_Register: { - U64 dst_reg = 0; - U64 dst_reg_size = str8_deserial_read_uleb128(data, cursor, &dst_reg); - if (dst_reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += dst_reg_size; - - U64 src_reg = 0; - U64 src_reg_size = str8_deserial_read_uleb128(data, cursor, &src_reg); - if (src_reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += src_reg_size; - - operands[0].u64 = dst_reg; - operands[1].u64 = src_reg; - } break; - case DW_CFA_Expr: { - U64 reg = 0; - U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®); - if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += reg_size; - - U64 expr_size = 0; - U64 expr_size_size = str8_deserial_read_uleb128(data, cursor, &expr_size); - if (expr_size_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += expr_size_size; - - if (cursor + expr_size > data.size) { goto exit; } - String8 expr = str8_prefix(str8_skip(data, cursor), expr_size); - cursor += expr_size; - - operands[0].u64 = reg; - operands[1].block = expr; - } break; - case DW_CFA_ValExpr: { - U64 val = 0; - U64 val_size = str8_deserial_read_uleb128(data, cursor, &val); - if (val_size == 0) { goto exit; } - cursor += val_size; - - U64 expr_size = 0; - U64 expr_size_size = str8_deserial_read_uleb128(data, cursor, &expr_size); - if (expr_size_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; } - cursor += expr_size_size; - - if (cursor + expr_size > data.size) { goto exit; } - String8 expr = str8_prefix(str8_skip(data, cursor), expr_size); - cursor += expr_size; - - operands[0].u64 = val; - operands[1].block = expr; - } break; - case DW_CFA_Restore: { - operands[0].u64 = implicit_operand; - } break; - case DW_CFA_RestoreExt: {} break; - case DW_CFA_RememberState: {} break; - case DW_CFA_RestoreState: {} break; - case DW_CFA_Nop: {} break; - default: { goto exit; } break; - } - - // fill out output - inst_out->opcode = opcode; - MemoryCopyTyped(&inst_out->operands[0], &operands[0], DW_CFA_OperandMax); - - *bytes_read_out = cursor; - - error_code = DW_CFA_ParseErrorCode_NewInst; - - exit:; - return error_code; + U64 bytes_read = (off-start_off); + return bytes_read; } -internal DW_CFA_InstList -dw_parse_cfa_inst_list(Arena *arena, - String8 data, - U64 code_align_factor, - S64 data_align_factor, - DW_DecodePtr *decode_ptr_func, - void *decode_ptr_ud) +internal DW2_AbbrevMap +dw2_abbrev_map_from_data(Arena *arena, String8 data, U64 off) { - U64 pos = arena_pos(arena); - DW_CFA_InstList list = {0}; - for (U64 cursor = 0, inst_size; cursor < data.size; cursor += inst_size) { - DW_CFA_Inst inst = {0}; - DW_CFA_ParseErrorCode error_code = dw_parse_cfa_inst(str8_skip(data, cursor), code_align_factor, data_align_factor, decode_ptr_func, decode_ptr_ud, &inst_size, &inst); - if (error_code == DW_CFA_ParseErrorCode_End) { break; } - if (error_code != DW_CFA_ParseErrorCode_NewInst) { - MemoryZeroStruct(&list); - arena_pop_to(arena, pos); + DW2_AbbrevMap map = {0}; + + // rjf: loop - first to determine the number of tag formats encoded + // by this abbrev table, second to actually build a hash table for + // mapping (id -> .debug_abbrev offset) + for(B32 build = 0; build <= 1; build += 1) + { + // rjf: parse whole abbrev table + U64 tag_count = 0; + for(U64 read_off = off;;) + { + U64 start_off = read_off; + + // rjf: read next abbrev + DW2_AbbrevHeader header = {0}; + read_off += dw2_read_abbrev(arena, data, read_off, &header, 0); + + // rjf: count tag + if(header.id != 0) + { + tag_count += 1; + } + + // rjf: if building (second loop) -> insert into map + if(build) + { + U64 hash = u64_hash_from_str8(str8_struct(&header.id)); + U64 slot_idx = hash%map.slots_count; + DW2_AbbrevMapNode *n = push_array(arena, DW2_AbbrevMapNode, 1); + SLLStackPush(map.slots[slot_idx], n); + n->id = header.id; + n->off = start_off; + } + + // rjf: no tag ID, or no movement? -> exit + if(read_off == start_off || header.id == 0) + { + break; + } + } + + // rjf: on first loop iteration, given the tag format count, construct the table + if(!build) + { + map.slots_count = Max(1, tag_count + tag_count/4); + map.slots = push_array(arena, DW2_AbbrevMapNode *, map.slots_count); + } + } + + return map; +} + +internal DW2_UnitAbbrevMapMap +dw2_unit_abbrev_map_map_from_data(Arena *arena, String8 data, DW2_UnitHeader *unit_headers, U64 unit_headers_count) +{ + DW2_UnitAbbrevMapMap result = {0}; + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: gather deduplicated .debug_abbrev offsets, representing beginnings + // of abbreviation tables. we want to do this because many units may refer + // to the same abbreviation table. + // + typedef struct AbbrevOffNode AbbrevOffNode; + struct AbbrevOffNode + { + AbbrevOffNode *order_next; + AbbrevOffNode *hash_next; + U64 off; + U64 idx; + }; + U64 abbrev_off_slots_count = unit_headers_count; + AbbrevOffNode **abbrev_off_slots = 0; + U64 abbrev_map_count = 0; + U64 *abbrev_map_off_from_idx_table = 0; + DW2_AbbrevMap *abbrev_map_from_idx_table = 0; + DW2_AbbrevMap **abbrev_map_from_unit_idx_table = 0; + ProfScope("gather deduplicated .debug_abbrev offsets") if(lane_idx() == 0) + { + AbbrevOffNode *abbrev_off_first = 0; + AbbrevOffNode *abbrev_off_last = 0; + abbrev_off_slots = push_array(scratch.arena, AbbrevOffNode *, abbrev_off_slots_count); + for EachIndex(unit_idx, unit_headers_count) + { + U64 abbrev_off = unit_headers[unit_idx].abbrev_off; + U64 hash = u64_hash_from_str8(str8_struct(&abbrev_off)); + U64 slot_idx = hash%abbrev_off_slots_count; + AbbrevOffNode *node = 0; + for(AbbrevOffNode *n = abbrev_off_slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->off == abbrev_off) + { + node = n; + break; + } + } + if(node == 0) + { + node = push_array(arena, AbbrevOffNode, 1); + SLLStackPush_N(abbrev_off_slots[slot_idx], node, hash_next); + SLLQueuePush_N(abbrev_off_first, abbrev_off_last, node, order_next); + node->off = abbrev_off; + node->idx = abbrev_map_count; + abbrev_map_count += 1; + } + } + abbrev_map_off_from_idx_table = push_array(scratch.arena, U64, abbrev_map_count); + abbrev_map_from_idx_table = push_array(arena, DW2_AbbrevMap, abbrev_map_count); + abbrev_map_from_unit_idx_table = push_array(arena, DW2_AbbrevMap *, unit_headers_count); + { + U64 abbrev_map_idx = 0; + for(AbbrevOffNode *n = abbrev_off_first; n != 0; n = n->order_next) + { + abbrev_map_off_from_idx_table[abbrev_map_idx] = n->off; + abbrev_map_idx += 1; + } + } + } + lane_sync_u64(&abbrev_off_slots, 0); + lane_sync_u64(&abbrev_map_count, 0); + lane_sync_u64(&abbrev_map_off_from_idx_table, 0); + lane_sync_u64(&abbrev_map_from_idx_table, 0); + lane_sync_u64(&abbrev_map_from_unit_idx_table, 0); + + //- rjf: build all unique abbreviation maps + ProfScope("build all unique abbreviation maps") + { + U64 abbrev_map_take_idx = 0; + U64 *abbrev_map_take_idx_ptr = &abbrev_map_take_idx; + lane_sync_u64(&abbrev_map_take_idx_ptr, 0); + for(;;) + { + U64 abbrev_map_idx = ins_atomic_u64_inc_eval(abbrev_map_take_idx_ptr) - 1; + if(abbrev_map_idx >= abbrev_map_count) + { + break; + } + abbrev_map_from_idx_table[abbrev_map_idx] = dw2_abbrev_map_from_data(arena, data, abbrev_map_off_from_idx_table[abbrev_map_idx]); + } + lane_sync(); + } + + //- rjf: build unit -> abbrev map table + ProfScope("build unit -> abbrev map table") + { + Rng1U64 range = lane_range(unit_headers_count); + for EachInRange(unit_idx, range) + { + U64 abbrev_off = unit_headers[unit_idx].abbrev_off; + U64 hash = u64_hash_from_str8(str8_struct(&abbrev_off)); + U64 slot_idx = hash%abbrev_off_slots_count; + U64 abbrev_map_idx = 0; + for(AbbrevOffNode *n = abbrev_off_slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->off == abbrev_off) + { + abbrev_map_idx = n->idx; + break; + } + } + abbrev_map_from_unit_idx_table[unit_idx] = &abbrev_map_from_idx_table[abbrev_map_idx]; + } + lane_sync(); + } + + //- rjf: fill result + result.map_count = abbrev_map_count; + result.map_from_idx_table = abbrev_map_from_idx_table; + result.map_from_unit_idx_table = abbrev_map_from_unit_idx_table; + + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Form Value Parsing + +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) +{ + U64 start_off = off; + DW2_FormVal val = {form_kind}; + { + //- rjf: read value bytes + U64 bytes_to_read = 0; + switch(form_kind) + { + //- rjf: no-ops + default: + case DW_FormKind_Indirect: + case DW_FormKind_Null: + {}break; + + //- rjf: 1-byte uint reads + case DW_FormKind_Ref1: + case DW_FormKind_Data1: + case DW_FormKind_Flag: + case DW_FormKind_Strx1: + case DW_FormKind_Addrx1: + bytes_to_read = 1; goto read_fixed_uint; + + //- rjf: 2-byte uint reads + case DW_FormKind_Ref2: + case DW_FormKind_Data2: + case DW_FormKind_Strx2: + case DW_FormKind_Addrx2: + bytes_to_read = 2; goto read_fixed_uint; + + //- rjf: 3-byte uint reads + case DW_FormKind_Strx3: + case DW_FormKind_Addrx3: + bytes_to_read = 3; goto read_fixed_uint; + + //- rjf: 4-byte uint reads + case DW_FormKind_Data4: + case DW_FormKind_Ref4: + case DW_FormKind_RefSup4: + case DW_FormKind_Strx4: + case DW_FormKind_Addrx4: + bytes_to_read = 4; goto read_fixed_uint; + + //- rjf: 8-byte uint reads + case DW_FormKind_Data8: + case DW_FormKind_Ref8: + case DW_FormKind_RefSig8: + case DW_FormKind_RefSup8: + bytes_to_read = 8; goto read_fixed_uint; + + //- rjf: 16-byte uint reads + case DW_FormKind_Data16: + bytes_to_read = 16; goto read_fixed_uint; + + //- rjf: address-sized reads + case DW_FormKind_Addr: + bytes_to_read = ctx->addr_size; goto read_fixed_uint; + + //- rjf: format-defined-size reads + case DW_FormKind_RefAddr: + case DW_FormKind_SecOffset: + case DW_FormKind_LineStrp: + case DW_FormKind_Strp: + case DW_FormKind_StrpSup: + bytes_to_read = dw_addr_size_from_format(ctx->format); goto read_fixed_uint; + + //- rjf: fixed-size uint reads + read_fixed_uint: + { + off += str8_deserial_read(data, off, &val.u128.u64[0], bytes_to_read, bytes_to_read); + }break; + + //- rjf: uleb128 reads + case DW_FormKind_UData: + case DW_FormKind_RefUData: + case DW_FormKind_Strx: + case DW_FormKind_Addrx: + case DW_FormKind_LocListx: + case DW_FormKind_RngListx: + { + off += str8_deserial_read_uleb128(data, off, &val.u128.u64[0]); + }break; + + //- rjf: sleb128 reads + case DW_FormKind_SData: + { + off += str8_deserial_read_sleb128(data, off, (S64 *)(&val.u128.u64[0])); + }break; + + //- rjf: fixed-size uint reads / skips + case DW_FormKind_Block1: bytes_to_read = 1; goto read_fixed_uint_and_skip; + case DW_FormKind_Block2: bytes_to_read = 2; goto read_fixed_uint_and_skip; + case DW_FormKind_Block4: bytes_to_read = 4; goto read_fixed_uint_and_skip; + read_fixed_uint_and_skip: + { + U64 size = 0; + U64 og_read_off = off; + off += str8_deserial_read(data, off, &size, bytes_to_read, bytes_to_read); + val.u128.u64[0] = size; + val.u128.u64[1] = og_read_off; + off += size; + }break; + + //- rjf: uleb128 read & skip + case DW_FormKind_Block: + { + U64 size = 0; + U64 og_read_off = off; + off += str8_deserial_read_uleb128(data, off, &size); + val.string = str8_substr(data, r1u64(off, off+size)); + off += size; + }break; + + //- rjf: strings + case DW_FormKind_String: + { + String8 string = {0}; + U64 og_read_off = off; + off += str8_deserial_read_cstr(data, off, &string); + val.string = string; + }break; + + //- rjf: implicit constants (no reading in .debug_info; value comes from .debug_abbrev) + case DW_FormKind_ImplicitConst: + { + val.u128.u64[0] = implicit_const; + }break; + + //- rjf: exprloc + case DW_FormKind_ExprLoc: + { + U64 size = 0; + U64 og_read_off = off; + U64 bytes_read = str8_deserial_read_uleb128(data, off, &size); + val.u128.u64[0] = og_read_off + bytes_read; + val.u128.u64[1] = size; + val.string = str8_substr(data, r1u64(og_read_off, og_read_off+size)); + off += size + bytes_read; + }break; + + //- rjf: flag present + case DW_FormKind_FlagPresent: + { + val.u128.u64[0] = 1; + }break; + } + + //- rjf: in some cases, resolve numeric values -> strings + { + switch(form_kind) + { + default:{}break; + case DW_FormKind_Strx1: + case DW_FormKind_Strx2: + case DW_FormKind_Strx3: + case DW_FormKind_Strx4: + case DW_FormKind_Strx: + if(ctx->str_offsets_table != 0) + { + U64 entry_idx = val.u128.u64[0]; + U64 string_data_off = 0; + if(dw2_try_offset_from_table_idx(ctx->str_offsets_table, entry_idx, &string_data_off)) + { + String8 string_section_data = raw->sec[DW_SectionKind_Str].data; + val.string = str8_cstring_capped(string_section_data.str + string_data_off, + string_section_data.str + string_section_data.size); + } + }break; + case DW_FormKind_LineStrp: + { + String8 string_section_data = raw->sec[DW_SectionKind_LineStr].data; + val.string = str8_cstring_capped(string_section_data.str + val.u128.u64[0], + string_section_data.str + string_section_data.size); + }break; + case DW_FormKind_Strp: + case DW_FormKind_StrpSup: + { + String8 string_section_data = raw->sec[DW_SectionKind_Str].data; + val.string = str8_cstring_capped(string_section_data.str + val.u128.u64[0], + string_section_data.str + string_section_data.size); + }break; + } + } + + //- rjf: in some cases, resolve base numeric values -> addresses + { + switch(form_kind) + { + default:{val.addr = val.u128.u64[0];}break; + case DW_FormKind_Addrx: + case DW_FormKind_Addrx1: + case DW_FormKind_Addrx2: + case DW_FormKind_Addrx3: + case DW_FormKind_Addrx4: + if(ctx->addr_table != 0) + { + U64 addr_idx = val.u128.u64[0]; + dw2_try_offset_from_table_idx(ctx->addr_table, addr_idx, &val.addr); + }break; + } + } + } + *out = val; + U64 bytes_read = (off - start_off); + return bytes_read; +} + +//////////////////////////////// +//~ rjf: Parse Context Construction + +internal void +dw2_parse_ctx_equip_unit_header(DW2_ParseCtx *ctx_out, DW2_UnitHeader *hdr, U64 unit_base_info_off) +{ + ctx_out->version = hdr->version; + ctx_out->format = hdr->format; + ctx_out->addr_size = hdr->addr_size; + ctx_out->unit_base_info_off = unit_base_info_off; +} + +internal void +dw2_parse_ctx_equip_unit_abbrev_map(DW2_ParseCtx *ctx_out, DW2_UnitAbbrevMapMap *map, U64 unit_idx) +{ + ctx_out->abbrev_map = map->map_from_unit_idx_table[unit_idx]; +} + +internal void +dw2_parse_ctx_equip_unit_root_tag(DW2_ParseCtx *ctx_out, DW2_Tag *tag, DW2_OffsetTableSet *offset_tables) +{ + // rjf: unpack attributes + DW2_Attrib *low_pc_attrib = &dw2_attrib_nil; + DW2_Attrib *lang_attrib = &dw2_attrib_nil; + DW2_Attrib *rnglists_base_off_attrib = &dw2_attrib_nil; + DW2_Attrib *str_offsets_base_off_attrib = &dw2_attrib_nil; + DW2_Attrib *addr_base_off_attrib = &dw2_attrib_nil; + DW2_Attrib *loclist_base_off_attrib = &dw2_attrib_nil; + DW2_Attrib *comp_dir_attrib = &dw2_attrib_nil; + for EachNode(n, DW2_AttribNode, tag->attribs.first) + { + switch(n->v.attrib_kind) + { + default:{}break; +#define Case(name, name_upper) case DW_AttribKind_##name_upper:{name##_attrib = &n->v;}break + Case(low_pc, LowPc); + Case(lang, Language); + Case(rnglists_base_off, RngListsBase); + Case(str_offsets_base_off, StrOffsetsBase); + Case(addr_base_off, AddrBase); + Case(loclist_base_off, LocListsBase); + Case(comp_dir, CompDir); +#undef Case + } + } + + // rjf: fill basics + ctx_out->unit_base_addr = low_pc_attrib->val.addr; + ctx_out->language = lang_attrib->val.u128.u64[0]; + ctx_out->unit_dir = comp_dir_attrib->val.string; + + // rjf: find offset tables + Rng1U64Array rnglists_tables_ranges_array = {offset_tables->rnglists_tables_ranges, offset_tables->rnglists_tables_count}; + Rng1U64Array str_offsets_tables_ranges_array = {offset_tables->str_offsets_tables_ranges, offset_tables->str_offsets_tables_count}; + Rng1U64Array addr_tables_ranges_array = {offset_tables->addr_tables_ranges, offset_tables->addr_tables_count}; + Rng1U64Array loclist_tables_ranges_array = {offset_tables->loclists_tables_ranges, offset_tables->loclists_tables_count}; + { + // rjf: find rnglists table + { + U64 rnglists_base_off = rnglists_base_off_attrib->val.u128.u64[0]; + U64 rnglists_table_num = rng1u64_array_num_from_value__binary_search(&rnglists_tables_ranges_array, rnglists_base_off); + if(0 < rnglists_table_num && rnglists_table_num <= rnglists_tables_ranges_array.count) + { + DW2_OffsetTable *table = &offset_tables->rnglists_tables[rnglists_table_num-1]; + ctx_out->rnglists_table = table; + } + } + + // rjf: find str offsets table + { + U64 str_offsets_base_off = str_offsets_base_off_attrib->val.u128.u64[0]; + U64 str_offsets_table_num = rng1u64_array_num_from_value__binary_search(&str_offsets_tables_ranges_array, str_offsets_base_off); + if(0 < str_offsets_table_num && str_offsets_table_num <= str_offsets_tables_ranges_array.count) + { + DW2_OffsetTable *table = &offset_tables->str_offsets_tables[str_offsets_table_num-1]; + ctx_out->str_offsets_table = table; + } + } + + // rjf: find addr table + { + U64 addr_base_off = addr_base_off_attrib->val.u128.u64[0]; + U64 addr_table_num = rng1u64_array_num_from_value__binary_search(&addr_tables_ranges_array, addr_base_off); + if(0 < addr_table_num && addr_table_num <= addr_tables_ranges_array.count) + { + DW2_OffsetTable *table = &offset_tables->addr_tables[addr_table_num-1]; + ctx_out->addr_table = table; + } + } + + // rjf: find loclists table + { + U64 loclist_base_off = loclist_base_off_attrib->val.u128.u64[0]; + U64 loclist_table_num = rng1u64_array_num_from_value__binary_search(&loclist_tables_ranges_array, loclist_base_off); + if(0 < loclist_table_num && loclist_table_num <= loclist_tables_ranges_array.count) + { + DW2_OffsetTable *table = &offset_tables->loclists_tables[loclist_table_num-1]; + ctx_out->loclists_table = table; + } + } + } +} + +//////////////////////////////// +//~ rjf: Tag Parsing + +internal U64 +dw2_read_tag(Arena *arena, DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_Tag *tag_out) +{ + U64 start_off = off; + + // rjf: read tag's abbrev ID + U64 abbrev_id = 0; + off += str8_deserial_read_uleb128(data, off, &abbrev_id); + + // rjf: map abbrev ID -> abbrev offset + U64 abbrev_off = 0; + { + DW2_AbbrevMap *abbrev_map = ctx->abbrev_map; + U64 hash = u64_hash_from_str8(str8_struct(&abbrev_id)); + U64 slot_idx = hash%abbrev_map->slots_count; + for EachNode(n, DW2_AbbrevMapNode, abbrev_map->slots[slot_idx]) + { + if(n->id == abbrev_id) + { + abbrev_off = n->off; + break; + } + } + } + + // rjf: read abbrev header + U64 tag_kind = 0; + U8 has_children = 0; + U64 attrib_abbrev_read_off = 0; + { + String8 abbrev_data = raw->sec[DW_SectionKind_Abbrev].data; + U64 abbrev_read_off = abbrev_off; + U64 id = 0; + abbrev_read_off += str8_deserial_read_uleb128(abbrev_data, abbrev_read_off, &id); + if(id != 0) + { + abbrev_read_off += str8_deserial_read_uleb128(abbrev_data, abbrev_read_off, &tag_kind); + abbrev_read_off += str8_deserial_read_struct(abbrev_data, abbrev_read_off, &has_children); + } + attrib_abbrev_read_off = abbrev_read_off; + } + + // rjf: walk abbrev / info in lock-step; read all tag attributes + DW2_AttribList attribs = {0}; + if(abbrev_id != 0) + { + String8 abbrev_data = raw->sec[DW_SectionKind_Abbrev].data; + U64 abbrev_read_off = attrib_abbrev_read_off; + for(;;) + { + U64 abbrev_start_read_off = abbrev_read_off; + + // rjf: read next attribute abbreviation from .debug_abbrev + U64 attrib_kind = 0; + U64 attrib_form_kind = 0; + U64 implicit_const = 0; + abbrev_read_off += str8_deserial_read_uleb128(abbrev_data, abbrev_read_off, &attrib_kind); + abbrev_read_off += str8_deserial_read_uleb128(abbrev_data, abbrev_read_off, &attrib_form_kind); + if(attrib_form_kind == DW_FormKind_ImplicitConst) + { + abbrev_read_off += str8_deserial_read_uleb128(abbrev_data, abbrev_read_off, &implicit_const); + } + + // rjf: indirect form -> form kind is encoded in .debug_info (because why not) + if(attrib_form_kind == DW_FormKind_Indirect) + { + off += str8_deserial_read_uleb128(data, off, &attrib_form_kind); + } + + // rjf: read attribute's value from .debug_info + DW2_FormVal val = {0}; + if(attrib_kind != 0) + { + off += dw2_read_form_val(raw, ctx, data, off, attrib_form_kind, implicit_const, &val); + } + + // rjf: push + if(attrib_kind != 0) + { + DW2_AttribNode *n = push_array(arena, DW2_AttribNode, 1); + SLLQueuePush(attribs.first, attribs.last, n); + attribs.count += 1; + n->v.attrib_kind = attrib_kind; + n->v.val = val; + } + + // rjf: no movement, or no attrib kind -> done + if(abbrev_read_off == abbrev_start_read_off || attrib_kind == 0) + { + break; + } + } + } + + // rjf: fill output + tag_out->kind = (DW_TagKind)tag_kind; + tag_out->has_children = !!has_children; + tag_out->attribs = attribs; + + // rjf: return # of bytes read + U64 bytes_read = (off - start_off); + return bytes_read; +} + +internal DW2_Attrib * +dw2_attrib_from_kind(DW2_Tag *tag, DW_AttribKind kind) +{ + DW2_Attrib *result = &dw2_attrib_nil; + for EachNode(n, DW2_AttribNode, tag->attribs.first) + { + if(n->v.attrib_kind == kind) + { + result = &n->v; + break; + } + } + return result; +} + +internal U64 +dw2_reference_info_off_from_form_val(DW2_ParseCtx *ctx, DW2_FormVal *v) +{ + U64 result = 0; + switch(v->kind) + { + default:{}break; + case DW_FormKind_Ref1: + case DW_FormKind_Ref2: + case DW_FormKind_Ref4: + case DW_FormKind_Ref8: + { + result = ctx->unit_base_info_off + v->u128.u64[0]; + }break; + // TODO(rjf): DW_FormKind_RefAddr, DW_FormKind_RefUData, DW_FormKind_RefSig8, DW_FormKind_RefSup8, etc. + } + return result; +} + +//////////////////////////////// +//~ rjf: Line Table Parsing + +internal U64 +dw2_read_line_table_header(Arena *arena, DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_LineTableHeader *out) +{ + Temp scratch = scratch_begin(&arena, 1); + U64 start_off = off; + + ////////////////////////////// + //- rjf: read unit length + // + U64 unit_length = 0; + DW_Format format = DW_Format_32Bit; + off += dw2_read_initial_length(data, off, &unit_length, &format); + U64 off_opl = off + unit_length; + + ////////////////////////////// + //- rjf: read version + // + DW_Version version = DW_Version_Null; + off += str8_deserial_read_struct(data, off, &version); + + ////////////////////////////// + //- rjf: read address / segment selector sizes + // + U8 addr_size = 0; + U8 segment_selector_size = 0; + switch(version) + { + // NOTE(rjf): pre-dwarf5: assume from context + default: + { + addr_size = ctx->addr_size; + }break; + + // NOTE(rjf): @dwarf5 read address / segment selector sizes explicitly + case DW_Version_5: + { + off += str8_deserial_read_struct(data, off, &addr_size); + off += str8_deserial_read_struct(data, off, &segment_selector_size); + }break; + } + + ////////////////////////////// + //- rjf: read all remaining flat header properties + // + U64 opl_header_length_off = 0; + U64 header_length = 0; + U8 min_inst_length = 0; + U8 max_ops_per_inst = 1; + U8 default_is_stmt = 0; + S8 line_base = 0; + U8 line_range = 0; + U8 opcode_base = 0; + { + off += dw2_read_fmt_u64(data, off, format, &header_length); + opl_header_length_off = off; + off += str8_deserial_read_struct(data, off, &min_inst_length); + off += str8_deserial_read_struct(data, off, &max_ops_per_inst); + off += str8_deserial_read_struct(data, off, &default_is_stmt); + off += str8_deserial_read_struct(data, off, &line_base); + off += str8_deserial_read_struct(data, off, &line_range); + off += str8_deserial_read_struct(data, off, &opcode_base); + } + + ////////////////////////////// + //- rjf: read opcode lengths + // + U64 opcode_lengths_count = (opcode_base > 0 ? opcode_base - 1 : 0); + U8 *opcode_lengths = 0; + if(opcode_lengths_count > 0) + { + opcode_lengths = str8_skip(data, off).str; + off += sizeof(opcode_lengths[0]) * opcode_lengths_count; + } + + ////////////////////////////// + //- rjf: read directory / file tables + // + DW2_LineTableFileArray dirs = {0}; + DW2_LineTableFileArray files = {0}; + switch(version) + { + //////////////////////////// + //- rjf: pre-dwarf5: simple(r) well-defined format... still ulebs everywhere but oh well... + // just wait until the next case... + // + default: + { + //- rjf: gather directories + DW2_LineTableFileList dir_list = {0}; + { + // rjf: push compile directory as first list element, always + { + DW2_LineTableFileNode *n = push_array(scratch.arena, DW2_LineTableFileNode, 1); + SLLQueuePush(dir_list.first, dir_list.last, n); + dir_list.count += 1; + n->v.file_name = ctx->unit_dir; + } + + // rjf: gather additional directories + for(;off < off_opl;) + { + String8 dir = {0}; + off += str8_deserial_read_cstr(data, off, &dir); + if(dir.size != 0) + { + DW2_LineTableFileNode *n = push_array(scratch.arena, DW2_LineTableFileNode, 1); + SLLQueuePush(dir_list.first, dir_list.last, n); + dir_list.count += 1; + n->v.file_name = dir; + } + else + { + break; + } + } + } + + //- rjf: gather files + DW2_LineTableFileList file_list = {0}; + { + // rjf: push main compilation unit file as first list element, always + { + DW2_LineTableFileNode *n = push_array(scratch.arena, DW2_LineTableFileNode, 1); + SLLQueuePush(file_list.first, file_list.last, n); + file_list.count += 1; + n->v.file_name = ctx->unit_file; + } + + // rjf: gather additional files + for(;off < off_opl;) + { + U8 next_byte = 0; + str8_deserial_read_struct(data, off, &next_byte); + if(next_byte == 0) + { + break; + } + String8 file_name = {0}; + U64 dir_idx = 0; + U64 modify_time = 0; + U64 file_size = 0; + off += str8_deserial_read_cstr(data, off, &file_name); + off += str8_deserial_read_uleb128(data, off, &dir_idx); + off += str8_deserial_read_uleb128(data, off, &modify_time); + off += str8_deserial_read_uleb128(data, off, &file_size); + if(file_name.size != 0) + { + DW2_LineTableFileNode *n = push_array(scratch.arena, DW2_LineTableFileNode, 1); + SLLQueuePush(file_list.first, file_list.last, n); + file_list.count += 1; + n->v.file_name = file_name; + n->v.dir_idx = dir_idx; + n->v.modify_time = modify_time; + n->v.file_size = file_size; + } + } + } + + //- rjf: flatten + { + dirs.count = dir_list.count; + dirs.v = push_array(arena, DW2_LineTableFile, dirs.count); + files.count = file_list.count; + files.v = push_array(arena, DW2_LineTableFile, files.count); + { + U64 idx = 0; + for EachNode(n, DW2_LineTableFileNode, dir_list.first) + { + MemoryCopyStruct(&dirs.v[idx], &n->v); + idx += 1; + } + } + { + U64 idx = 0; + for EachNode(n, DW2_LineTableFileNode, file_list.first) + { + MemoryCopyStruct(&files.v[idx], &n->v); + idx += 1; + } + } + } + }break; + + //////////////////////////// + //- rjf: @dwarf5: another VM! d'oh. :( + // + case DW_Version_5: + { + //- rjf: read directory & file tables + for(B32 do_files = 0, do_dirs = 1; do_files <= 1; do_files += 1, do_dirs = 0) + { + // rjf: read header + U8 entry_formats_count = 0; + off += str8_deserial_read_struct(data, off, &entry_formats_count); + U64 *entry_formats = push_array(scratch.arena, U64, entry_formats_count*2); + for EachIndex(idx, entry_formats_count) + { + off += str8_deserial_read_uleb128(data, off, &entry_formats[idx*2 + 0]); + off += str8_deserial_read_uleb128(data, off, &entry_formats[idx*2 + 1]); + } + U64 table_count = 0; + off += str8_deserial_read_uleb128(data, off, &table_count); + + // rjf: read all table entries + DW2_LineTableFileArray table = {0}; + table.count = table_count; + table.v = push_array(arena, DW2_LineTableFile, table.count); + { + U64 idx = 0; + for(;off < off_opl && idx < table.count; idx += 1) + { + DW2_LineTableFile *entry_out = &table.v[idx]; + for(U64 entry_format_idx = 0; entry_format_idx < entry_formats_count; entry_format_idx += 1) + { + DW_LNCT lnct = (DW_LNCT)entry_formats[entry_format_idx*2 + 0]; + DW_FormKind form_kind = (DW_FormKind)entry_formats[entry_format_idx*2 + 1]; + DW2_FormVal form_val = {0}; + off += dw2_read_form_val(raw, ctx, data, off, form_kind, 0, &form_val); + switch(lnct) + { + default: + { + log_infof("DWARF LNCT encoding not currently supported (0x%I64x).\n", (U64)lnct); + }break; + case DW_LNCT_Path: + { + entry_out->file_name = form_val.string; + }break; + case DW_LNCT_DirectoryIndex: + { + entry_out->dir_idx = form_val.u128.u64[0]; + }break; + case DW_LNCT_TimeStamp: + { + entry_out->modify_time = form_val.u128.u64[0]; + entry_out->flags |= DW2_LineTableFileFlag_HasModifyTime; + }break; + case DW_LNCT_Size: + { + entry_out->file_size = form_val.u128.u64[0]; + }break; + case DW_LNCT_MD5: + { + entry_out->md5.u128 = form_val.u128; + entry_out->flags |= DW2_LineTableFileFlag_HasMD5; + }break; + case DW_LNCT_LLVM_Source: + { + entry_out->source = form_val.string; + }break; + } + } + } + } + + // rjf: store + if(0){} + else if(do_files) { files = table; } + else if(do_dirs) { dirs = table; } + } + + }break; + } + + ////////////////////////////// + //- rjf: fill output + // + if(out) + { + out->unit_length = unit_length; + out->format = format; + out->version = version; + out->addr_size = addr_size; + out->segment_selector_size = segment_selector_size; + out->header_length = header_length; + out->min_inst_length = min_inst_length; + out->max_ops_per_inst = max_ops_per_inst; + out->default_is_stmt = default_is_stmt; + out->line_base = line_base; + out->line_range = line_range; + out->opcode_base = opcode_base; + out->opcode_lengths_count = opcode_lengths_count; + out->opcode_lengths = opcode_lengths; + out->dirs = dirs; + out->files = files; + out->line_program_off = opl_header_length_off + header_length; + out->total_unit_data_size = (off_opl - start_off); + } + + U64 bytes_read = (off - start_off); + scratch_end(scratch); + return bytes_read; +} + +//////////////////////////////// +//~ rjf: String Offset Table Parsing (.debug_str_offsets) + +internal U64 +dw2_read_offset_table(String8 data, U64 off, DW2_OffsetTable *out) +{ + U64 start_off = off; + { + // rjf: read data length / format + U64 unit_data_length = 0; + DW_Format format = DW_Format_Null; + off += dw2_read_initial_length(data, off, &unit_data_length, &format); + U64 unit_data_off_opl = off + unit_data_length; + + // rjf: read version + DW_Version version = DW_Version_Null; + off += str8_deserial_read_struct(data, off, &version); + + // rjf: version 5: read rest (this section only exists in 5+) + if(version == DW_Version_5) + { + // rjf: read address / segment selector size (these need to be 0 in non-address offset tables) + U8 addr_size = 0; + U8 segment_selector_size = 0; + off += str8_deserial_read_struct(data, off, &addr_size); + off += str8_deserial_read_struct(data, off, &segment_selector_size); + + // rjf: determine entry size + U64 entry_size = dw_addr_size_from_format(format); + if(addr_size != 0) + { + entry_size = addr_size + segment_selector_size; + } + + // rjf: fill table info + out->format = format; + out->version = version; + out->addr_size = addr_size; + out->segment_selector_size = segment_selector_size; + out->entry_size = entry_size; + out->entries_count = (unit_data_off_opl - off) / out->entry_size; + out->entries = data.str + off; + + // rjf: skip table + off = unit_data_off_opl; + } + } + U64 bytes_read = (off - start_off); + return bytes_read; +} + +internal DW2_OffsetTableList +dw2_offset_table_list_from_data(Arena *arena, String8 data) +{ + DW2_OffsetTableList list = {0}; + for(U64 off = 0; off < data.size;) + { + U64 start_off = off; + DW2_OffsetTable table = {0}; + off += dw2_read_offset_table(data, off, &table); + if(table.entries != 0) + { + DW2_OffsetTableNode *n = push_array(arena, DW2_OffsetTableNode, 1); + SLLQueuePush(list.first, list.last, n); + n->v = table; + n->range = r1u64(start_off, off); + list.count += 1; + } + if(off == start_off) + { break; } - dw_cfa_inst_list_push(arena, &list, inst); } return list; } -internal -DW_DECODE_PTR(dw_decode_ptr_debug_frame) +internal B32 +dw2_try_offset_from_table_idx(DW2_OffsetTable *tbl, U64 idx, U64 *out) { - return dw_read_debug_frame_ptr(data, ud, ptr_out); + B32 result = 0; + if(idx < tbl->entries_count) + { + U64 entry_size = tbl->entry_size; + U64 entry_off = idx * entry_size; + if(tbl->addr_size != 0) + { + U64 segment_off = entry_off; + U64 addr_off = entry_off + tbl->segment_selector_size; + U64 segment = 0; + U64 addr = 0; + MemoryCopy(&segment, (U8 *)tbl->entries + segment_off, tbl->segment_selector_size); + MemoryCopy(&addr, (U8 *)tbl->entries + addr_off, tbl->addr_size); + // TODO(rjf): @segment_based_addressing + *out = addr; + } + else + { + MemoryCopy(out, (U8 *)tbl->entries + entry_off, entry_size); + } + result = 1; + } + return result; } +internal DW2_OffsetTableSet +dw2_offset_table_set_from_raw(Arena *arena, DW_Raw *raw) +{ + DW2_OffsetTableSet result = {0}; + { + struct + { + String8 data; + U64 *tables_count_out; + DW2_OffsetTable **tables_out; + Rng1U64 **tables_ranges_out; + } + tasks[] = + { + {raw->sec[DW_SectionKind_StrOffsets].data, &result.str_offsets_tables_count, &result.str_offsets_tables, &result.str_offsets_tables_ranges}, + {raw->sec[DW_SectionKind_RngLists].data, &result.rnglists_tables_count, &result.rnglists_tables, &result.rnglists_tables_ranges}, + {raw->sec[DW_SectionKind_Addr].data, &result.addr_tables_count, &result.addr_tables, &result.addr_tables_ranges}, + {raw->sec[DW_SectionKind_LocLists].data, &result.loclists_tables_count, &result.loclists_tables, &result.loclists_tables_ranges}, + }; + for EachElement(task_idx, tasks) + { + Temp scratch = scratch_begin(&arena, 1); + String8 data = tasks[task_idx].data; + DW2_OffsetTableList tables = dw2_offset_table_list_from_data(scratch.arena, data); + tasks[task_idx].tables_count_out[0] = tables.count; + tasks[task_idx].tables_out[0] = push_array(arena, DW2_OffsetTable, tables.count); + tasks[task_idx].tables_ranges_out[0] = push_array(arena, Rng1U64, tables.count); + { + U64 idx = 0; + for EachNode(n, DW2_OffsetTableNode, tables.first) + { + tasks[task_idx].tables_out[0][idx] = n->v; + tasks[task_idx].tables_ranges_out[0][idx] = n->range; + idx += 1; + } + } + scratch_end(scratch); + } + } + return result; +} + +//////////////////////////////// +//~ rjf: Range List Parsing (.debug_rnglists) + +internal Rng1U64List +dw2_rnglist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val) +{ + Rng1U64List result = {0}; + switch((DW_VersionEnum)ctx->version) + { + case DW_Version_Null:{}break; + + //- rjf: pre-dwarf5 + case DW_Version_1: + case DW_Version_2: + case DW_Version_3: + case DW_Version_4: + { + String8 data = raw->sec[DW_SectionKind_Ranges].data; + U64 ranges_off = ranges_off = form_val.u128.u64[0];; + U64 base_addr = ctx->unit_base_addr; + U64 sentinel = (ctx->addr_size == 4 ? max_U32 : max_U64); + for(U64 off = ranges_off; off < data.size;) + { + U64 start_off = off; + U64 range_min = 0; + U64 range_opl = 0; + off += str8_deserial_read(data, off, &range_min, ctx->addr_size, ctx->addr_size); + off += str8_deserial_read(data, off, &range_opl, ctx->addr_size, ctx->addr_size); + // + // NOTE(rjf): interpreting tuples: + // [0, 0) -> ending range list + // [max_U32/U64, depending on addr size, X) -> set new base address to X + // [N, M) -> new [base + N, base + M) range + // + if(range_min == 0 && range_opl == 0) + { + break; + } + else if(range_min == sentinel) + { + base_addr = range_opl; + } + else if(off == start_off) + { + break; + } + else + { + rng1u64_list_push(arena, &result, r1u64(base_addr + range_min, base_addr + range_opl)); + } + if(off == start_off) + { + break; + } + } + }break; + + //- rjf: @dwarf5 + case DW_Version_5: + { + String8 data = raw->sec[DW_SectionKind_RngLists].data; + + // rjf: determine section offset - sometimes this is encoded directly, + // other times it is relative, based on the form kind - more variability + // in this awful format + U64 rnglist_off = 0; + switch(form_val.kind) + { + default:{}break; + case DW_FormKind_SecOffset: + { + rnglist_off = form_val.u128.u64[0]; + }break; + case DW_FormKind_RngListx: + if(ctx->rnglists_table != 0) + { + U64 rnglist_off_idx = form_val.u128.u64[0]; + dw2_try_offset_from_table_idx(ctx->rnglists_table, rnglist_off_idx, &rnglist_off); + }break; + } + + // rjf: in a HIGHLY UNEXPECTED TURN OF EVENTS, we now have to decode ANOTHER + // OPCODE STREAM to unpack the actual list of ranges!!! + U64 rle_sentinel = (ctx->addr_size == 4 ? max_U32 : max_U64); + U64 base_addr = ctx->unit_base_addr; + for(U64 off = rnglist_off; off < data.size;) + { + U64 start_off = off; + + // rjf: decode op kind + DW_RLE rle_kind = DW_RLE_EndOfList; + off += str8_deserial_read_struct(data, off, &rle_kind); + + // rjf: obtain range from op + B32 good_range = 1; + Rng1U64 range = {0}; + switch(rle_kind) + { + default:{good_range = 0;}break; + case DW_RLE_BaseAddressx: + { + good_range = 0; + U64 addr_idx = 0; + off += str8_deserial_read_uleb128(data, off, &addr_idx); + if(ctx->addr_table != 0) + { + U64 new_base_addr = 0; + if(dw2_try_offset_from_table_idx(ctx->addr_table, addr_idx, &new_base_addr)) + { + good_range = 1; + base_addr = new_base_addr; + } + } + }break; + case DW_RLE_StartxEndx: + { + good_range = 0; + U64 start_idx = 0; + U64 end_idx = 0; + off += str8_deserial_read_uleb128(data, off, &start_idx); + off += str8_deserial_read_uleb128(data, off, &end_idx); + if(ctx->addr_table != 0) + { + U64 start = 0; + U64 end = 0; + if(dw2_try_offset_from_table_idx(ctx->addr_table, start_idx, &start) && + dw2_try_offset_from_table_idx(ctx->addr_table, end_idx, &end)) + { + good_range = 1; + range = r1u64(start, end); + } + } + }break; + case DW_RLE_StartxLength: + { + good_range = 0; + U64 start_idx = 0; + U64 length = 0; + off += str8_deserial_read_uleb128(data, off, &start_idx); + off += str8_deserial_read_uleb128(data, off, &length); + if(ctx->addr_table != 0) + { + U64 start = 0; + if(dw2_try_offset_from_table_idx(ctx->addr_table, start_idx, &start)) + { + good_range = 1; + range = r1u64(start, start+length); + } + } + }break; + case DW_RLE_OffsetPair: + { + U64 range_off_start = 0; + U64 range_off_end = 0; + off += str8_deserial_read_uleb128(data, off, &range_off_start); + off += str8_deserial_read_uleb128(data, off, &range_off_end); + range = r1u64(base_addr + range_off_start, base_addr + range_off_end); + }break; + case DW_RLE_BaseAddress: + { + U64 new_base_addr = 0; + off += str8_deserial_read(data, off, &new_base_addr, ctx->addr_size, ctx->addr_size); + base_addr = new_base_addr; + }break; + case DW_RLE_StartEnd: + { + U64 start = 0; + U64 end = 0; + off += str8_deserial_read(data, off, &start, ctx->addr_size, ctx->addr_size); + off += str8_deserial_read(data, off, &end, ctx->addr_size, ctx->addr_size); + range = r1u64(start, end); + }break; + case DW_RLE_StartLength: + { + U64 start = 0; + U64 length = 0; + off += str8_deserial_read(data, off, &start, ctx->addr_size, ctx->addr_size); + off += str8_deserial_read_uleb128(data, off, &length); + range = r1u64(start, start + length); + }break; + } + + // rjf: add range + if(good_range) + { + rng1u64_list_push(arena, &result, range); + } + + // rjf: end if no movement or end-of-list code + if(off == start_off || rle_kind == DW_RLE_EndOfList) + { + break; + } + } + }break; + } + return result; +} + +//////////////////////////////// +//~ rjf: Location List Parsing (.debug_loclists) + +internal DW2_LocList +dw2_loclist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val) +{ + DW2_LocList result = {0}; + switch((DW_VersionEnum)ctx->version) + { + case DW_Version_Null:{}break; + + //- rjf: pre-dwarf5 + case DW_Version_1: + case DW_Version_2: + case DW_Version_3: + case DW_Version_4: + { + String8 data = raw->sec[DW_SectionKind_Loc].data; + U64 locs_off = locs_off = form_val.u128.u64[0]; + U64 base_addr = ctx->unit_base_addr; + U64 sentinel = (ctx->addr_size == 4 ? max_U32 : max_U64); + for(U64 off = locs_off; off < data.size;) + { + U64 start_off = off; + U64 range_min = 0; + U64 range_opl = 0; + off += str8_deserial_read(data, off, &range_min, ctx->addr_size, ctx->addr_size); + off += str8_deserial_read(data, off, &range_opl, ctx->addr_size, ctx->addr_size); + // + // NOTE(rjf): interpreting tuples: + // [0, 0) -> ending range list + // [max_U32/U64, depending on addr size, X) -> set new base address to X + // [N, M) -> new [base + N, base + M) range + // + if(range_min == 0 && range_opl == 0) + { + break; + } + else if(range_min == sentinel) + { + base_addr = range_opl; + } + else if(off == start_off) + { + break; + } + else + { + U16 expr_size = 0; + off += str8_deserial_read_struct(data, off, &expr_size); + DW2_LocNode *n = push_array(arena, DW2_LocNode, 1); + n->v.range = r1u64(range_min + base_addr, range_opl + base_addr); + n->v.expr = str8_substr(data, r1u64(off, off+expr_size)); + SLLQueuePush(result.first, result.last, n); + result.count += 1; + off += expr_size; + } + if(off == start_off) + { + break; + } + } + }break; + + //- rjf: @dwarf5 + case DW_Version_5: + { + String8 data = raw->sec[DW_SectionKind_LocLists].data; + + // rjf: determine section offset - sometimes this is encoded directly, + // other times it is relative, based on the form kind - more variability + // in this awful format + U64 loclist_off = 0; + switch(form_val.kind) + { + default:{}break; + case DW_FormKind_SecOffset: + { + loclist_off = form_val.u128.u64[0]; + }break; + case DW_FormKind_LocListx: + if(ctx->rnglists_table != 0) + { + U64 loclist_off_idx = form_val.u128.u64[0]; + dw2_try_offset_from_table_idx(ctx->loclists_table, loclist_off_idx, &loclist_off); + }break; + } + + // rjf: in a HIGHLY UNEXPECTED TURN OF EVENTS, we now have to decode ANOTHER + // OPCODE STREAM to unpack the actual list of locations!!! + U64 rle_sentinel = (ctx->addr_size == 4 ? max_U32 : max_U64); + U64 base_addr = ctx->unit_base_addr; + for(U64 off = loclist_off; off < data.size;) + { + U64 start_off = off; + + // rjf: decode op kind + DW_LLE lle_kind = DW_LLE_EndOfList; + off += str8_deserial_read_struct(data, off, &lle_kind); + + // rjf: obtain range from op + B32 good_loc = 1; + Rng1U64 range = {0}; + switch(lle_kind) + { + default:{good_loc = 0;}break; + case DW_LLE_BaseAddressx: + { + good_loc = 0; + U64 addr_idx = 0; + off += str8_deserial_read_uleb128(data, off, &addr_idx); + if(ctx->addr_table != 0) + { + U64 new_base_addr = 0; + if(dw2_try_offset_from_table_idx(ctx->addr_table, addr_idx, &new_base_addr)) + { + good_loc = 1; + base_addr = new_base_addr; + } + } + }break; + case DW_LLE_StartxEndx: + { + good_loc = 0; + U64 start_idx = 0; + U64 end_idx = 0; + off += str8_deserial_read_uleb128(data, off, &start_idx); + off += str8_deserial_read_uleb128(data, off, &end_idx); + if(ctx->addr_table != 0) + { + U64 start = 0; + U64 end = 0; + if(dw2_try_offset_from_table_idx(ctx->addr_table, start_idx, &start) && + dw2_try_offset_from_table_idx(ctx->addr_table, end_idx, &end)) + { + good_loc = 1; + range = r1u64(start, end); + } + } + }break; + case DW_LLE_StartxLength: + { + good_loc = 0; + U64 start_idx = 0; + U64 length = 0; + off += str8_deserial_read_uleb128(data, off, &start_idx); + off += str8_deserial_read_uleb128(data, off, &length); + if(ctx->addr_table != 0) + { + U64 start = 0; + if(dw2_try_offset_from_table_idx(ctx->addr_table, start_idx, &start)) + { + good_loc = 1; + range = r1u64(start, start+length); + } + } + }break; + case DW_LLE_OffsetPair: + { + U64 range_off_start = 0; + U64 range_off_end = 0; + off += str8_deserial_read_uleb128(data, off, &range_off_start); + off += str8_deserial_read_uleb128(data, off, &range_off_end); + range = r1u64(base_addr + range_off_start, base_addr + range_off_end); + }break; + case DW_LLE_DefaultLocation: + { + range = r1u64(0, max_U64); + }break; + case DW_LLE_BaseAddress: + { + U64 new_base_addr = 0; + off += str8_deserial_read(data, off, &new_base_addr, ctx->addr_size, ctx->addr_size); + base_addr = new_base_addr; + }break; + case DW_LLE_StartEnd: + { + U64 start = 0; + U64 end = 0; + off += str8_deserial_read(data, off, &start, ctx->addr_size, ctx->addr_size); + off += str8_deserial_read(data, off, &end, ctx->addr_size, ctx->addr_size); + range = r1u64(start, end); + }break; + case DW_LLE_StartLength: + { + U64 start = 0; + U64 length = 0; + off += str8_deserial_read(data, off, &start, ctx->addr_size, ctx->addr_size); + off += str8_deserial_read_uleb128(data, off, &length); + range = r1u64(start, start + length); + }break; + } + + // rjf: read expression + String8 expr = {0}; + if(good_loc && lle_kind != DW_LLE_BaseAddress && lle_kind != DW_LLE_BaseAddressx) + { + U64 expr_size = 0; + off += str8_deserial_read_uleb128(data, off, &expr_size); + expr = str8_substr(data, r1u64(off, off+expr_size)); + off += expr_size; + } + + // rjf: add range + if(good_loc) + { + DW2_LocNode *n = push_array(arena, DW2_LocNode, 1); + n->v.range = range; + n->v.expr = expr; + SLLQueuePush(result.first, result.last, n); + result.count += 1; + } + + // rjf: end if no movement or end-of-list code + if(off == start_off || lle_kind == DW_LLE_EndOfList) + { + break; + } + } + }break; + } + return result; +} + +//////////////////////////////// +//~ rjf: Unwind Info Parsing (.debug_frame) + +internal U64 +dw2_read_cfi_header(String8 data, U64 off, DW_CFIHeader *cfi_header_out) +{ + U64 start_off = off; + + // rjf: read length / format + U64 length = 0; + DW_Format fmt = DW_Format_Null; + U64 length_size = dw2_read_initial_length(data, off, &length, &fmt); + + // rjf: find entry info, read ID + Rng1U64 entry_range = r1u64(off, off + length_size + length); + String8 entry_data = str8_substr(data, entry_range); + U64 id = 0; + U64 id_size = dw2_read_fmt_u64(entry_data, length_size, fmt, &id); + + // rjf: fill + cfi_header_out->kind = ((fmt == DW_Format_32Bit && id == max_U32) || (fmt == DW_Format_64Bit && id == max_U64)) ? DW_CFIKind_CIE : DW_CFIKind_FDE; + cfi_header_out->fmt = fmt; + cfi_header_out->entry_range = entry_range; + cfi_header_out->cie_pointer = id; + cfi_header_out->cie_pointer_off = off + length_size; + + U64 bytes_read = (off - start_off); + return bytes_read; +} + +internal U64 +dw2_read_cie(String8 data, U64 off, DW_Format fmt, Arch arch, DW_CIE *cie_out) +{ + U64 start_off = off; + + // rjf: read id + U64 id = 0; + off += dw2_read_fmt_u64(data, off, fmt, &id); + + // rjf: read version + U8 version = 0; + off += str8_deserial_read_struct(data, off, &version); + + // rjf: read aug string + String8 aug_string = {0}; + U64 aug_string_off = off; + off += str8_deserial_read_cstr(data, off, &aug_string); + U64 aug_string_off_opl = off; + + // rjf: read address/segment-selector size + U8 address_size = 0; + U8 segment_selector_size = 0; + if(version >= DW_Version_4) + { + off += str8_deserial_read_struct(data, off, &address_size); + off += str8_deserial_read_struct(data, off, &segment_selector_size); + } + else + { + address_size = byte_size_from_arch(arch); + } + + // rjf: read alignments + U64 code_align_factor = 0; + U64 data_align_factor = 0; + off += str8_deserial_read_uleb128(data, off, &code_align_factor); + off += str8_deserial_read_uleb128(data, off, &data_align_factor); + + // rjf: read return address register encoding + U64 ret_addr_reg = 0; + switch(version) + { + case DW_Version_1: + { + off += str8_deserial_read(data, off, &ret_addr_reg, 1, 1); + }break; + default: + { + off += str8_deserial_read_uleb128(data, off, &ret_addr_reg); + }break; + } + + // rjf: fill output + { + cie_out->aug_string_range = r1u64(aug_string_off, aug_string_off_opl); + 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 = fmt; + cie_out->version = version; + cie_out->address_size = address_size; + cie_out->segment_selector_size = segment_selector_size; + } + + U64 bytes_read = (off - start_off); + return bytes_read; +} + +internal U64 +dw2_read_fde(String8 data, U64 off, DW_Format fmt, Arch arch, DW_CIE *cie, DW_FDE *fde_out) +{ + U64 start_off = off; + + // rjf: skip format-dependent prefix + off += (fmt == DW_Format_32Bit) ? 4 : 12; + + // rjf: read cie ptr + U64 cie_ptr = 0; + off += dw2_read_fmt_u64(data, off, fmt, &cie_ptr); + + // rjf: read address of first instruction + U64 pc_begin = 0; + off += str8_deserial_read(data, off, &pc_begin, cie->address_size, cie->address_size); + + // rjf: read instruction range size + U64 pc_range_size = 0; + off += str8_deserial_read(data, off, &pc_range_size, cie->address_size, cie->address_size); + + // rjf: skip aug data + off += dim_1u64(cie->aug_string_range); + + // rjf: fill output + fde_out->cie_pointer = cie_ptr; + fde_out->pc_range = r1u64(pc_begin, pc_begin + pc_range_size); + + U64 bytes_read = (off - start_off); + return bytes_read; +} + +internal B32 +dw2_try_cfi_from_data(String8 data, U64 off, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out) +{ + B32 result = 0; + { + DW_CFIHeader fde_header = {0}; + off += dw2_read_cfi_header(data, off, &fde_header); + if(fde_header.kind == DW_CFIKind_FDE) + { + DW_CFIHeader cie_header = {0}; + dw2_read_cfi_header(data, fde_header.cie_pointer, &cie_header); + if(cie_header.kind == DW_CFIKind_CIE) + { + result = 1; + dw2_read_cie(data, cie_header.entry_range.min, cie_header.fmt, arch, cie_out); + dw2_read_fde(data, fde_header.entry_range.min, fde_header.fmt, arch, cie_out, fde_out); + } + } + } + return result; +} diff --git a/src/dwarf/dwarf_parse.h b/src/dwarf/dwarf_parse.h index 2bddbe72..b8bd3554 100644 --- a/src/dwarf/dwarf_parse.h +++ b/src/dwarf/dwarf_parse.h @@ -4,525 +4,453 @@ #ifndef DWARF_PARSE_H #define DWARF_PARSE_H -typedef struct DW_Section +//////////////////////////////// +//~ rjf: Raw Section Data + +typedef struct DW_Section DW_Section; +struct DW_Section { String8 name; String8 data; - B32 is_dwo; -} DW_Section; +}; -typedef struct DW_Raw +typedef struct DW_Raw DW_Raw; +struct DW_Raw { - DW_Section sec[DW_Section_COUNT]; - DW_Section sup[DW_Section_COUNT]; -} DW_Raw; + DW_Section sec[DW_SectionKind_COUNT]; + DW_Section sup[DW_SectionKind_COUNT]; +}; -typedef struct DW_ListUnit +//////////////////////////////// +//~ rjf: Unit Headers + +typedef struct DW2_UnitHeader DW2_UnitHeader; +struct DW2_UnitHeader { DW_Version version; - U64 address_size; - U64 segment_selector_size; - U64 entry_size; - String8 entries; -} DW_ListUnit; + DW_Format format; + U64 abbrev_off; + U64 addr_size; + DW_CompUnitKind kind; + U64 dwo_id; +}; -typedef struct DW_ListUnitInput +//////////////////////////////// +//~ rjf: Abbreviation Map (ID -> .debug_abbrev Offset) + +typedef struct DW2_AbbrevAttrib DW2_AbbrevAttrib; +struct DW2_AbbrevAttrib { - U64 addr_count; - U64 str_offset_count; - U64 rnglist_count; - U64 loclist_count; - Rng1U64Array addr_ranges; - Rng1U64Array str_offset_ranges; - Rng1U64Array rnglist_ranges; - Rng1U64Array loclist_ranges; - DW_ListUnit *addrs; - DW_ListUnit *str_offsets; - DW_ListUnit *rnglists; - DW_ListUnit *loclists; -} DW_ListUnitInput; + DW_AttribKind attrib_kind; + DW_FormKind form_kind; + U64 implicit_const; +}; -typedef struct DW_AbbrevTableEntry +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; - U64 off; -} DW_AbbrevTableEntry; - -typedef struct DW_AbbrevTable DW_AbbrevTable; -struct DW_AbbrevTable -{ - U64 count; - DW_AbbrevTableEntry *entries; + DW_TagKind tag_kind; + B8 has_children; }; -typedef enum DW_AbbrevKind +typedef struct DW2_AbbrevMapNode DW2_AbbrevMapNode; +struct DW2_AbbrevMapNode { - DW_Abbrev_Null, - DW_Abbrev_Tag, - DW_Abbrev_Attrib, - DW_Abbrev_AttribSequenceEnd, - DW_Abbrev_DIEBegin, - DW_Abbrev_DIEEnd, -} DW_AbbrevKind; + DW2_AbbrevMapNode *next; + U64 id; + U64 off; +}; -typedef U32 DW_AbbrevFlags; +typedef struct DW2_AbbrevMap DW2_AbbrevMap; +struct DW2_AbbrevMap +{ + DW2_AbbrevMapNode **slots; + 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) + +typedef struct DW2_OffsetTable DW2_OffsetTable; +struct DW2_OffsetTable +{ + DW_Format format; + DW_Version version; + U8 addr_size; + U8 segment_selector_size; + U64 entry_size; + U64 entries_count; + 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_Version version; + DW_Format format; + DW_ExtFlags exts; + U64 addr_size; + U64 unit_base_addr; + U64 unit_base_info_off; + DW2_AbbrevMap *abbrev_map; + DW2_OffsetTable *rnglists_table; + DW2_OffsetTable *str_offsets_table; + DW2_OffsetTable *addr_table; + DW2_OffsetTable *loclists_table; + String8 unit_dir; + String8 unit_file; + DW_Language language; +}; + +//////////////////////////////// +//~ rjf: Tag Attributes + +typedef struct DW2_FormVal DW2_FormVal; +struct DW2_FormVal +{ + DW_FormKind kind; + U128 u128; + String8 string; + U64 addr; +}; + +typedef struct DW2_Attrib DW2_Attrib; +struct DW2_Attrib +{ + DW_AttribKind attrib_kind; + DW2_FormVal val; +}; + +typedef struct DW2_AttribNode DW2_AttribNode; +struct DW2_AttribNode +{ + DW2_AttribNode *next; + DW2_Attrib v; +}; + +typedef struct DW2_AttribList DW2_AttribList; +struct DW2_AttribList +{ + DW2_AttribNode *first; + DW2_AttribNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Tags + +typedef struct DW2_Tag DW2_Tag; +struct DW2_Tag +{ + DW_TagKind kind; + B32 has_children; + DW2_AttribList attribs; +}; + +//////////////////////////////// +//~ rjf: Line Info + +typedef U32 DW2_LineTableFileFlags; enum { - DW_AbbrevFlag_HasImplicitConst = (1 << 0), - DW_AbbrevFlag_HasChildren = (1 << 1), + DW2_LineTableFileFlag_HasMD5 = (1<<0), + DW2_LineTableFileFlag_HasModifyTime = (1<<1), }; -typedef struct DW_Abbrev +typedef struct DW2_LineTableFile DW2_LineTableFile; +struct DW2_LineTableFile { - DW_AbbrevKind kind; - U64 sub_kind; - U64 id; - S64 implicit_const; - DW_AbbrevFlags flags; -} DW_Abbrev; + String8 file_name; + DW2_LineTableFileFlags flags; + U64 dir_idx; + U64 modify_time; + U64 file_size; + MD5 md5; + String8 source; +}; -typedef struct DW_Attrib +typedef struct DW2_LineTableFileNode DW2_LineTableFileNode; +struct DW2_LineTableFileNode { - U64 info_off; - U64 abbrev_off; - U64 abbrev_id; - DW_AttribKind attrib_kind; - DW_Form form; -} DW_Attrib; + DW2_LineTableFileNode *next; + DW2_LineTableFile v; +}; -typedef struct DW_AttribNode +typedef struct DW2_LineTableFileList DW2_LineTableFileList; +struct DW2_LineTableFileList { - struct DW_AttribNode *next; - DW_Attrib v; -} DW_AttribNode; + DW2_LineTableFileNode *first; + DW2_LineTableFileNode *last; + U64 count; +}; -typedef struct DW_AttribList +typedef struct DW2_LineTableFileArray DW2_LineTableFileArray; +struct DW2_LineTableFileArray { - DW_AttribNode *first; - DW_AttribNode *last; - U64 count; -} DW_AttribList; + DW2_LineTableFile *v; + U64 count; +}; -typedef U8 DW_TagSpare; -typedef struct DW_Tag +typedef struct DW2_LineTableHeader DW2_LineTableHeader; +struct DW2_LineTableHeader { - B32 has_children; - U64 abbrev_id; - DW_TagKind kind; - DW_AttribList attribs; - U64 info_off; - DW_TagSpare v; -} DW_Tag; + U64 unit_length; + DW_Format format; + DW_Version version; + U8 addr_size; + U8 segment_selector_size; + U64 header_length; + U8 min_inst_length; + U8 max_ops_per_inst; + U8 default_is_stmt; + S8 line_base; + U8 line_range; + U8 opcode_base; + U64 opcode_lengths_count; + U8 *opcode_lengths; + DW2_LineTableFileArray dirs; + DW2_LineTableFileArray files; + U64 line_program_off; + U64 total_unit_data_size; // NOTE(rjf): would be implied by `unit_length`, but DWARF makes that the size *past* the variable-width unit-length field itself +}; -typedef struct DW_TagNode +typedef struct DW2_LineVMRegs DW2_LineVMRegs; +struct DW2_LineVMRegs { - DW_Tag tag; - struct DW_TagNode *sibling; - struct DW_TagNode *first_child; - struct DW_TagNode *last_child; -} DW_TagNode; + U64 address; + U64 vliw_op_index; + U64 file_index; + U64 line; + U64 column; + B32 is_stmt; + B32 basic_block; + B32 end_sequence; + B32 prologue_end; + B32 epilogue_begin; + U64 isa; + U64 discriminator; +}; -typedef struct DW_Loc +//////////////////////////////// +//~ rjf: Location Lists + +typedef struct DW2_Loc DW2_Loc; +struct DW2_Loc { Rng1U64 range; String8 expr; -} DW_Loc; +}; -typedef struct DW_LocNode +typedef struct DW2_LocNode DW2_LocNode; +struct DW2_LocNode { - DW_Loc v; - struct DW_LocNode *next; -} DW_LocNode; + DW2_LocNode *next; + DW2_Loc v; +}; -typedef struct DW_LocList +typedef struct DW2_LocList DW2_LocList; +struct DW2_LocList { - U64 count; - DW_LocNode *first; - DW_LocNode *last; -} DW_LocList; - -typedef struct DW_CompUnit -{ - B32 relaxed; - DW_Ext ext; - DW_CompUnitKind kind; - DW_Version version; - DW_Format format; - U64 address_size; - U64 abbrev_off; - Rng1U64 info_range; - U64 first_tag_info_off; - DW_AbbrevTable abbrev_table; - DW_ListUnit *addr_lu; - DW_ListUnit *str_offsets_lu; - DW_ListUnit *rnglists_lu; - DW_ListUnit *loclists_lu; - U64 low_pc; - U64 dwo_id; - DW_Tag tag; - HashTable *tag_ht; -} DW_CompUnit; - -typedef struct DW_TagTree -{ - DW_TagNode *root; - U64 tag_count; -} DW_TagTree; + DW2_LocNode *first; + DW2_LocNode *last; + U64 count; +}; //////////////////////////////// +//~ rjf: Unwind Info -typedef struct DW_LineFile +typedef enum DW_CFIKind { - String8 path; - U64 dir_idx; - U64 time_stamp; - U64 size; - U128 md5; - String8 source; -} DW_LineFile; + DW_CFIKind_Null, + DW_CFIKind_CIE, // Common Information Entry + DW_CFIKind_FDE, // Frame Description Entry + DW_CFIKind_COUNT +} +DW_CFIKind; -typedef struct DW_LineFileNode +typedef struct DW_CFIHeader DW_CFIHeader; +struct DW_CFIHeader { - struct DW_LineFileNode *next; - DW_LineFile file; -} DW_LineFileNode; + DW_CFIKind kind; + DW_Format fmt; + Rng1U64 entry_range; + U64 cie_pointer_off; + U64 cie_pointer; +}; -typedef struct DW_LineFileList +typedef struct DW_CIE DW_CIE; +struct DW_CIE { - U64 node_count; - DW_LineFileNode *first; - DW_LineFileNode *last; -} DW_LineFileList; - -typedef struct DW_LineFileArray -{ - U64 count; - DW_LineFile *v; -} DW_LineFileArray; - -typedef struct DW_LineVMHeader -{ - U64 unit_length; - DW_Version version; - U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str. - U8 segment_selector_size; - U64 header_length; - U8 min_inst_len; - U8 max_ops_for_inst; - U8 default_is_stmt; - S8 line_base; - U8 line_range; - U8 opcode_base; - U64 num_opcode_lens; - U8 *opcode_lens; - U64 line_program_off; - String8Array dir_table; - DW_LineFileArray file_table; -} DW_LineVMHeader; - -typedef struct DW_LineVMState -{ - U64 address; // Address of a machine instruction. - U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction. - - // Line table doesn't contain full path to a file, instead - // DWARF encodes path as two indices. First index will point into a directory - // table, and second points into a file name table. - U64 file_index; - - U64 line; - U64 column; - - B32 is_stmt; // Indicates that "address" points to place suitable for a breakpoint. - B32 basic_block; // Indicates that the "address" is inside a basic block. - - // Indicates that "address" points to place where function starts. - // Usually prologue is the place where compiler emits instructions to - // prepare stack for a function. - B32 prologue_end; - - B32 epilogue_begin; // Indicates that "address" points to section where function exits and unwinds stack. - U64 isa; // Instruction set that is used. - U64 discriminator; // Arbitrary id that indicates to which block these instructions belong. - B32 end_sequence; // Indicates that "address" points to the first instruction in the instruction block that follows. -} DW_LineVMState; - -typedef struct DW_LineVM -{ - Arena *arena; - U64 cursor; - String8 program; - DW_LineVMHeader header; - B32 new_line; - B32 new_seq; - B32 skip_opcode; - DW_LineVMState state; - U64 advance; - U64 opcode_off; - DW_StdOpcode opcode; - DW_ExtOpcode ext_opcode; - U64 ext_length; - U64 line_advance; - U64 addr_advance; - HashTable *ext_file_ht; - struct { - union { - String8 string; - U64 u64; - S64 s64; - }; - } operands[4]; - String8 error; -} DW_LineVM; - -//////////////////////////////// -// .debug_pubnames and .debug_pubtypes - -typedef struct DW_PubStringsBucket -{ - struct DW_PubStringsBucket *next; - String8 string; - U64 info_off; - U64 cu_info_off; -} DW_PubStringsBucket; - -typedef struct DW_PubStringsTable -{ - U64 size; - DW_PubStringsBucket **buckets; -} DW_PubStringsTable; - -typedef struct DW_Reference -{ - DW_CompUnit *cu; - U64 info_off; // global .debug_info offset -} DW_Reference; - -//////////////////////////////// -//~ Expression - -typedef union DW_ExprOperand -{ - U8 u8; - U16 u16; - U32 u32; - U64 u64; - - S8 s8; - S16 s16; - S32 s32; - S64 s64; - - String8 block; -} DW_ExprOperand; - -typedef struct DW_ExprInst -{ - DW_ExprOp opcode; - DW_ExprOperand *operands; - U64 size; - struct DW_ExprInst *next; - struct DW_ExprInst *prev; -} DW_ExprInst; - -typedef struct DW_Expr -{ - U64 count; - DW_ExprInst *first; - DW_ExprInst *last; -} DW_Expr; - -//////////////////////////////// -// .debug_frame - -typedef struct DW_CIE -{ - String8 insts; - String8 aug_string; - String8 aug_data; - U64 code_align_factor; - S64 data_align_factor; - U64 ret_addr_reg; - U64 ext[4]; + 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; -} DW_CIE; + U8 version; + U8 address_size; + U8 segment_selector_size; +}; -typedef struct DW_FDE +typedef struct DW_FDE DW_FDE; +struct DW_FDE { - DW_Format format; - U64 cie_pointer; - Rng1U64 pc_range; - String8 insts; -} DW_FDE; + U64 cie_pointer; + Rng1U64 pc_range; +}; -typedef union DW_CFA_Operand +typedef struct DW_CFI DW_CFI; +struct DW_CFI { - U64 u64; - S64 s64; - String8 block; -} DW_CFA_Operand; + DW_CIE cie; + DW_FDE fde; +}; -typedef enum -{ - DW_CFA_ParseErrorCode_NewInst, - DW_CFA_ParseErrorCode_End, - DW_CFA_ParseErrorCode_OutOfData -} DW_CFA_ParseErrorCode; +//////////////////////////////// +//~ rjf: Globals -typedef struct DW_CFA_Inst -{ - DW_CFA_Opcode opcode; - DW_CFA_Operand operands[DW_CFA_OperandMax]; -} DW_CFA_Inst; +global read_only DW2_Attrib dw2_attrib_nil = {0}; -typedef struct DW_CFA_InstNode -{ - DW_CFA_Inst v; - struct DW_CFA_InstNode *next; -} DW_CFA_InstNode; +//////////////////////////////// +//~ rjf: Basic Parsing Helpers -typedef struct DW_CFA_InstList -{ - U64 count; - DW_CFA_InstNode *first; - DW_CFA_InstNode *last; -} DW_CFA_InstList; +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); -#define DW_DECODE_PTR(name) U64 name(String8 data, void *ud, U64 *ptr_out) -typedef DW_DECODE_PTR(DW_DecodePtr); +//////////////////////////////// +//~ rjf: Unit Range Set Parsing (Top-Level .debug_info, .debug_aranges) -// hasher +internal Rng1U64Array dw2_unit_ranges_from_data(Arena *arena, String8 data); -internal U64 dw_hash_from_string(String8 string); +//////////////////////////////// +//~ rjf: Unit Header Parsing -// deserial helpers +internal U64 dw2_read_unit_header(String8 data, U64 off, DW2_UnitHeader *out); -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_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); +//////////////////////////////// +//~ rjf: Abbreviation Map Parsing -internal Rng1U64List dw_unit_ranges_from_data(Arena *arena, String8 data); -internal Rng1U64Array dw_unit_ranges_from_data_arr(Arena *arena, String8 data); +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); -// list units +//////////////////////////////// +//~ rjf: Form Value Parsing -internal U64 dw_read_list_unit_header_addr (String8 unit_data, DW_ListUnit *lu_out); -internal U64 dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out); -internal U64 dw_read_list_unit_header_list (String8 unit_data, DW_ListUnit *lu_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); -internal DW_ListUnitInput dw_list_unit_input_from_input(Arena *arena, DW_Raw *input); +//////////////////////////////// +//~ rjf: Parse Context Construction -internal U64 dw_offset_from_list_unit(DW_ListUnit *lu, U64 index); -internal U64 dw_addr_from_list_unit (DW_ListUnit *lu, U64 index); +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); -// abbrev table +//////////////////////////////// +//~ rjf: Tag Parsing -internal U64 dw_read_abbrev_tag (String8 data, U64 offset, DW_Abbrev *out_abbrev); -internal U64 dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev); +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); -internal DW_AbbrevTable dw_read_abbrev_table(Arena *arena, String8 abbrev_data, U64 abbrev_base); -internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id); +//////////////////////////////// +//~ rjf: Line Table Parsing -// form and tag +internal U64 dw2_read_line_table_header(Arena *arena, DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_LineTableHeader *out); -internal B32 dw_read_form (String8 data, DW_Version version, DW_Format unit_format, U64 address_size, DW_FormKind form_kind, S64 implicit_const, DW_Form *form_out, U64 *bytes_read_out); -internal U64 dw_read_tag (Arena *arena, DW_Raw *input, DW_AbbrevTable abbrev_table, DW_Version version, DW_Format format, U64 address_size, Rng1U64 cu_info_range, U64 tag_info_off, DW_Tag *tag_out); -internal U64 dw_read_tag_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out); +//////////////////////////////// +//~ rjf: Offset Table Parsing (.debug_str_offsets, .debug_rnglists) -// attrib interp +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); -internal U64 dw_interp_sec_offset(DW_Form form); -internal String8 dw_interp_exprloc (DW_Form form); -internal U128 dw_interp_const_u128(DW_Form form); -internal U64 dw_interp_const_u64 (DW_Form form); -internal U32 dw_interp_const_u32 (DW_Form form); -internal S64 dw_interp_const_s64 (DW_Form form); -internal S32 dw_interp_const_s32 (DW_Form form); -internal B32 dw_interp_flag (DW_Form form); -internal U64 dw_interp_address (U64 address_size, U64 base_addr, DW_ListUnit *addr_xlist, DW_Form form); -internal String8 dw_interp_block (DW_Raw *input, DW_CompUnit *cu, DW_Form form); -internal String8 dw_interp_string (DW_Raw *input, DW_Format unit_format, DW_ListUnit *str_offsets, DW_Form form); -internal String8 dw_interp_line_ptr (DW_Raw *input, DW_Form form); -internal DW_LineFile * dw_interp_file (DW_LineVM *line_vm, DW_Form form); -internal DW_Reference dw_interp_ref (DW_Raw *input, DW_CompUnit *cu, DW_Form form); -internal DW_LocList dw_interp_loclist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form); -internal Rng1U64List dw_interp_rnglist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form); +//////////////////////////////// +//~ rjf: Range List Parsing (.debug_rnglists) -internal String8 dw_exprloc_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal U128 dw_const_u128_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal U64 dw_const_u64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal U32 dw_const_u32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal S64 dw_const_s64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal S32 dw_const_s32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal B32 dw_flag_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal U64 dw_address_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal String8 dw_block_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal String8 dw_string_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal String8 dw_line_ptr_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal DW_LineFile * dw_file_from_attrib (DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib); -internal DW_Reference dw_ref_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); -internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal Rng1U64List dw2_rnglist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val); -internal String8 dw_exprloc_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal U128 dw_const_u128_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal U64 dw_const_u64_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal U32 dw_const_u32_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal B32 dw_flag_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal U64 dw_address_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal String8 dw_block_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal String8 dw_string_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal DW_LineFile * dw_file_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Tag tag, DW_AttribKind kind); -internal DW_Reference dw_ref_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal DW_LocList dw_loclist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -internal Rng1U64List dw_rnglist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +//////////////////////////////// +//~ rjf: Location List Parsing (.debug_loclists) -internal B32 dw_is_attrib_var_ref(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal DW2_LocList dw2_loclist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val); -// compile unit +//////////////////////////////// +//~ rjf: Unwind Info Parsing (.debug_frame) -internal DW_CompUnit dw_cu_from_info_off(Arena *arena, DW_Raw *input, DW_ListUnitInput lu_input, U64 offset, B32 relaxed); -internal DW_TagTree dw_tag_tree_from_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu); -internal HashTable * dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree); -internal DW_TagNode * dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off); - -// line VM - -internal U64 dw_read_line_vm_header(Arena *arena, DW_Raw *input, String8 cu_stmt_list, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets, DW_LineVMHeader *header_out); -internal DW_LineVM * dw_line_vm_init(DW_Raw *input, DW_CompUnit *cu); -internal void dw_line_vm_release(DW_LineVM *vm); -internal void dw_line_vm_advance(DW_LineVM *vm, U64 advance); -internal B32 dw_line_vm_step(DW_LineVM *vm); -internal DW_LineFile * dw_line_vm_find_file(DW_LineVM *vm, U64 file_idx); -internal String8 dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file); - -// helper for .debug_pubtypes and .debug_pubnames - -internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Raw *input, DW_SectionKind section_kind); - -// expression - -internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data); - -// debug frame - -internal void dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n); -internal DW_CFA_InstNode * dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v); - -internal U64 dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out); - -internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out); -internal B32 dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out); -internal B32 dw_parse_fde(String8 data, DW_Format format, DW_CIE *cie, DW_FDE *fde_out); -internal B32 dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out); - -internal DW_CFA_ParseErrorCode dw_parse_cfa_inst(String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud, U64 *bytes_read_out, DW_CFA_Inst *inst_out); -internal DW_CFA_InstList dw_parse_cfa_inst_list(Arena *arena, String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud); +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_H diff --git a/src/dwarf/dwarf_parse_2.c b/src/dwarf/dwarf_parse_2.c deleted file mode 100644 index 2bba4b22..00000000 --- a/src/dwarf/dwarf_parse_2.c +++ /dev/null @@ -1,1916 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Basic Parsing Helpers - -internal U64 -dw2_read_initial_length(String8 data, U64 off, U64 *out, DW_Format *fmt_out) -{ - DW_Format format = DW_Format_32Bit; - U64 size = 0; - U64 size_size = 0; - { - U32 size_or_header = 0; - size_size += str8_deserial_read_struct(data, off, &size_or_header); - if(size_or_header == max_U32) - { - size_size += str8_deserial_read_struct(data, off + size_size, &size); - format = DW_Format_64Bit; - } - else - { - size = (U64)size_or_header; - } - } - if(out) - { - out[0] = size; - } - if(fmt_out) - { - fmt_out[0] = format; - } - return size_size; -} - -internal U64 -dw2_read_fmt_u64(String8 data, U64 off, DW_Format format, U64 *out) -{ - U64 start_off = off; - switch(format) - { - default: - case DW_Format_32Bit: - { - U32 out_32 = 0; - off += str8_deserial_read_struct(data, off, &out_32); - out[0] = (U64)out_32; - }break; - case DW_Format_64Bit: - { - off += str8_deserial_read_struct(data, off, out); - }break; - } - U64 bytes_read = (off - start_off); - return bytes_read; -} - -internal DW_SectionKind -dw_section_kind_from_string(String8 string) -{ - DW_SectionKind s = DW_SectionKind_Null; - if(0){} -#define X(name, regular_string, macho_string, dwo_string) else if(str8_match(string, s(regular_string), 0) || str8_match(string, s(macho_string), 0) || str8_match(string, s(dwo_string), 0)) { s = DW_SectionKind_##name; } - DW_SectionKind_XList -#undef X - return s; -} - -//////////////////////////////// -//~ rjf: Unit Range Set Parsing (Top-Level .debug_info, .debug_aranges) - -internal Rng1U64Array -dw2_unit_ranges_from_data(Arena *arena, String8 data) -{ - Temp scratch = scratch_begin(&arena, 1); - Rng1U64List unit_range_list = {0}; - for(U64 off = 0; off < data.size;) - { - U64 start_off = off; - - // rjf: read next unit size - U64 unit_size = 0; - U64 unit_size_size = dw2_read_initial_length(data, off, &unit_size, 0); - - // rjf: push - if(unit_size > 0) - { - rng1u64_list_push(scratch.arena, &unit_range_list, r1u64(off, off + unit_size_size + unit_size)); - } - - // rjf: advance - off += unit_size_size; - off += unit_size; - - // rjf: break if no movement - if(off == start_off) - { - break; - } - } - Rng1U64Array result = rng1u64_array_from_list(arena, &unit_range_list); - scratch_end(scratch); - return result; -} - -//////////////////////////////// -//~ rjf: Unit Header Parsing - -internal U64 -dw2_read_unit_header(String8 data, U64 off, DW2_UnitHeader *out) -{ - U64 start_off = off; - - // rjf: read unit's .debug_info range size / format - U64 unit_info_size = 0; - DW_Format format = DW_Format_32Bit; - off += dw2_read_initial_length(data, off, &unit_info_size, &format); - - // rjf: read dwarf version - DW_Version version = 0; - off += str8_deserial_read_struct(data, off, &version); - - // rjf: read header properties - U64 abbrev_off = max_U64; - U64 addr_size = 0; - DW_CompUnitKind kind = DW_CompUnitKind_Reserved; - U64 dwo_id = 0; - switch((DW_VersionEnum)version) - { - case DW_Version_Null: - case DW_Version_1: - {}break; - - // rjf: @dwarf2 - case DW_Version_2: - { - // rjf: read abbrev off - U32 abbrev_off_32 = 0; - off += str8_deserial_read_struct(data, off, &abbrev_off_32); - abbrev_off = (U64)abbrev_off_32; - - // rjf: read address size - U8 addr_size_8 = 0; - off += str8_deserial_read_struct(data, off, &addr_size_8); - addr_size = (U64)addr_size_8; - }break; - - // rjf: @dwarf3 @dwarf4 - case DW_Version_3: - case DW_Version_4: - { - // rjf: read abbrev off - off += dw2_read_fmt_u64(data, off, format, &abbrev_off); - - // rjf: read address size - U8 addr_size_8 = 0; - off += str8_deserial_read_struct(data, off, &addr_size_8); - addr_size = (U64)addr_size_8; - }break; - - // rjf: @dwarf5 - case DW_Version_5: - { - // rjf: read unit kind - U8 comp_unit_kind_8 = 0; - off += str8_deserial_read_struct(data, off, &comp_unit_kind_8); - kind = (DW_CompUnitKind)comp_unit_kind_8; - - // rjf: read address size - U8 addr_size_8 = 0; - off += str8_deserial_read_struct(data, off, &addr_size_8); - addr_size = (U64)addr_size_8; - - // rjf: read abbrev off - off += dw2_read_fmt_u64(data, off, format, &abbrev_off); - - // rjf: read DWO ID, if applicable - if(kind == DW_CompUnitKind_Skeleton || - kind == DW_CompUnitKind_SplitCompile || - kind == DW_CompUnitKind_SplitType) - { - off += str8_deserial_read_struct(data, off, &dwo_id); - } - }break; - } - - // rjf: fill - out->version = version; - out->format = format; - out->abbrev_off = abbrev_off; - out->addr_size = addr_size; - out->kind = kind; - out->dwo_id = dwo_id; - - // rjf: return # of bytes read - U64 bytes_read = (off - start_off); - return bytes_read; -} - -//////////////////////////////// -//~ rjf: Abbreviation Map Parsing - -internal U64 -dw2_read_abbrev(Arena *arena, String8 data, U64 off, DW2_AbbrevHeader *header_out, DW2_AbbrevAttribList *attribs_out) -{ - U64 start_off = off; - - // rjf: read tag abbrev - U64 id = 0; - U64 tag_kind = 0; - U8 has_children = 0; - { - off += str8_deserial_read_uleb128(data, off, &id); - if(id != 0) - { - off += str8_deserial_read_uleb128(data, off, &tag_kind); - off += str8_deserial_read_struct(data, off, &has_children); - } - } - - // rjf: read all tag attribute abbreviations - DW2_AbbrevAttribList attribs = {0}; - if(id != 0) - { - for(;;) - { - U64 attrib_start_off = off; - U64 attrib_kind = 0; - U64 attrib_form_kind = 0; - U64 implicit_const = 0; - off += str8_deserial_read_uleb128(data, off, &attrib_kind); - off += str8_deserial_read_uleb128(data, off, &attrib_form_kind); - if(attrib_form_kind == DW_FormKind_ImplicitConst) - { - off += str8_deserial_read_uleb128(data, off, &implicit_const); - } - if(attrib_kind != 0 && attribs_out != 0) - { - DW2_AbbrevAttribNode *n = push_array(arena, DW2_AbbrevAttribNode, 1); - SLLQueuePush(attribs.first, attribs.last, n); - attribs.count += 1; - n->v.attrib_kind = attrib_kind; - n->v.form_kind = attrib_form_kind; - n->v.implicit_const = implicit_const; - } - if(off == attrib_start_off || attrib_kind == 0) - { - break; - } - } - } - - // rjf: fill - if(header_out != 0) - { - header_out->id = id; - header_out->tag_kind = tag_kind; - header_out->has_children = has_children; - } - if(attribs_out != 0) - { - MemoryCopyStruct(attribs_out, &attribs); - } - - U64 bytes_read = (off-start_off); - return bytes_read; -} - -internal DW2_AbbrevMap -dw2_abbrev_map_from_data(Arena *arena, String8 data, U64 off) -{ - DW2_AbbrevMap map = {0}; - - // rjf: loop - first to determine the number of tag formats encoded - // by this abbrev table, second to actually build a hash table for - // mapping (id -> .debug_abbrev offset) - for(B32 build = 0; build <= 1; build += 1) - { - // rjf: parse whole abbrev table - U64 tag_count = 0; - for(U64 read_off = off;;) - { - U64 start_off = read_off; - - // rjf: read next abbrev - DW2_AbbrevHeader header = {0}; - read_off += dw2_read_abbrev(arena, data, read_off, &header, 0); - - // rjf: count tag - if(header.id != 0) - { - tag_count += 1; - } - - // rjf: if building (second loop) -> insert into map - if(build) - { - U64 hash = u64_hash_from_str8(str8_struct(&header.id)); - U64 slot_idx = hash%map.slots_count; - DW2_AbbrevMapNode *n = push_array(arena, DW2_AbbrevMapNode, 1); - SLLStackPush(map.slots[slot_idx], n); - n->id = header.id; - n->off = start_off; - } - - // rjf: no tag ID, or no movement? -> exit - if(read_off == start_off || header.id == 0) - { - break; - } - } - - // rjf: on first loop iteration, given the tag format count, construct the table - if(!build) - { - map.slots_count = Max(1, tag_count + tag_count/4); - map.slots = push_array(arena, DW2_AbbrevMapNode *, map.slots_count); - } - } - - return map; -} - -internal DW2_UnitAbbrevMapMap -dw2_unit_abbrev_map_map_from_data(Arena *arena, String8 data, DW2_UnitHeader *unit_headers, U64 unit_headers_count) -{ - DW2_UnitAbbrevMapMap result = {0}; - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: gather deduplicated .debug_abbrev offsets, representing beginnings - // of abbreviation tables. we want to do this because many units may refer - // to the same abbreviation table. - // - typedef struct AbbrevOffNode AbbrevOffNode; - struct AbbrevOffNode - { - AbbrevOffNode *order_next; - AbbrevOffNode *hash_next; - U64 off; - U64 idx; - }; - U64 abbrev_off_slots_count = unit_headers_count; - AbbrevOffNode **abbrev_off_slots = 0; - U64 abbrev_map_count = 0; - U64 *abbrev_map_off_from_idx_table = 0; - DW2_AbbrevMap *abbrev_map_from_idx_table = 0; - DW2_AbbrevMap **abbrev_map_from_unit_idx_table = 0; - ProfScope("gather deduplicated .debug_abbrev offsets") if(lane_idx() == 0) - { - AbbrevOffNode *abbrev_off_first = 0; - AbbrevOffNode *abbrev_off_last = 0; - abbrev_off_slots = push_array(scratch.arena, AbbrevOffNode *, abbrev_off_slots_count); - for EachIndex(unit_idx, unit_headers_count) - { - U64 abbrev_off = unit_headers[unit_idx].abbrev_off; - U64 hash = u64_hash_from_str8(str8_struct(&abbrev_off)); - U64 slot_idx = hash%abbrev_off_slots_count; - AbbrevOffNode *node = 0; - for(AbbrevOffNode *n = abbrev_off_slots[slot_idx]; n != 0; n = n->hash_next) - { - if(n->off == abbrev_off) - { - node = n; - break; - } - } - if(node == 0) - { - node = push_array(arena, AbbrevOffNode, 1); - SLLStackPush_N(abbrev_off_slots[slot_idx], node, hash_next); - SLLQueuePush_N(abbrev_off_first, abbrev_off_last, node, order_next); - node->off = abbrev_off; - node->idx = abbrev_map_count; - abbrev_map_count += 1; - } - } - abbrev_map_off_from_idx_table = push_array(scratch.arena, U64, abbrev_map_count); - abbrev_map_from_idx_table = push_array(arena, DW2_AbbrevMap, abbrev_map_count); - abbrev_map_from_unit_idx_table = push_array(arena, DW2_AbbrevMap *, unit_headers_count); - { - U64 abbrev_map_idx = 0; - for(AbbrevOffNode *n = abbrev_off_first; n != 0; n = n->order_next) - { - abbrev_map_off_from_idx_table[abbrev_map_idx] = n->off; - abbrev_map_idx += 1; - } - } - } - lane_sync_u64(&abbrev_off_slots, 0); - lane_sync_u64(&abbrev_map_count, 0); - lane_sync_u64(&abbrev_map_off_from_idx_table, 0); - lane_sync_u64(&abbrev_map_from_idx_table, 0); - lane_sync_u64(&abbrev_map_from_unit_idx_table, 0); - - //- rjf: build all unique abbreviation maps - ProfScope("build all unique abbreviation maps") - { - U64 abbrev_map_take_idx = 0; - U64 *abbrev_map_take_idx_ptr = &abbrev_map_take_idx; - lane_sync_u64(&abbrev_map_take_idx_ptr, 0); - for(;;) - { - U64 abbrev_map_idx = ins_atomic_u64_inc_eval(abbrev_map_take_idx_ptr) - 1; - if(abbrev_map_idx >= abbrev_map_count) - { - break; - } - abbrev_map_from_idx_table[abbrev_map_idx] = dw2_abbrev_map_from_data(arena, data, abbrev_map_off_from_idx_table[abbrev_map_idx]); - } - lane_sync(); - } - - //- rjf: build unit -> abbrev map table - ProfScope("build unit -> abbrev map table") - { - Rng1U64 range = lane_range(unit_headers_count); - for EachInRange(unit_idx, range) - { - U64 abbrev_off = unit_headers[unit_idx].abbrev_off; - U64 hash = u64_hash_from_str8(str8_struct(&abbrev_off)); - U64 slot_idx = hash%abbrev_off_slots_count; - U64 abbrev_map_idx = 0; - for(AbbrevOffNode *n = abbrev_off_slots[slot_idx]; n != 0; n = n->hash_next) - { - if(n->off == abbrev_off) - { - abbrev_map_idx = n->idx; - break; - } - } - abbrev_map_from_unit_idx_table[unit_idx] = &abbrev_map_from_idx_table[abbrev_map_idx]; - } - lane_sync(); - } - - //- rjf: fill result - result.map_count = abbrev_map_count; - result.map_from_idx_table = abbrev_map_from_idx_table; - result.map_from_unit_idx_table = abbrev_map_from_unit_idx_table; - - scratch_end(scratch); - return result; -} - -//////////////////////////////// -//~ rjf: Form Value Parsing - -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) -{ - U64 start_off = off; - DW2_FormVal val = {form_kind}; - { - //- rjf: read value bytes - U64 bytes_to_read = 0; - switch(form_kind) - { - //- rjf: no-ops - default: - case DW_FormKind_Indirect: - case DW_FormKind_Null: - {}break; - - //- rjf: 1-byte uint reads - case DW_FormKind_Ref1: - case DW_FormKind_Data1: - case DW_FormKind_Flag: - case DW_FormKind_Strx1: - case DW_FormKind_Addrx1: - bytes_to_read = 1; goto read_fixed_uint; - - //- rjf: 2-byte uint reads - case DW_FormKind_Ref2: - case DW_FormKind_Data2: - case DW_FormKind_Strx2: - case DW_FormKind_Addrx2: - bytes_to_read = 2; goto read_fixed_uint; - - //- rjf: 3-byte uint reads - case DW_FormKind_Strx3: - case DW_FormKind_Addrx3: - bytes_to_read = 3; goto read_fixed_uint; - - //- rjf: 4-byte uint reads - case DW_FormKind_Data4: - case DW_FormKind_Ref4: - case DW_FormKind_RefSup4: - case DW_FormKind_Strx4: - case DW_FormKind_Addrx4: - bytes_to_read = 4; goto read_fixed_uint; - - //- rjf: 8-byte uint reads - case DW_FormKind_Data8: - case DW_FormKind_Ref8: - case DW_FormKind_RefSig8: - case DW_FormKind_RefSup8: - bytes_to_read = 8; goto read_fixed_uint; - - //- rjf: 16-byte uint reads - case DW_FormKind_Data16: - bytes_to_read = 16; goto read_fixed_uint; - - //- rjf: address-sized reads - case DW_FormKind_Addr: - bytes_to_read = ctx->addr_size; goto read_fixed_uint; - - //- rjf: format-defined-size reads - case DW_FormKind_RefAddr: - case DW_FormKind_SecOffset: - case DW_FormKind_LineStrp: - case DW_FormKind_Strp: - case DW_FormKind_StrpSup: - bytes_to_read = dw_addr_size_from_format(ctx->format); goto read_fixed_uint; - - //- rjf: fixed-size uint reads - read_fixed_uint: - { - off += str8_deserial_read(data, off, &val.u128.u64[0], bytes_to_read, bytes_to_read); - }break; - - //- rjf: uleb128 reads - case DW_FormKind_UData: - case DW_FormKind_RefUData: - case DW_FormKind_Strx: - case DW_FormKind_Addrx: - case DW_FormKind_LocListx: - case DW_FormKind_RngListx: - { - off += str8_deserial_read_uleb128(data, off, &val.u128.u64[0]); - }break; - - //- rjf: sleb128 reads - case DW_FormKind_SData: - { - off += str8_deserial_read_sleb128(data, off, (S64 *)(&val.u128.u64[0])); - }break; - - //- rjf: fixed-size uint reads / skips - case DW_FormKind_Block1: bytes_to_read = 1; goto read_fixed_uint_and_skip; - case DW_FormKind_Block2: bytes_to_read = 2; goto read_fixed_uint_and_skip; - case DW_FormKind_Block4: bytes_to_read = 4; goto read_fixed_uint_and_skip; - read_fixed_uint_and_skip: - { - U64 size = 0; - U64 og_read_off = off; - off += str8_deserial_read(data, off, &size, bytes_to_read, bytes_to_read); - val.u128.u64[0] = size; - val.u128.u64[1] = og_read_off; - off += size; - }break; - - //- rjf: uleb128 read & skip - case DW_FormKind_Block: - { - U64 size = 0; - U64 og_read_off = off; - off += str8_deserial_read_uleb128(data, off, &size); - val.string = str8_substr(data, r1u64(off, off+size)); - off += size; - }break; - - //- rjf: strings - case DW_FormKind_String: - { - String8 string = {0}; - U64 og_read_off = off; - off += str8_deserial_read_cstr(data, off, &string); - val.string = string; - }break; - - //- rjf: implicit constants (no reading in .debug_info; value comes from .debug_abbrev) - case DW_FormKind_ImplicitConst: - { - val.u128.u64[0] = implicit_const; - }break; - - //- rjf: exprloc - case DW_FormKind_ExprLoc: - { - U64 size = 0; - U64 og_read_off = off; - U64 bytes_read = str8_deserial_read_uleb128(data, off, &size); - val.u128.u64[0] = og_read_off + bytes_read; - val.u128.u64[1] = size; - val.string = str8_substr(data, r1u64(og_read_off, og_read_off+size)); - off += size + bytes_read; - }break; - - //- rjf: flag present - case DW_FormKind_FlagPresent: - { - val.u128.u64[0] = 1; - }break; - } - - //- rjf: in some cases, resolve numeric values -> strings - { - switch(form_kind) - { - default:{}break; - case DW_FormKind_Strx1: - case DW_FormKind_Strx2: - case DW_FormKind_Strx3: - case DW_FormKind_Strx4: - case DW_FormKind_Strx: - if(ctx->str_offsets_table != 0) - { - U64 entry_idx = val.u128.u64[0]; - U64 string_data_off = 0; - if(dw2_try_offset_from_table_idx(ctx->str_offsets_table, entry_idx, &string_data_off)) - { - String8 string_section_data = raw->sec[DW_SectionKind_Str].data; - val.string = str8_cstring_capped(string_section_data.str + string_data_off, - string_section_data.str + string_section_data.size); - } - }break; - case DW_FormKind_LineStrp: - { - String8 string_section_data = raw->sec[DW_SectionKind_LineStr].data; - val.string = str8_cstring_capped(string_section_data.str + val.u128.u64[0], - string_section_data.str + string_section_data.size); - }break; - case DW_FormKind_Strp: - case DW_FormKind_StrpSup: - { - String8 string_section_data = raw->sec[DW_SectionKind_Str].data; - val.string = str8_cstring_capped(string_section_data.str + val.u128.u64[0], - string_section_data.str + string_section_data.size); - }break; - } - } - - //- rjf: in some cases, resolve base numeric values -> addresses - { - switch(form_kind) - { - default:{val.addr = val.u128.u64[0];}break; - case DW_FormKind_Addrx: - case DW_FormKind_Addrx1: - case DW_FormKind_Addrx2: - case DW_FormKind_Addrx3: - case DW_FormKind_Addrx4: - if(ctx->addr_table != 0) - { - U64 addr_idx = val.u128.u64[0]; - dw2_try_offset_from_table_idx(ctx->addr_table, addr_idx, &val.addr); - }break; - } - } - } - *out = val; - U64 bytes_read = (off - start_off); - return bytes_read; -} - -//////////////////////////////// -//~ rjf: Parse Context Construction - -internal void -dw2_parse_ctx_equip_unit_header(DW2_ParseCtx *ctx_out, DW2_UnitHeader *hdr, U64 unit_base_info_off) -{ - ctx_out->version = hdr->version; - ctx_out->format = hdr->format; - ctx_out->addr_size = hdr->addr_size; - ctx_out->unit_base_info_off = unit_base_info_off; -} - -internal void -dw2_parse_ctx_equip_unit_abbrev_map(DW2_ParseCtx *ctx_out, DW2_UnitAbbrevMapMap *map, U64 unit_idx) -{ - ctx_out->abbrev_map = map->map_from_unit_idx_table[unit_idx]; -} - -internal void -dw2_parse_ctx_equip_unit_root_tag(DW2_ParseCtx *ctx_out, DW2_Tag *tag, DW2_OffsetTableSet *offset_tables) -{ - // rjf: unpack attributes - DW2_Attrib *low_pc_attrib = &dw2_attrib_nil; - DW2_Attrib *lang_attrib = &dw2_attrib_nil; - DW2_Attrib *rnglists_base_off_attrib = &dw2_attrib_nil; - DW2_Attrib *str_offsets_base_off_attrib = &dw2_attrib_nil; - DW2_Attrib *addr_base_off_attrib = &dw2_attrib_nil; - DW2_Attrib *loclist_base_off_attrib = &dw2_attrib_nil; - DW2_Attrib *comp_dir_attrib = &dw2_attrib_nil; - for EachNode(n, DW2_AttribNode, tag->attribs.first) - { - switch(n->v.attrib_kind) - { - default:{}break; -#define Case(name, name_upper) case DW_AttribKind_##name_upper:{name##_attrib = &n->v;}break - Case(low_pc, LowPc); - Case(lang, Language); - Case(rnglists_base_off, RngListsBase); - Case(str_offsets_base_off, StrOffsetsBase); - Case(addr_base_off, AddrBase); - Case(loclist_base_off, LocListsBase); - Case(comp_dir, CompDir); -#undef Case - } - } - - // rjf: fill basics - ctx_out->unit_base_addr = low_pc_attrib->val.addr; - ctx_out->language = lang_attrib->val.u128.u64[0]; - ctx_out->unit_dir = comp_dir_attrib->val.string; - - // rjf: find offset tables - Rng1U64Array rnglists_tables_ranges_array = {offset_tables->rnglists_tables_ranges, offset_tables->rnglists_tables_count}; - Rng1U64Array str_offsets_tables_ranges_array = {offset_tables->str_offsets_tables_ranges, offset_tables->str_offsets_tables_count}; - Rng1U64Array addr_tables_ranges_array = {offset_tables->addr_tables_ranges, offset_tables->addr_tables_count}; - Rng1U64Array loclist_tables_ranges_array = {offset_tables->loclists_tables_ranges, offset_tables->loclists_tables_count}; - { - // rjf: find rnglists table - { - U64 rnglists_base_off = rnglists_base_off_attrib->val.u128.u64[0]; - U64 rnglists_table_num = rng1u64_array_num_from_value__binary_search(&rnglists_tables_ranges_array, rnglists_base_off); - if(0 < rnglists_table_num && rnglists_table_num <= rnglists_tables_ranges_array.count) - { - DW2_OffsetTable *table = &offset_tables->rnglists_tables[rnglists_table_num-1]; - ctx_out->rnglists_table = table; - } - } - - // rjf: find str offsets table - { - U64 str_offsets_base_off = str_offsets_base_off_attrib->val.u128.u64[0]; - U64 str_offsets_table_num = rng1u64_array_num_from_value__binary_search(&str_offsets_tables_ranges_array, str_offsets_base_off); - if(0 < str_offsets_table_num && str_offsets_table_num <= str_offsets_tables_ranges_array.count) - { - DW2_OffsetTable *table = &offset_tables->str_offsets_tables[str_offsets_table_num-1]; - ctx_out->str_offsets_table = table; - } - } - - // rjf: find addr table - { - U64 addr_base_off = addr_base_off_attrib->val.u128.u64[0]; - U64 addr_table_num = rng1u64_array_num_from_value__binary_search(&addr_tables_ranges_array, addr_base_off); - if(0 < addr_table_num && addr_table_num <= addr_tables_ranges_array.count) - { - DW2_OffsetTable *table = &offset_tables->addr_tables[addr_table_num-1]; - ctx_out->addr_table = table; - } - } - - // rjf: find loclists table - { - U64 loclist_base_off = loclist_base_off_attrib->val.u128.u64[0]; - U64 loclist_table_num = rng1u64_array_num_from_value__binary_search(&loclist_tables_ranges_array, loclist_base_off); - if(0 < loclist_table_num && loclist_table_num <= loclist_tables_ranges_array.count) - { - DW2_OffsetTable *table = &offset_tables->loclists_tables[loclist_table_num-1]; - ctx_out->loclists_table = table; - } - } - } -} - -//////////////////////////////// -//~ rjf: Tag Parsing - -internal U64 -dw2_read_tag(Arena *arena, DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_Tag *tag_out) -{ - U64 start_off = off; - - // rjf: read tag's abbrev ID - U64 abbrev_id = 0; - off += str8_deserial_read_uleb128(data, off, &abbrev_id); - - // rjf: map abbrev ID -> abbrev offset - U64 abbrev_off = 0; - { - DW2_AbbrevMap *abbrev_map = ctx->abbrev_map; - U64 hash = u64_hash_from_str8(str8_struct(&abbrev_id)); - U64 slot_idx = hash%abbrev_map->slots_count; - for EachNode(n, DW2_AbbrevMapNode, abbrev_map->slots[slot_idx]) - { - if(n->id == abbrev_id) - { - abbrev_off = n->off; - break; - } - } - } - - // rjf: read abbrev header - U64 tag_kind = 0; - U8 has_children = 0; - U64 attrib_abbrev_read_off = 0; - { - String8 abbrev_data = raw->sec[DW_SectionKind_Abbrev].data; - U64 abbrev_read_off = abbrev_off; - U64 id = 0; - abbrev_read_off += str8_deserial_read_uleb128(abbrev_data, abbrev_read_off, &id); - if(id != 0) - { - abbrev_read_off += str8_deserial_read_uleb128(abbrev_data, abbrev_read_off, &tag_kind); - abbrev_read_off += str8_deserial_read_struct(abbrev_data, abbrev_read_off, &has_children); - } - attrib_abbrev_read_off = abbrev_read_off; - } - - // rjf: walk abbrev / info in lock-step; read all tag attributes - DW2_AttribList attribs = {0}; - if(abbrev_id != 0) - { - String8 abbrev_data = raw->sec[DW_SectionKind_Abbrev].data; - U64 abbrev_read_off = attrib_abbrev_read_off; - for(;;) - { - U64 abbrev_start_read_off = abbrev_read_off; - - // rjf: read next attribute abbreviation from .debug_abbrev - U64 attrib_kind = 0; - U64 attrib_form_kind = 0; - U64 implicit_const = 0; - abbrev_read_off += str8_deserial_read_uleb128(abbrev_data, abbrev_read_off, &attrib_kind); - abbrev_read_off += str8_deserial_read_uleb128(abbrev_data, abbrev_read_off, &attrib_form_kind); - if(attrib_form_kind == DW_FormKind_ImplicitConst) - { - abbrev_read_off += str8_deserial_read_uleb128(abbrev_data, abbrev_read_off, &implicit_const); - } - - // rjf: indirect form -> form kind is encoded in .debug_info (because why not) - if(attrib_form_kind == DW_FormKind_Indirect) - { - off += str8_deserial_read_uleb128(data, off, &attrib_form_kind); - } - - // rjf: read attribute's value from .debug_info - DW2_FormVal val = {0}; - if(attrib_kind != 0) - { - off += dw2_read_form_val(raw, ctx, data, off, attrib_form_kind, implicit_const, &val); - } - - // rjf: push - if(attrib_kind != 0) - { - DW2_AttribNode *n = push_array(arena, DW2_AttribNode, 1); - SLLQueuePush(attribs.first, attribs.last, n); - attribs.count += 1; - n->v.attrib_kind = attrib_kind; - n->v.val = val; - } - - // rjf: no movement, or no attrib kind -> done - if(abbrev_read_off == abbrev_start_read_off || attrib_kind == 0) - { - break; - } - } - } - - // rjf: fill output - tag_out->kind = (DW_TagKind)tag_kind; - tag_out->has_children = !!has_children; - tag_out->attribs = attribs; - - // rjf: return # of bytes read - U64 bytes_read = (off - start_off); - return bytes_read; -} - -internal DW2_Attrib * -dw2_attrib_from_kind(DW2_Tag *tag, DW_AttribKind kind) -{ - DW2_Attrib *result = &dw2_attrib_nil; - for EachNode(n, DW2_AttribNode, tag->attribs.first) - { - if(n->v.attrib_kind == kind) - { - result = &n->v; - break; - } - } - return result; -} - -internal U64 -dw2_reference_info_off_from_form_val(DW2_ParseCtx *ctx, DW2_FormVal *v) -{ - U64 result = 0; - switch(v->kind) - { - default:{}break; - case DW_FormKind_Ref1: - case DW_FormKind_Ref2: - case DW_FormKind_Ref4: - case DW_FormKind_Ref8: - { - result = ctx->unit_base_info_off + v->u128.u64[0]; - }break; - // TODO(rjf): DW_FormKind_RefAddr, DW_FormKind_RefUData, DW_FormKind_RefSig8, DW_FormKind_RefSup8, etc. - } - return result; -} - -//////////////////////////////// -//~ rjf: Line Table Parsing - -internal U64 -dw2_read_line_table_header(Arena *arena, DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_LineTableHeader *out) -{ - Temp scratch = scratch_begin(&arena, 1); - U64 start_off = off; - - ////////////////////////////// - //- rjf: read unit length - // - U64 unit_length = 0; - DW_Format format = DW_Format_32Bit; - off += dw2_read_initial_length(data, off, &unit_length, &format); - U64 off_opl = off + unit_length; - - ////////////////////////////// - //- rjf: read version - // - DW_Version version = DW_Version_Null; - off += str8_deserial_read_struct(data, off, &version); - - ////////////////////////////// - //- rjf: read address / segment selector sizes - // - U8 addr_size = 0; - U8 segment_selector_size = 0; - switch(version) - { - // NOTE(rjf): pre-dwarf5: assume from context - default: - { - addr_size = ctx->addr_size; - }break; - - // NOTE(rjf): @dwarf5 read address / segment selector sizes explicitly - case DW_Version_5: - { - off += str8_deserial_read_struct(data, off, &addr_size); - off += str8_deserial_read_struct(data, off, &segment_selector_size); - }break; - } - - ////////////////////////////// - //- rjf: read all remaining flat header properties - // - U64 opl_header_length_off = 0; - U64 header_length = 0; - U8 min_inst_length = 0; - U8 max_ops_per_inst = 1; - U8 default_is_stmt = 0; - S8 line_base = 0; - U8 line_range = 0; - U8 opcode_base = 0; - { - off += dw2_read_fmt_u64(data, off, format, &header_length); - opl_header_length_off = off; - off += str8_deserial_read_struct(data, off, &min_inst_length); - off += str8_deserial_read_struct(data, off, &max_ops_per_inst); - off += str8_deserial_read_struct(data, off, &default_is_stmt); - off += str8_deserial_read_struct(data, off, &line_base); - off += str8_deserial_read_struct(data, off, &line_range); - off += str8_deserial_read_struct(data, off, &opcode_base); - } - - ////////////////////////////// - //- rjf: read opcode lengths - // - U64 opcode_lengths_count = (opcode_base > 0 ? opcode_base - 1 : 0); - U8 *opcode_lengths = 0; - if(opcode_lengths_count > 0) - { - opcode_lengths = str8_skip(data, off).str; - off += sizeof(opcode_lengths[0]) * opcode_lengths_count; - } - - ////////////////////////////// - //- rjf: read directory / file tables - // - DW2_LineTableFileArray dirs = {0}; - DW2_LineTableFileArray files = {0}; - switch(version) - { - //////////////////////////// - //- rjf: pre-dwarf5: simple(r) well-defined format... still ulebs everywhere but oh well... - // just wait until the next case... - // - default: - { - //- rjf: gather directories - DW2_LineTableFileList dir_list = {0}; - { - // rjf: push compile directory as first list element, always - { - DW2_LineTableFileNode *n = push_array(scratch.arena, DW2_LineTableFileNode, 1); - SLLQueuePush(dir_list.first, dir_list.last, n); - dir_list.count += 1; - n->v.file_name = ctx->unit_dir; - } - - // rjf: gather additional directories - for(;off < off_opl;) - { - String8 dir = {0}; - off += str8_deserial_read_cstr(data, off, &dir); - if(dir.size != 0) - { - DW2_LineTableFileNode *n = push_array(scratch.arena, DW2_LineTableFileNode, 1); - SLLQueuePush(dir_list.first, dir_list.last, n); - dir_list.count += 1; - n->v.file_name = dir; - } - else - { - break; - } - } - } - - //- rjf: gather files - DW2_LineTableFileList file_list = {0}; - { - // rjf: push main compilation unit file as first list element, always - { - DW2_LineTableFileNode *n = push_array(scratch.arena, DW2_LineTableFileNode, 1); - SLLQueuePush(file_list.first, file_list.last, n); - file_list.count += 1; - n->v.file_name = ctx->unit_file; - } - - // rjf: gather additional files - for(;off < off_opl;) - { - U8 next_byte = 0; - str8_deserial_read_struct(data, off, &next_byte); - if(next_byte == 0) - { - break; - } - String8 file_name = {0}; - U64 dir_idx = 0; - U64 modify_time = 0; - U64 file_size = 0; - off += str8_deserial_read_cstr(data, off, &file_name); - off += str8_deserial_read_uleb128(data, off, &dir_idx); - off += str8_deserial_read_uleb128(data, off, &modify_time); - off += str8_deserial_read_uleb128(data, off, &file_size); - if(file_name.size != 0) - { - DW2_LineTableFileNode *n = push_array(scratch.arena, DW2_LineTableFileNode, 1); - SLLQueuePush(file_list.first, file_list.last, n); - file_list.count += 1; - n->v.file_name = file_name; - n->v.dir_idx = dir_idx; - n->v.modify_time = modify_time; - n->v.file_size = file_size; - } - } - } - - //- rjf: flatten - { - dirs.count = dir_list.count; - dirs.v = push_array(arena, DW2_LineTableFile, dirs.count); - files.count = file_list.count; - files.v = push_array(arena, DW2_LineTableFile, files.count); - { - U64 idx = 0; - for EachNode(n, DW2_LineTableFileNode, dir_list.first) - { - MemoryCopyStruct(&dirs.v[idx], &n->v); - idx += 1; - } - } - { - U64 idx = 0; - for EachNode(n, DW2_LineTableFileNode, file_list.first) - { - MemoryCopyStruct(&files.v[idx], &n->v); - idx += 1; - } - } - } - }break; - - //////////////////////////// - //- rjf: @dwarf5: another VM! d'oh. :( - // - case DW_Version_5: - { - //- rjf: read directory & file tables - for(B32 do_files = 0, do_dirs = 1; do_files <= 1; do_files += 1, do_dirs = 0) - { - // rjf: read header - U8 entry_formats_count = 0; - off += str8_deserial_read_struct(data, off, &entry_formats_count); - U64 *entry_formats = push_array(scratch.arena, U64, entry_formats_count*2); - for EachIndex(idx, entry_formats_count) - { - off += str8_deserial_read_uleb128(data, off, &entry_formats[idx*2 + 0]); - off += str8_deserial_read_uleb128(data, off, &entry_formats[idx*2 + 1]); - } - U64 table_count = 0; - off += str8_deserial_read_uleb128(data, off, &table_count); - - // rjf: read all table entries - DW2_LineTableFileArray table = {0}; - table.count = table_count; - table.v = push_array(arena, DW2_LineTableFile, table.count); - { - U64 idx = 0; - for(;off < off_opl && idx < table.count; idx += 1) - { - DW2_LineTableFile *entry_out = &table.v[idx]; - for(U64 entry_format_idx = 0; entry_format_idx < entry_formats_count; entry_format_idx += 1) - { - DW_LNCT lnct = (DW_LNCT)entry_formats[entry_format_idx*2 + 0]; - DW_FormKind form_kind = (DW_FormKind)entry_formats[entry_format_idx*2 + 1]; - DW2_FormVal form_val = {0}; - off += dw2_read_form_val(raw, ctx, data, off, form_kind, 0, &form_val); - switch(lnct) - { - default: - { - log_infof("DWARF LNCT encoding not currently supported (0x%I64x).\n", (U64)lnct); - }break; - case DW_LNCT_Path: - { - entry_out->file_name = form_val.string; - }break; - case DW_LNCT_DirectoryIndex: - { - entry_out->dir_idx = form_val.u128.u64[0]; - }break; - case DW_LNCT_TimeStamp: - { - entry_out->modify_time = form_val.u128.u64[0]; - entry_out->flags |= DW2_LineTableFileFlag_HasModifyTime; - }break; - case DW_LNCT_Size: - { - entry_out->file_size = form_val.u128.u64[0]; - }break; - case DW_LNCT_MD5: - { - entry_out->md5.u128 = form_val.u128; - entry_out->flags |= DW2_LineTableFileFlag_HasMD5; - }break; - case DW_LNCT_LLVM_Source: - { - entry_out->source = form_val.string; - }break; - } - } - } - } - - // rjf: store - if(0){} - else if(do_files) { files = table; } - else if(do_dirs) { dirs = table; } - } - - }break; - } - - ////////////////////////////// - //- rjf: fill output - // - if(out) - { - out->unit_length = unit_length; - out->format = format; - out->version = version; - out->addr_size = addr_size; - out->segment_selector_size = segment_selector_size; - out->header_length = header_length; - out->min_inst_length = min_inst_length; - out->max_ops_per_inst = max_ops_per_inst; - out->default_is_stmt = default_is_stmt; - out->line_base = line_base; - out->line_range = line_range; - out->opcode_base = opcode_base; - out->opcode_lengths_count = opcode_lengths_count; - out->opcode_lengths = opcode_lengths; - out->dirs = dirs; - out->files = files; - out->line_program_off = opl_header_length_off + header_length; - out->total_unit_data_size = (off_opl - start_off); - } - - U64 bytes_read = (off - start_off); - scratch_end(scratch); - return bytes_read; -} - -//////////////////////////////// -//~ rjf: String Offset Table Parsing (.debug_str_offsets) - -internal U64 -dw2_read_offset_table(String8 data, U64 off, DW2_OffsetTable *out) -{ - U64 start_off = off; - { - // rjf: read data length / format - U64 unit_data_length = 0; - DW_Format format = DW_Format_Null; - off += dw2_read_initial_length(data, off, &unit_data_length, &format); - U64 unit_data_off_opl = off + unit_data_length; - - // rjf: read version - DW_Version version = DW_Version_Null; - off += str8_deserial_read_struct(data, off, &version); - - // rjf: version 5: read rest (this section only exists in 5+) - if(version == DW_Version_5) - { - // rjf: read address / segment selector size (these need to be 0 in non-address offset tables) - U8 addr_size = 0; - U8 segment_selector_size = 0; - off += str8_deserial_read_struct(data, off, &addr_size); - off += str8_deserial_read_struct(data, off, &segment_selector_size); - - // rjf: determine entry size - U64 entry_size = dw_addr_size_from_format(format); - if(addr_size != 0) - { - entry_size = addr_size + segment_selector_size; - } - - // rjf: fill table info - out->format = format; - out->version = version; - out->addr_size = addr_size; - out->segment_selector_size = segment_selector_size; - out->entry_size = entry_size; - out->entries_count = (unit_data_off_opl - off) / out->entry_size; - out->entries = data.str + off; - - // rjf: skip table - off = unit_data_off_opl; - } - } - U64 bytes_read = (off - start_off); - return bytes_read; -} - -internal DW2_OffsetTableList -dw2_offset_table_list_from_data(Arena *arena, String8 data) -{ - DW2_OffsetTableList list = {0}; - for(U64 off = 0; off < data.size;) - { - U64 start_off = off; - DW2_OffsetTable table = {0}; - off += dw2_read_offset_table(data, off, &table); - if(table.entries != 0) - { - DW2_OffsetTableNode *n = push_array(arena, DW2_OffsetTableNode, 1); - SLLQueuePush(list.first, list.last, n); - n->v = table; - n->range = r1u64(start_off, off); - list.count += 1; - } - if(off == start_off) - { - break; - } - } - return list; -} - -internal B32 -dw2_try_offset_from_table_idx(DW2_OffsetTable *tbl, U64 idx, U64 *out) -{ - B32 result = 0; - if(idx < tbl->entries_count) - { - U64 entry_size = tbl->entry_size; - U64 entry_off = idx * entry_size; - if(tbl->addr_size != 0) - { - U64 segment_off = entry_off; - U64 addr_off = entry_off + tbl->segment_selector_size; - U64 segment = 0; - U64 addr = 0; - MemoryCopy(&segment, (U8 *)tbl->entries + segment_off, tbl->segment_selector_size); - MemoryCopy(&addr, (U8 *)tbl->entries + addr_off, tbl->addr_size); - // TODO(rjf): @segment_based_addressing - *out = addr; - } - else - { - MemoryCopy(out, (U8 *)tbl->entries + entry_off, entry_size); - } - result = 1; - } - return result; -} - -internal DW2_OffsetTableSet -dw2_offset_table_set_from_raw(Arena *arena, DW_Raw *raw) -{ - DW2_OffsetTableSet result = {0}; - { - struct - { - String8 data; - U64 *tables_count_out; - DW2_OffsetTable **tables_out; - Rng1U64 **tables_ranges_out; - } - tasks[] = - { - {raw->sec[DW_SectionKind_StrOffsets].data, &result.str_offsets_tables_count, &result.str_offsets_tables, &result.str_offsets_tables_ranges}, - {raw->sec[DW_SectionKind_RngLists].data, &result.rnglists_tables_count, &result.rnglists_tables, &result.rnglists_tables_ranges}, - {raw->sec[DW_SectionKind_Addr].data, &result.addr_tables_count, &result.addr_tables, &result.addr_tables_ranges}, - {raw->sec[DW_SectionKind_LocLists].data, &result.loclists_tables_count, &result.loclists_tables, &result.loclists_tables_ranges}, - }; - for EachElement(task_idx, tasks) - { - Temp scratch = scratch_begin(&arena, 1); - String8 data = tasks[task_idx].data; - DW2_OffsetTableList tables = dw2_offset_table_list_from_data(scratch.arena, data); - tasks[task_idx].tables_count_out[0] = tables.count; - tasks[task_idx].tables_out[0] = push_array(arena, DW2_OffsetTable, tables.count); - tasks[task_idx].tables_ranges_out[0] = push_array(arena, Rng1U64, tables.count); - { - U64 idx = 0; - for EachNode(n, DW2_OffsetTableNode, tables.first) - { - tasks[task_idx].tables_out[0][idx] = n->v; - tasks[task_idx].tables_ranges_out[0][idx] = n->range; - idx += 1; - } - } - scratch_end(scratch); - } - } - return result; -} - -//////////////////////////////// -//~ rjf: Range List Parsing (.debug_rnglists) - -internal Rng1U64List -dw2_rnglist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val) -{ - Rng1U64List result = {0}; - switch((DW_VersionEnum)ctx->version) - { - case DW_Version_Null:{}break; - - //- rjf: pre-dwarf5 - case DW_Version_1: - case DW_Version_2: - case DW_Version_3: - case DW_Version_4: - { - String8 data = raw->sec[DW_SectionKind_Ranges].data; - U64 ranges_off = ranges_off = form_val.u128.u64[0];; - U64 base_addr = ctx->unit_base_addr; - U64 sentinel = (ctx->addr_size == 4 ? max_U32 : max_U64); - for(U64 off = ranges_off; off < data.size;) - { - U64 start_off = off; - U64 range_min = 0; - U64 range_opl = 0; - off += str8_deserial_read(data, off, &range_min, ctx->addr_size, ctx->addr_size); - off += str8_deserial_read(data, off, &range_opl, ctx->addr_size, ctx->addr_size); - // - // NOTE(rjf): interpreting tuples: - // [0, 0) -> ending range list - // [max_U32/U64, depending on addr size, X) -> set new base address to X - // [N, M) -> new [base + N, base + M) range - // - if(range_min == 0 && range_opl == 0) - { - break; - } - else if(range_min == sentinel) - { - base_addr = range_opl; - } - else if(off == start_off) - { - break; - } - else - { - rng1u64_list_push(arena, &result, r1u64(base_addr + range_min, base_addr + range_opl)); - } - if(off == start_off) - { - break; - } - } - }break; - - //- rjf: @dwarf5 - case DW_Version_5: - { - String8 data = raw->sec[DW_SectionKind_RngLists].data; - - // rjf: determine section offset - sometimes this is encoded directly, - // other times it is relative, based on the form kind - more variability - // in this awful format - U64 rnglist_off = 0; - switch(form_val.kind) - { - default:{}break; - case DW_FormKind_SecOffset: - { - rnglist_off = form_val.u128.u64[0]; - }break; - case DW_FormKind_RngListx: - if(ctx->rnglists_table != 0) - { - U64 rnglist_off_idx = form_val.u128.u64[0]; - dw2_try_offset_from_table_idx(ctx->rnglists_table, rnglist_off_idx, &rnglist_off); - }break; - } - - // rjf: in a HIGHLY UNEXPECTED TURN OF EVENTS, we now have to decode ANOTHER - // OPCODE STREAM to unpack the actual list of ranges!!! - U64 rle_sentinel = (ctx->addr_size == 4 ? max_U32 : max_U64); - U64 base_addr = ctx->unit_base_addr; - for(U64 off = rnglist_off; off < data.size;) - { - U64 start_off = off; - - // rjf: decode op kind - DW_RLE rle_kind = DW_RLE_EndOfList; - off += str8_deserial_read_struct(data, off, &rle_kind); - - // rjf: obtain range from op - B32 good_range = 1; - Rng1U64 range = {0}; - switch(rle_kind) - { - default:{good_range = 0;}break; - case DW_RLE_BaseAddressx: - { - good_range = 0; - U64 addr_idx = 0; - off += str8_deserial_read_uleb128(data, off, &addr_idx); - if(ctx->addr_table != 0) - { - U64 new_base_addr = 0; - if(dw2_try_offset_from_table_idx(ctx->addr_table, addr_idx, &new_base_addr)) - { - good_range = 1; - base_addr = new_base_addr; - } - } - }break; - case DW_RLE_StartxEndx: - { - good_range = 0; - U64 start_idx = 0; - U64 end_idx = 0; - off += str8_deserial_read_uleb128(data, off, &start_idx); - off += str8_deserial_read_uleb128(data, off, &end_idx); - if(ctx->addr_table != 0) - { - U64 start = 0; - U64 end = 0; - if(dw2_try_offset_from_table_idx(ctx->addr_table, start_idx, &start) && - dw2_try_offset_from_table_idx(ctx->addr_table, end_idx, &end)) - { - good_range = 1; - range = r1u64(start, end); - } - } - }break; - case DW_RLE_StartxLength: - { - good_range = 0; - U64 start_idx = 0; - U64 length = 0; - off += str8_deserial_read_uleb128(data, off, &start_idx); - off += str8_deserial_read_uleb128(data, off, &length); - if(ctx->addr_table != 0) - { - U64 start = 0; - if(dw2_try_offset_from_table_idx(ctx->addr_table, start_idx, &start)) - { - good_range = 1; - range = r1u64(start, start+length); - } - } - }break; - case DW_RLE_OffsetPair: - { - U64 range_off_start = 0; - U64 range_off_end = 0; - off += str8_deserial_read_uleb128(data, off, &range_off_start); - off += str8_deserial_read_uleb128(data, off, &range_off_end); - range = r1u64(base_addr + range_off_start, base_addr + range_off_end); - }break; - case DW_RLE_BaseAddress: - { - U64 new_base_addr = 0; - off += str8_deserial_read(data, off, &new_base_addr, ctx->addr_size, ctx->addr_size); - base_addr = new_base_addr; - }break; - case DW_RLE_StartEnd: - { - U64 start = 0; - U64 end = 0; - off += str8_deserial_read(data, off, &start, ctx->addr_size, ctx->addr_size); - off += str8_deserial_read(data, off, &end, ctx->addr_size, ctx->addr_size); - range = r1u64(start, end); - }break; - case DW_RLE_StartLength: - { - U64 start = 0; - U64 length = 0; - off += str8_deserial_read(data, off, &start, ctx->addr_size, ctx->addr_size); - off += str8_deserial_read_uleb128(data, off, &length); - range = r1u64(start, start + length); - }break; - } - - // rjf: add range - if(good_range) - { - rng1u64_list_push(arena, &result, range); - } - - // rjf: end if no movement or end-of-list code - if(off == start_off || rle_kind == DW_RLE_EndOfList) - { - break; - } - } - }break; - } - return result; -} - -//////////////////////////////// -//~ rjf: Location List Parsing (.debug_loclists) - -internal DW2_LocList -dw2_loclist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val) -{ - DW2_LocList result = {0}; - switch((DW_VersionEnum)ctx->version) - { - case DW_Version_Null:{}break; - - //- rjf: pre-dwarf5 - case DW_Version_1: - case DW_Version_2: - case DW_Version_3: - case DW_Version_4: - { - String8 data = raw->sec[DW_SectionKind_Loc].data; - U64 locs_off = locs_off = form_val.u128.u64[0]; - U64 base_addr = ctx->unit_base_addr; - U64 sentinel = (ctx->addr_size == 4 ? max_U32 : max_U64); - for(U64 off = locs_off; off < data.size;) - { - U64 start_off = off; - U64 range_min = 0; - U64 range_opl = 0; - off += str8_deserial_read(data, off, &range_min, ctx->addr_size, ctx->addr_size); - off += str8_deserial_read(data, off, &range_opl, ctx->addr_size, ctx->addr_size); - // - // NOTE(rjf): interpreting tuples: - // [0, 0) -> ending range list - // [max_U32/U64, depending on addr size, X) -> set new base address to X - // [N, M) -> new [base + N, base + M) range - // - if(range_min == 0 && range_opl == 0) - { - break; - } - else if(range_min == sentinel) - { - base_addr = range_opl; - } - else if(off == start_off) - { - break; - } - else - { - U16 expr_size = 0; - off += str8_deserial_read_struct(data, off, &expr_size); - DW2_LocNode *n = push_array(arena, DW2_LocNode, 1); - n->v.range = r1u64(range_min + base_addr, range_opl + base_addr); - n->v.expr = str8_substr(data, r1u64(off, off+expr_size)); - SLLQueuePush(result.first, result.last, n); - result.count += 1; - off += expr_size; - } - if(off == start_off) - { - break; - } - } - }break; - - //- rjf: @dwarf5 - case DW_Version_5: - { - String8 data = raw->sec[DW_SectionKind_LocLists].data; - - // rjf: determine section offset - sometimes this is encoded directly, - // other times it is relative, based on the form kind - more variability - // in this awful format - U64 loclist_off = 0; - switch(form_val.kind) - { - default:{}break; - case DW_FormKind_SecOffset: - { - loclist_off = form_val.u128.u64[0]; - }break; - case DW_FormKind_LocListx: - if(ctx->rnglists_table != 0) - { - U64 loclist_off_idx = form_val.u128.u64[0]; - dw2_try_offset_from_table_idx(ctx->loclists_table, loclist_off_idx, &loclist_off); - }break; - } - - // rjf: in a HIGHLY UNEXPECTED TURN OF EVENTS, we now have to decode ANOTHER - // OPCODE STREAM to unpack the actual list of locations!!! - U64 rle_sentinel = (ctx->addr_size == 4 ? max_U32 : max_U64); - U64 base_addr = ctx->unit_base_addr; - for(U64 off = loclist_off; off < data.size;) - { - U64 start_off = off; - - // rjf: decode op kind - DW_LLE lle_kind = DW_LLE_EndOfList; - off += str8_deserial_read_struct(data, off, &lle_kind); - - // rjf: obtain range from op - B32 good_loc = 1; - Rng1U64 range = {0}; - switch(lle_kind) - { - default:{good_loc = 0;}break; - case DW_LLE_BaseAddressx: - { - good_loc = 0; - U64 addr_idx = 0; - off += str8_deserial_read_uleb128(data, off, &addr_idx); - if(ctx->addr_table != 0) - { - U64 new_base_addr = 0; - if(dw2_try_offset_from_table_idx(ctx->addr_table, addr_idx, &new_base_addr)) - { - good_loc = 1; - base_addr = new_base_addr; - } - } - }break; - case DW_LLE_StartxEndx: - { - good_loc = 0; - U64 start_idx = 0; - U64 end_idx = 0; - off += str8_deserial_read_uleb128(data, off, &start_idx); - off += str8_deserial_read_uleb128(data, off, &end_idx); - if(ctx->addr_table != 0) - { - U64 start = 0; - U64 end = 0; - if(dw2_try_offset_from_table_idx(ctx->addr_table, start_idx, &start) && - dw2_try_offset_from_table_idx(ctx->addr_table, end_idx, &end)) - { - good_loc = 1; - range = r1u64(start, end); - } - } - }break; - case DW_LLE_StartxLength: - { - good_loc = 0; - U64 start_idx = 0; - U64 length = 0; - off += str8_deserial_read_uleb128(data, off, &start_idx); - off += str8_deserial_read_uleb128(data, off, &length); - if(ctx->addr_table != 0) - { - U64 start = 0; - if(dw2_try_offset_from_table_idx(ctx->addr_table, start_idx, &start)) - { - good_loc = 1; - range = r1u64(start, start+length); - } - } - }break; - case DW_LLE_OffsetPair: - { - U64 range_off_start = 0; - U64 range_off_end = 0; - off += str8_deserial_read_uleb128(data, off, &range_off_start); - off += str8_deserial_read_uleb128(data, off, &range_off_end); - range = r1u64(base_addr + range_off_start, base_addr + range_off_end); - }break; - case DW_LLE_DefaultLocation: - { - range = r1u64(0, max_U64); - }break; - case DW_LLE_BaseAddress: - { - U64 new_base_addr = 0; - off += str8_deserial_read(data, off, &new_base_addr, ctx->addr_size, ctx->addr_size); - base_addr = new_base_addr; - }break; - case DW_LLE_StartEnd: - { - U64 start = 0; - U64 end = 0; - off += str8_deserial_read(data, off, &start, ctx->addr_size, ctx->addr_size); - off += str8_deserial_read(data, off, &end, ctx->addr_size, ctx->addr_size); - range = r1u64(start, end); - }break; - case DW_LLE_StartLength: - { - U64 start = 0; - U64 length = 0; - off += str8_deserial_read(data, off, &start, ctx->addr_size, ctx->addr_size); - off += str8_deserial_read_uleb128(data, off, &length); - range = r1u64(start, start + length); - }break; - } - - // rjf: read expression - String8 expr = {0}; - if(good_loc && lle_kind != DW_LLE_BaseAddress && lle_kind != DW_LLE_BaseAddressx) - { - U64 expr_size = 0; - off += str8_deserial_read_uleb128(data, off, &expr_size); - expr = str8_substr(data, r1u64(off, off+expr_size)); - off += expr_size; - } - - // rjf: add range - if(good_loc) - { - DW2_LocNode *n = push_array(arena, DW2_LocNode, 1); - n->v.range = range; - n->v.expr = expr; - SLLQueuePush(result.first, result.last, n); - result.count += 1; - } - - // rjf: end if no movement or end-of-list code - if(off == start_off || lle_kind == DW_LLE_EndOfList) - { - break; - } - } - }break; - } - return result; -} - -//////////////////////////////// -//~ rjf: Unwind Info Parsing (.debug_frame) - -internal U64 -dw2_read_cfi_header(String8 data, U64 off, DW_CFIHeader *cfi_header_out) -{ - U64 start_off = off; - - // rjf: read length / format - U64 length = 0; - DW_Format fmt = DW_Format_Null; - U64 length_size = dw2_read_initial_length(data, off, &length, &fmt); - - // rjf: find entry info, read ID - Rng1U64 entry_range = r1u64(off, off + length_size + length); - String8 entry_data = str8_substr(data, entry_range); - U64 id = 0; - U64 id_size = dw2_read_fmt_u64(entry_data, length_size, fmt, &id); - - // rjf: fill - cfi_header_out->kind = ((fmt == DW_Format_32Bit && id == max_U32) || (fmt == DW_Format_64Bit && id == max_U64)) ? DW_CFIKind_CIE : DW_CFIKind_FDE; - cfi_header_out->fmt = fmt; - cfi_header_out->entry_range = entry_range; - cfi_header_out->cie_pointer = id; - cfi_header_out->cie_pointer_off = off + length_size; - - U64 bytes_read = (off - start_off); - return bytes_read; -} - -internal U64 -dw2_read_cie(String8 data, U64 off, DW_Format fmt, Arch arch, DW_CIE *cie_out) -{ - U64 start_off = off; - - // rjf: read id - U64 id = 0; - off += dw2_read_fmt_u64(data, off, fmt, &id); - - // rjf: read version - U8 version = 0; - off += str8_deserial_read_struct(data, off, &version); - - // rjf: read aug string - String8 aug_string = {0}; - U64 aug_string_off = off; - off += str8_deserial_read_cstr(data, off, &aug_string); - U64 aug_string_off_opl = off; - - // rjf: read address/segment-selector size - U8 address_size = 0; - U8 segment_selector_size = 0; - if(version >= DW_Version_4) - { - off += str8_deserial_read_struct(data, off, &address_size); - off += str8_deserial_read_struct(data, off, &segment_selector_size); - } - else - { - address_size = byte_size_from_arch(arch); - } - - // rjf: read alignments - U64 code_align_factor = 0; - U64 data_align_factor = 0; - off += str8_deserial_read_uleb128(data, off, &code_align_factor); - off += str8_deserial_read_uleb128(data, off, &data_align_factor); - - // rjf: read return address register encoding - U64 ret_addr_reg = 0; - switch(version) - { - case DW_Version_1: - { - off += str8_deserial_read(data, off, &ret_addr_reg, 1, 1); - }break; - default: - { - off += str8_deserial_read_uleb128(data, off, &ret_addr_reg); - }break; - } - - // rjf: fill output - { - cie_out->aug_string_range = r1u64(aug_string_off, aug_string_off_opl); - 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 = fmt; - cie_out->version = version; - cie_out->address_size = address_size; - cie_out->segment_selector_size = segment_selector_size; - } - - U64 bytes_read = (off - start_off); - return bytes_read; -} - -internal U64 -dw2_read_fde(String8 data, U64 off, DW_Format fmt, Arch arch, DW_CIE *cie, DW_FDE *fde_out) -{ - U64 start_off = off; - - // rjf: skip format-dependent prefix - off += (fmt == DW_Format_32Bit) ? 4 : 12; - - // rjf: read cie ptr - U64 cie_ptr = 0; - off += dw2_read_fmt_u64(data, off, fmt, &cie_ptr); - - // rjf: read address of first instruction - U64 pc_begin = 0; - off += str8_deserial_read(data, off, &pc_begin, cie->address_size, cie->address_size); - - // rjf: read instruction range size - U64 pc_range_size = 0; - off += str8_deserial_read(data, off, &pc_range_size, cie->address_size, cie->address_size); - - // rjf: skip aug data - off += dim_1u64(cie->aug_string_range); - - // rjf: fill output - fde_out->cie_pointer = cie_ptr; - fde_out->pc_range = r1u64(pc_begin, pc_begin + pc_range_size); - - U64 bytes_read = (off - start_off); - return bytes_read; -} - -internal B32 -dw2_try_cfi_from_data(String8 data, U64 off, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out) -{ - B32 result = 0; - { - DW_CFIHeader fde_header = {0}; - off += dw2_read_cfi_header(data, off, &fde_header); - if(fde_header.kind == DW_CFIKind_FDE) - { - DW_CFIHeader cie_header = {0}; - dw2_read_cfi_header(data, fde_header.cie_pointer, &cie_header); - if(cie_header.kind == DW_CFIKind_CIE) - { - result = 1; - dw2_read_cie(data, cie_header.entry_range.min, cie_header.fmt, arch, cie_out); - dw2_read_fde(data, fde_header.entry_range.min, fde_header.fmt, arch, cie_out, fde_out); - } - } - } - return result; -} diff --git a/src/dwarf/dwarf_parse_2.h b/src/dwarf/dwarf_parse_2.h deleted file mode 100644 index a4d5606c..00000000 --- a/src/dwarf/dwarf_parse_2.h +++ /dev/null @@ -1,456 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#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 - -typedef struct DW2_UnitHeader DW2_UnitHeader; -struct DW2_UnitHeader -{ - DW_Version version; - DW_Format format; - U64 abbrev_off; - U64 addr_size; - DW_CompUnitKind kind; - U64 dwo_id; -}; - -//////////////////////////////// -//~ 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 -{ - DW2_AbbrevMapNode *next; - U64 id; - U64 off; -}; - -typedef struct DW2_AbbrevMap DW2_AbbrevMap; -struct DW2_AbbrevMap -{ - DW2_AbbrevMapNode **slots; - 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) - -typedef struct DW2_OffsetTable DW2_OffsetTable; -struct DW2_OffsetTable -{ - DW_Format format; - DW_Version version; - U8 addr_size; - U8 segment_selector_size; - U64 entry_size; - U64 entries_count; - 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_Version version; - DW_Format format; - DW_ExtFlags exts; - U64 addr_size; - U64 unit_base_addr; - U64 unit_base_info_off; - DW2_AbbrevMap *abbrev_map; - DW2_OffsetTable *rnglists_table; - DW2_OffsetTable *str_offsets_table; - DW2_OffsetTable *addr_table; - DW2_OffsetTable *loclists_table; - String8 unit_dir; - String8 unit_file; - DW_Language language; -}; - -//////////////////////////////// -//~ rjf: Tag Attributes - -typedef struct DW2_FormVal DW2_FormVal; -struct DW2_FormVal -{ - DW_FormKind kind; - U128 u128; - String8 string; - U64 addr; -}; - -typedef struct DW2_Attrib DW2_Attrib; -struct DW2_Attrib -{ - DW_AttribKind attrib_kind; - DW2_FormVal val; -}; - -typedef struct DW2_AttribNode DW2_AttribNode; -struct DW2_AttribNode -{ - DW2_AttribNode *next; - DW2_Attrib v; -}; - -typedef struct DW2_AttribList DW2_AttribList; -struct DW2_AttribList -{ - DW2_AttribNode *first; - DW2_AttribNode *last; - U64 count; -}; - -//////////////////////////////// -//~ rjf: Tags - -typedef struct DW2_Tag DW2_Tag; -struct DW2_Tag -{ - DW_TagKind kind; - B32 has_children; - DW2_AttribList attribs; -}; - -//////////////////////////////// -//~ rjf: Line Info - -typedef U32 DW2_LineTableFileFlags; -enum -{ - DW2_LineTableFileFlag_HasMD5 = (1<<0), - DW2_LineTableFileFlag_HasModifyTime = (1<<1), -}; - -typedef struct DW2_LineTableFile DW2_LineTableFile; -struct DW2_LineTableFile -{ - String8 file_name; - DW2_LineTableFileFlags flags; - U64 dir_idx; - U64 modify_time; - U64 file_size; - MD5 md5; - String8 source; -}; - -typedef struct DW2_LineTableFileNode DW2_LineTableFileNode; -struct DW2_LineTableFileNode -{ - DW2_LineTableFileNode *next; - DW2_LineTableFile v; -}; - -typedef struct DW2_LineTableFileList DW2_LineTableFileList; -struct DW2_LineTableFileList -{ - DW2_LineTableFileNode *first; - DW2_LineTableFileNode *last; - U64 count; -}; - -typedef struct DW2_LineTableFileArray DW2_LineTableFileArray; -struct DW2_LineTableFileArray -{ - DW2_LineTableFile *v; - U64 count; -}; - -typedef struct DW2_LineTableHeader DW2_LineTableHeader; -struct DW2_LineTableHeader -{ - U64 unit_length; - DW_Format format; - DW_Version version; - U8 addr_size; - U8 segment_selector_size; - U64 header_length; - U8 min_inst_length; - U8 max_ops_per_inst; - U8 default_is_stmt; - S8 line_base; - U8 line_range; - U8 opcode_base; - U64 opcode_lengths_count; - U8 *opcode_lengths; - DW2_LineTableFileArray dirs; - DW2_LineTableFileArray files; - U64 line_program_off; - U64 total_unit_data_size; // NOTE(rjf): would be implied by `unit_length`, but DWARF makes that the size *past* the variable-width unit-length field itself -}; - -typedef struct DW2_LineVMRegs DW2_LineVMRegs; -struct DW2_LineVMRegs -{ - U64 address; - U64 vliw_op_index; - U64 file_index; - U64 line; - U64 column; - B32 is_stmt; - B32 basic_block; - B32 end_sequence; - B32 prologue_end; - B32 epilogue_begin; - U64 isa; - U64 discriminator; -}; - -//////////////////////////////// -//~ rjf: Location Lists - -typedef struct DW2_Loc DW2_Loc; -struct DW2_Loc -{ - Rng1U64 range; - String8 expr; -}; - -typedef struct DW2_LocNode DW2_LocNode; -struct DW2_LocNode -{ - DW2_LocNode *next; - DW2_Loc v; -}; - -typedef struct DW2_LocList DW2_LocList; -struct DW2_LocList -{ - DW2_LocNode *first; - DW2_LocNode *last; - 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 - -global read_only DW2_Attrib dw2_attrib_nil = {0}; - -//////////////////////////////// -//~ rjf: Basic Parsing Helpers - -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) - -internal Rng1U64Array dw2_unit_ranges_from_data(Arena *arena, String8 data); - -//////////////////////////////// -//~ rjf: Unit Header Parsing - -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(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, 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, 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) - -internal Rng1U64List dw2_rnglist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val); - -//////////////////////////////// -//~ rjf: Location List Parsing (.debug_loclists) - -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 diff --git a/src/dwarf/dwarf_parse_coff.h b/src/dwarf/dwarf_parse_coff.h index 3df0b5be..9523f053 100644 --- a/src/dwarf/dwarf_parse_coff.h +++ b/src/dwarf/dwarf_parse_coff.h @@ -8,4 +8,3 @@ internal B32 dw_is_dwarf_present_coff_section_table(String8 string_table, U64 se 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_PARSE_COFF_H - diff --git a/src/dwarf/dwarf_unwind.c b/src/dwarf/dwarf_unwind.c index c8124236..ae447aab 100644 --- a/src/dwarf/dwarf_unwind.c +++ b/src/dwarf/dwarf_unwind.c @@ -1,373 +1,2 @@ // Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) - -internal DW_CFI_Row * -dw_make_cfi_row(Arena *arena, U64 reg_count) -{ - DW_CFI_Row *row = push_array(arena, DW_CFI_Row, 1); - row->regs = push_array(arena, DW_CFI_Register, reg_count); - for EachIndex(reg_idx, reg_count) { - row->regs[reg_idx].rule = DW_CFI_RegisterRule_SameValue; - } - return row; -} - -internal void -dw_memcpy_cfi_row(DW_CFI_Row *dst, DW_CFI_Row *src, U64 reg_count) -{ - dst->cfa = src->cfa; - MemoryCopyTyped(dst->regs, src->regs, reg_count); -} - -internal DW_CFI_Row * -dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count) -{ - DW_CFI_Row *new_row = dw_make_cfi_row(arena, reg_count); - dw_memcpy_cfi_row(new_row, row, reg_count); - return new_row; -} - -internal DW_CFI_Unwind * -dw_cfi_unwind_init(Arena *arena, - Arch arch, - DW_CIE *cie, - DW_FDE *fde, - DW_DecodePtr *decode_ptr_func, - void *decode_ptr_ud) -{ - Temp scratch = scratch_begin(&arena, 1); - - DW_CFI_Unwind *uw = push_array(arena, DW_CFI_Unwind, 1); - uw->insts = dw_parse_cfa_inst_list(arena, fde->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud); - uw->cie = cie; - uw->fde = fde; - uw->pc = fde->pc_range.min; - uw->arch = arch; - uw->reg_count = dw_reg_count_from_arch(arch); - - // setup initial register rules - DW_CFA_InstList initial_insts = dw_parse_cfa_inst_list(scratch.arena, cie->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud); - uw->row = dw_make_cfi_row(arena, uw->reg_count); - uw->curr_inst = initial_insts.first; - if (!dw_cfi_next_row(arena, uw)) { - AssertAlways(0 && "unable to interpret initial row instructions"); - } - - // make first row from initial rules - uw->initial_row = uw->row; - uw->row = dw_copy_cfi_row(arena, uw->initial_row, uw->reg_count); - uw->curr_inst = uw->insts.first; - - scratch_end(scratch); - return uw; -} - -internal B32 -dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw) -{ - B32 is_row_valid = 0; - DW_CFA_InstNode *row_inst = uw->curr_inst; - - // skip leading nops - while (uw->curr_inst) { - if (uw->curr_inst->v.opcode != DW_CFA_Nop) { - break; - } - uw->curr_inst = uw->curr_inst->next; - } - - while (uw->curr_inst) { - DW_CFA_Inst *inst = &uw->curr_inst->v; - - // validate register operands - DW_CFA_OperandType *operand_types = dw_operand_types_from_cfa_op(inst->opcode); - U64 operand_count = dw_operand_count_from_cfa_opcode(inst->opcode); - for EachIndex(operand_idx, operand_count) { - if (operand_types[operand_idx] == DW_CFA_OperandType_Register) { - if (inst->operands[operand_idx].u64 >= uw->reg_count) { - goto exit; - } - } - } - - switch (inst->opcode) { - // Row Creation Instructions - case DW_CFA_SetLoc: { - uw->pc = inst->operands[0].u64; - } break; - case DW_CFA_AdvanceLoc: - case DW_CFA_AdvanceLoc1: - case DW_CFA_AdvanceLoc2: - case DW_CFA_AdvanceLoc4: { - uw->pc += inst->operands[0].u64; - } break; - - // CFA Definition Instructions - case DW_CFA_DefCfa: - case DW_CFA_DefCfaSf: { - U64 reg = inst->operands[0].u64; - S64 off = inst->operands[1].s64; - uw->row->cfa.rule = DW_CFA_Rule_RegOff; - uw->row->cfa.reg = reg; - uw->row->cfa.off = off; - } break; - case DW_CFA_DefCfaRegister: { - // TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset - if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; } - U64 reg = inst->operands[0].u64; - uw->row->cfa.reg = reg; - } break; - case DW_CFA_DefCfaOffset: - case DW_CFA_DefCfaOffsetSf: { - // TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset - if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; } - uw->row->cfa.off = inst->operands[0].s64; - } break; - case DW_CFA_DefCfaExpr: { - uw->row->cfa.rule = DW_CFA_Rule_Expression; - uw->row->cfa.expr = inst->operands[0].block; - } break; - - // Register Rule Instructions - case DW_CFA_Undefined: { - U64 reg = inst->operands[0].u64; - uw->row->regs[reg].rule = DW_CFI_RegisterRule_Undefined; - } break; - case DW_CFA_SameValue: { - U64 reg = inst->operands[0].u64; - uw->row->regs[reg].rule = DW_CFI_RegisterRule_SameValue; - } break; - case DW_CFA_Offset: - case DW_CFA_OffsetExt: - case DW_CFA_OffsetExtSf: { - U64 reg = inst->operands[0].u64; - uw->row->regs[reg].rule = DW_CFI_RegisterRule_Offset; - uw->row->regs[reg].n = inst->operands[1].s64; - } break; - case DW_CFA_ValOffset: - case DW_CFA_ValOffsetSf: { - U64 reg = inst->operands[0].u64; - uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValOffset; - uw->row->regs[reg].n = inst->operands[1].s64; - } break; - case DW_CFA_Register: { - U64 reg = inst->operands[0].u64; - uw->row->regs[reg].rule = DW_CFI_RegisterRule_Register; - uw->row->regs[reg].n = inst->operands[1].s64; - } break; - case DW_CFA_Expr: { - U64 reg = inst->operands[0].u64; - uw->row->regs[reg].rule = DW_CFI_RegisterRule_Expression; - uw->row->regs[reg].expr = inst->operands[1].block; - } break; - case DW_CFA_ValExpr: { - U64 reg = inst->operands[0].u64; - uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValExpression; - uw->row->regs[reg].expr = inst->operands[1].block; - } break; - case DW_CFA_Restore: - case DW_CFA_RestoreExt: { - U64 reg = inst->operands[0].u64; - uw->row->regs[reg] = uw->initial_row->regs[reg]; - } break; - - // Row State Instructions - case DW_CFA_RememberState: { - DW_CFI_Row *new_row = dw_copy_cfi_row(arena, uw->row, uw->reg_count); - SLLStackPush(uw->row, new_row); - } break; - case DW_CFA_RestoreState: { - if (uw->row == 0) { goto exit; } // TODO: report error: unbalanced number of pushes and pops - DW_CFI_Row *free_row = uw->row; - SLLStackPop(uw->row); - SLLStackPush(uw->free_rows, free_row); - } break; - - case DW_CFA_Nop: {} break; - - default: { NotImplemented; } break; // TODO: report error: unknown CFA opcode - } - - uw->curr_inst = uw->curr_inst->next; - if (uw->curr_inst) { - if (dw_is_new_row_cfa_opcode(uw->curr_inst->v.opcode)) { break; } - } - } - - is_row_valid = row_inst != 0; - exit:; - return is_row_valid; -} - -internal DW_CFI_Row * -dw_cfi_row_from_pc(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc) -{ - Temp scratch = scratch_begin(&arena, 1); - - B32 is_row_found = 0; - U64 reg_count = dw_reg_count_from_arch(arch); - DW_CFI_Unwind *uw = dw_cfi_unwind_init(scratch.arena, arch, cie, fde, decode_ptr_func, decode_ptr_ctx); - DW_CFI_Row *row = dw_copy_cfi_row(scratch.arena, uw->row, uw->reg_count); - U64 prev_pc = uw->pc; - while (dw_cfi_next_row(scratch.arena, uw)) { - if (prev_pc <= pc && pc < uw->pc) { - is_row_found = 1; - break; - } - dw_memcpy_cfi_row(row, uw->row, uw->reg_count); - prev_pc = uw->pc; - } - - // handle last row - if (!is_row_found) { - if (contains_1u64(fde->pc_range, pc)) { - row = uw->row; - is_row_found = 1; - } - } - - // copy out final row - DW_CFI_Row *result = 0; - if (is_row_found) { - result = dw_copy_cfi_row(arena, row, reg_count); - } - - scratch_end(scratch); - return result; -} - -internal MachineOpResult -dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out) -{ - MachineOpResult unwind_status = MachineOpResult_Fail; - ARCH_Info *arch_info = arch_info_from_arch(arch); - switch(row->cfa.rule) - { - case DW_CFA_Rule_Null:{}break; - case DW_CFA_Rule_RegOff: - { - // TODO: report error (invalid register read) - U64 cfa_reg_value = 0; - U64 reg_size = dw_reg_size_from_code(arch, row->cfa.reg); - AssertAlways(reg_size <= sizeof(cfa_reg_value)); - ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, row->cfa.reg); - Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code]; - if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, &cfa_reg_value)) - { - break; - } - *cfa_out = cfa_reg_value + row->cfa.off; - unwind_status = MachineOpResult_Ok; - }break; - case DW_CFA_Rule_Expression: - { - Temp scratch = scratch_begin(0,0); - DW_ExprValue value = {0}; - DW_Expr expr = dw_expr_from_data(scratch.arena, DW_Format_32Bit, byte_size_from_arch(arch), row->cfa.expr); - DW_ExprEvalResult eval_result = dw_eval_expr(scratch.arena, arch, DW_Format_32Bit, 0, 0, 0, 9999, expr, reg_block, mem_read_func, mem_read_ud, &value); - if (eval_result == DW_ExprEvalResult_Ok) { - if (DW_ExprValueType_IsInt(value.type)) { - *cfa_out = value.u64; - unwind_status = MachineOpResult_Ok; - } - } else if (eval_result == DW_ExprEvalResult_Maybe) { - unwind_status = MachineOpResult_Maybe; - } - scratch_end(scratch); - }break; - } - return unwind_status; -} - -internal MachineOpResult -dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud) -{ - Temp scratch = scratch_begin(0,0); - MachineOpResult unwind_status = MachineOpResult_Ok; - - ARCH_Info *arch_info = arch_info_from_arch(arch); - - U64 max_reg_size = dw_reg_max_size_from_arch(arch); - void *reg_buffer = push_array(scratch.arena, U8, max_reg_size); - - U64 reg_count = dw_reg_count_from_arch(arch); - for EachIndex(reg_idx, reg_count) - { - DW_CFI_Register *reg = &row->regs[reg_idx]; - ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_idx); - Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code]; - switch(reg->rule) - { - default:{}break; - case DW_CFI_RegisterRule_Undefined: {} break; - case DW_CFI_RegisterRule_SameValue: {} break; - case DW_CFI_RegisterRule_Offset: - { - // read register value from memory - U64 addr = cfa + reg->n; - U64 reg_size = dw_reg_size_from_code(arch, reg_idx); - unwind_status = mem_read_func(addr, reg_buffer, reg_size, mem_read_ud); - if (unwind_status != MachineOpResult_Ok) { goto exit; } - - // write register value to the thread context - if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer)) - { - unwind_status = MachineOpResult_Fail; - goto exit; - } - }break; - case DW_CFI_RegisterRule_ValOffset: - { - // compute register value - U64 reg_value = cfa + reg->n; - - // write register value to the thread context - U64 reg_size = dw_reg_size_from_code(arch, reg_idx); - if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, ®_value)) - { - unwind_status = MachineOpResult_Fail; - goto exit; - } - }break; - case DW_CFI_RegisterRule_Register: - { - // read register value from another register - U64 reg_size = dw_reg_size_from_code(arch, reg_idx); - if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, reg_buffer)) - { - unwind_status = MachineOpResult_Fail; - goto exit; - } - - // write register value to the thread context - if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer)) - { - unwind_status = MachineOpResult_Fail; - goto exit; - } - if (unwind_status != MachineOpResult_Ok) { goto exit; } - }break; - case DW_CFI_RegisterRule_Expression: - { - // TODO: evaluate expression - NotImplemented; - }break; - case DW_CFI_RegisterRule_ValExpression: - { - // TODO: evaluate expression - NotImplemented; - }break; - case DW_CFI_RegisterRule_Architectural: - { - NotImplemented; - }break; - } - } - - // update stack pointer - arch_reg_block_write_sp(arch_info, reg_block, cfa); - - exit:; - scratch_end(scratch); - return unwind_status; -} diff --git a/src/dwarf/dwarf_unwind.h b/src/dwarf/dwarf_unwind.h index 63e5ba3f..d278d9f6 100644 --- a/src/dwarf/dwarf_unwind.h +++ b/src/dwarf/dwarf_unwind.h @@ -4,78 +4,41 @@ #ifndef DWARF_UNWIND_H #define DWARF_UNWIND_H -typedef enum DW_CFI_RegisterRule +typedef enum DW_UnwindRuleCode { - DW_CFI_RegisterRule_Undefined, - DW_CFI_RegisterRule_SameValue, - DW_CFI_RegisterRule_Offset, - DW_CFI_RegisterRule_ValOffset, - DW_CFI_RegisterRule_Register, - DW_CFI_RegisterRule_Expression, - DW_CFI_RegisterRule_ValExpression, - DW_CFI_RegisterRule_Architectural -} DW_CFI_RegisterRule; + 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 enum DW_CFA_Rule +typedef struct DW_UnwindRule DW_UnwindRule; +struct DW_UnwindRule { - DW_CFA_Rule_Null, - DW_CFA_Rule_RegOff, - DW_CFA_Rule_Expression -} DW_CFA_Rule; + DW_UnwindRuleCode code; + DW_RegCode reg_code; + S64 s64; + String8 expr; +}; -typedef struct DW_CFA +typedef struct DW_CFIRow DW_CFIRow; +struct DW_CFIRow { - DW_CFA_Rule rule; - union { - struct { - DW_Reg reg; - S64 off; - }; - String8 expr; - }; -} DW_CFA; + U64 base_pc_off; + DW_UnwindRule cfa_rule; + DW_UnwindRule *reg_rules; +}; -typedef struct DW_CFI_Register +typedef struct DW_CFIRowNode DW_CFIRowNode; +struct DW_CFIRowNode { - DW_CFI_RegisterRule rule; - union { - S64 n; - String8 expr; - }; -} DW_CFI_Register; - -typedef struct DW_CFI_Row -{ - DW_CFA cfa; - DW_CFI_Register *regs; - struct DW_CFI_Row *next; -} DW_CFI_Row; - -typedef struct DW_CFI_Unwind -{ - DW_CFA_InstList insts; - DW_CIE *cie; - DW_FDE *fde; - DW_CFI_Row *initial_row; - DW_CFI_Row *row; - DW_CFA_InstNode *curr_inst; - DW_CFI_Row *free_rows; - U64 pc; - Arch arch; - U64 reg_count; -} DW_CFI_Unwind; - -//////////////////////////////// - -internal DW_CFI_Row * dw_make_cfi_row(Arena *arena, U64 reg_count); -internal DW_CFI_Row * dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count); - -internal DW_CFI_Unwind * dw_cfi_unwind_init(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud); -internal B32 dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw); - -internal DW_CFI_Row * dw_cfi_row_from_pc(Arena *arena, Arch arch, struct DW_CIE *cie, struct DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc); -internal MachineOpResult dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out); -internal MachineOpResult dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud); + DW_CFIRowNode *next; + DW_CFIRow v; +}; #endif // DWARF_UNWIND_H - diff --git a/src/dwarf/dwarf_unwind_2.c b/src/dwarf/dwarf_unwind_2.c deleted file mode 100644 index ae447aab..00000000 --- a/src/dwarf/dwarf_unwind_2.c +++ /dev/null @@ -1,2 +0,0 @@ -// Copyright (c) Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) diff --git a/src/dwarf/dwarf_unwind_2.h b/src/dwarf/dwarf_unwind_2.h deleted file mode 100644 index ca1bea9a..00000000 --- a/src/dwarf/dwarf_unwind_2.h +++ /dev/null @@ -1,44 +0,0 @@ -// 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