added CFA instruction parser, interpreter, and a dumper

This commit is contained in:
Nikita Smith
2025-10-10 10:09:46 -07:00
parent c738768e41
commit 061b5c5955
10 changed files with 1198 additions and 1376 deletions
+94 -5
View File
@@ -69,6 +69,31 @@ dw_reg_pos_from_code(Arch arch, DW_Reg reg_code)
return max_U64;
}
internal U64
dw_reg_count_from_arch(Arch arch)
{
switch (arch) {
default: { NotImplemented; } // fall-through
case Arch_Null: return 0;
case Arch_x86: return DW_RegX86_Last;
case Arch_x64: return DW_RegX64_Last;
}
}
internal U64
dw_reg_max_size_from_arch(Arch arch)
{
local_persist U64 max_size = 0;
if (max_size == 0) {
U64 max_idx = dw_reg_count_from_arch(arch);
for EachIndex(reg_idx, max_idx) {
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
max_size = Max(max_size, reg_size);
}
}
return max_size;
}
internal DW_AttribClass
dw_attrib_class_from_attrib_v2(DW_AttribKind k)
{
@@ -431,6 +456,71 @@ dw_push_count_from_expr_op(DW_ExprOp op)
return 0;
}
internal U64
dw_operand_count_from_cfa_opcode(DW_CFA_Opcode opcode)
{
switch (opcode) {
#define X(_N, _ID, ...) case _ID: { local_persist DW_CFA_OperandType t[] = { DW_CFA_OperandType_Null, __VA_ARGS__ }; return ArrayCount(t)-1; }
DW_CFA_Kind_XList(X)
#undef X
default: { NotImplemented; } break;
}
return 0;
}
internal B32
dw_is_cfa_expr_opcode_invalid(DW_ExprOp opcode)
{
B32 is_invalid = 0;
switch (opcode) {
case DW_ExprOp_Addrx:
case DW_ExprOp_Call2:
case DW_ExprOp_Call4:
case DW_ExprOp_CallRef:
case DW_ExprOp_ConstType:
case DW_ExprOp_Constx:
case DW_ExprOp_Convert:
case DW_ExprOp_DerefType:
case DW_ExprOp_RegvalType:
case DW_ExprOp_Reinterpret:
case DW_ExprOp_PushObjectAddress:
case DW_ExprOp_CallFrameCfa: {
is_invalid = 1;
} break;
default: break;
}
return is_invalid;
}
internal B32
dw_is_new_row_cfa_opcode(DW_CFA_Opcode opcode)
{
B32 is_new_row_op = 0;
switch (opcode) {
case DW_CFA_SetLoc:
case DW_CFA_AdvanceLoc:
case DW_CFA_AdvanceLoc1:
case DW_CFA_AdvanceLoc2:
case DW_CFA_AdvanceLoc4: {
is_new_row_op = 1;
} break;
default: break;
}
return is_new_row_op;
}
internal DW_CFA_OperandType *
dw_operand_types_from_cfa_op(DW_CFA_Opcode opcode)
{
switch (opcode) {
#define X(_N, _ID, ...) case _ID: { local_persist DW_CFA_OperandType t[] = { DW_CFA_OperandType_Null, __VA_ARGS__ }; return &t[0] + 1; }
DW_CFA_Kind_XList(X)
#undef X
default: { NotImplemented; } break;
}
return 0;
}
////////////////////////////////
//~ rjf: String <=> Enum
@@ -717,12 +807,11 @@ dw_string_from_register(Arena *arena, Arch arch, U64 reg_id)
}
internal String8
dw_string_from_cfa_opcode(DW_CFA cfa_opcode)
dw_string_from_cfa_opcode(DW_CFA_Opcode opcode)
{
switch (cfa_opcode) {
#define X(_NAME, _ID) case _ID: return str8_lit(Stringify(_NAME));
DW_CFA_Kind1_XList(X)
DW_CFA_Kind2_XList(X)
switch (opcode) {
#define X(_NAME, _ID, ...) case _ID: return str8_lit(Stringify(_NAME));
DW_CFA_Kind_XList(X)
#undef X
default: InvalidPath; break;
}
+66 -51
View File
@@ -1337,56 +1337,57 @@ typedef enum DW_LNCTEnum
DW_LNCT_UserHi = 0x3fff
} DW_LNCTEnum;
#define DW_CFA_Kind1_XList(X) \
X(Nop, 0x0) \
X(SetLoc, 0x1) \
X(AdvanceLoc1, 0x2) \
X(AdvanceLoc2, 0x3) \
X(AdvanceLoc4, 0x4) \
X(OffsetExt, 0x5) \
X(RestoreExt, 0x6) \
X(Undefined, 0x7) \
X(SameValue, 0x8) \
X(Register, 0x9) \
X(RememberState, 0xA) \
X(RestoreState, 0xB) \
X(DefCfa, 0xC) \
X(DefCfaRegister, 0xD) \
X(DefCfaOffset, 0xE) \
X(DefCfaExpr, 0xF) \
X(Expr, 0x10) \
X(OffsetExtSf, 0x11) \
X(DefCfaSf, 0x12) \
X(DefCfaOffsetSf, 0x13) \
X(ValOffset, 0x14) \
X(ValOffsetSf, 0x15) \
X(ValExpr, 0x16)
////////////////////////////////
// CFA
#define DW_CFA_Kind2_XList(X) \
X(AdvanceLoc, 0x40) \
X(Offset, 0x80) \
X(Restore, 0xC0)
typedef U8 DW_CFA;
typedef enum DW_CFAEnum
typedef enum
{
#define X(_N, _ID) DW_CFA_##_N = _ID,
DW_CFA_Kind1_XList(X)
DW_CFA_Kind2_XList(X)
DW_CFA_OperandType_Null,
DW_CFA_OperandType_Value,
DW_CFA_OperandType_Register,
DW_CFA_OperandType_Expression,
} DW_CFA_OperandType;
// (opcode name, opcode id, operand count, operand types)
#define DW_CFA_Kind_XList(X) \
X(Nop, 0x0) \
X(SetLoc, 0x1, DW_CFA_OperandType_Value) \
X(AdvanceLoc1, 0x2, DW_CFA_OperandType_Value) \
X(AdvanceLoc2, 0x3, DW_CFA_OperandType_Value) \
X(AdvanceLoc4, 0x4, DW_CFA_OperandType_Value) \
X(OffsetExt, 0x5, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
X(RestoreExt, 0x6) \
X(Undefined, 0x7, DW_CFA_OperandType_Register) \
X(SameValue, 0x8, DW_CFA_OperandType_Register) \
X(Register, 0x9, DW_CFA_OperandType_Register) \
X(RememberState, 0xa) \
X(RestoreState, 0xb) \
X(DefCfa, 0xc, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
X(DefCfaRegister, 0xd, DW_CFA_OperandType_Register) \
X(DefCfaOffset, 0xe, DW_CFA_OperandType_Value) \
X(DefCfaExpr, 0xf, DW_CFA_OperandType_Expression) \
X(Expr, 0x10, DW_CFA_OperandType_Expression) \
X(OffsetExtSf, 0x11, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
X(DefCfaSf, 0x12, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
X(DefCfaOffsetSf, 0x13, DW_CFA_OperandType_Value) \
X(ValOffset, 0x14, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
X(ValOffsetSf, 0x15, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
X(ValExpr, 0x16, DW_CFA_OperandType_Register, DW_CFA_OperandType_Expression) \
X(AdvanceLoc, 0x40, DW_CFA_OperandType_Value) \
X(Offset, 0x80, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
X(Restore, 0xc0, DW_CFA_OperandType_Register)
#define DW_CFA_OperandMax 2
#define DW_CFA_Mask_OpcodeHi 0xc0
#define DW_CFA_Mask_Operand 0x3f
typedef U8 DW_CFA_Opcode;
typedef enum DW_CFA_Enum
{
#define X(_N, _ID, ...) DW_CFA_##_N = _ID,
DW_CFA_Kind_XList(X)
#undef X
DW_CFA_OplKind1 = DW_CFA_ValExpr,
DW_CFA_OplKind2 = DW_CFA_Restore,
} DW_CFAEnum;
typedef U8 DW_CFAMask;
enum
{
// kind1: opcode: [0,5] zeroes:[6,7]; kind2: operand:[0,5] opcode:[6,7]
DW_CFAMask_OpcodeHi = 0xC0,
DW_CFAMask_Operand = 0x3F,
DW_CFAMask_Count = 2
};
} DW_CFA_Enum;
////////////////////////////////
// Expression Opcodes
@@ -1561,7 +1562,7 @@ X(RegvalType, 0xa5, 2, 0, 1) \
X(DerefType, 0xa6, 2, 1, 1) \
X(XDerefType, 0xa7, 2, 2, 1) \
X(Convert, 0xa8, 1, 1, 1) \
X(ReInterpret, 0xa9, 1, 1, 1)
X(Reinterpret, 0xa9, 1, 1, 1)
#define DW_Expr_GNU_XList(X) \
X(GNU_PushTlsAddress, 0xe0, 0, 0, 1) \
@@ -1589,7 +1590,7 @@ typedef enum DW_ExprOpEnum
//- Regs
#define DW_Regs_X86_XList(X) \
#define DW_Regs_X86_XList(X) \
X(Eax, 0, eax, 0, 4) \
X(Ecx, 1, ecx, 0, 4) \
X(Edx, 2, edx, 0, 4) \
@@ -1637,7 +1638,7 @@ X(Gs, 45, gs, 0, 2) \
X(Tr, 48, nil, 0, 0) \
X(Ldtr, 49, nil, 0, 0)
#define DW_Regs_X64_XList(X) \
#define DW_Regs_X64_XList(X) \
X(Rax, 0, rax, 0, 8) \
X(Rdx, 1, rdx, 0, 8) \
X(Rcx, 2, rcx, 0, 8) \
@@ -1723,6 +1724,7 @@ typedef enum DW_RegX86Enum
#define X(_N,_ID,...) DW_RegX86_##_N = _ID,
DW_Regs_X86_XList(X)
#undef X
DW_RegX86_Last
} DW_RegX86Enum;
typedef DW_Reg DW_RegX64;
@@ -1731,6 +1733,7 @@ typedef enum DW_RegX64Enum
#define X(_N,_ID,...) DW_RegX64_##_N = _ID,
DW_Regs_X64_XList(X)
#undef X
DW_RegX64_Last
} DW_RegX64Enum;
////////////////////////////////
@@ -1741,6 +1744,8 @@ internal U64 dw_reg_size_from_code_x64(DW_Reg reg_code);
internal U64 dw_reg_pos_from_code_x64(DW_Reg reg_code);
internal U64 dw_reg_size_from_code(Arch arch, DW_Reg reg_code);
internal U64 dw_reg_pos_from_code(Arch arch, DW_Reg reg_code);
internal U64 dw_reg_max_size_from_arch(Arch arch);
internal U64 dw_reg_count_from_arch(Arch arch);
//- Attrib Class Encodings
@@ -1781,6 +1786,16 @@ internal DW_AttribClass dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, B
internal U64 dw_pick_default_lower_bound(DW_Language lang);
internal U64 dw_operand_count_from_expr_op(DW_ExprOp op);
internal U64 dw_pop_count_from_expr_op(DW_ExprOp op);
internal U64 dw_push_count_from_expr_op(DW_ExprOp op);
////////////////////////////////
//~ CFA
internal U64 dw_operand_count_from_cfa_opcode(DW_CFA_Opcode opcode);
internal B32 dw_is_cfa_expr_opcode_invalid(DW_ExprOp opcode);
internal B32 dw_is_new_row_cfa_opcode(DW_CFA_Opcode opcode);
internal DW_CFA_OperandType * dw_operand_types_from_cfa_op(DW_CFA_Opcode opcode);
////////////////////////////////
//~ rjf: String <=> Enum
@@ -1801,6 +1816,6 @@ internal String8 dw_string_from_loc_list_entry_kind(Arena *arena, DW_LLE kind);
internal String8 dw_string_from_section_kind(Arena *arena, DW_SectionKind kind);
internal String8 dw_string_from_rng_list_entry_kind(Arena *arena, DW_RLE kind);
internal String8 dw_string_from_register(Arena *arena, Arch arch, U64 reg_id);
internal String8 dw_string_from_cfa_opcode(DW_CFA cfa_opcode);
internal String8 dw_string_from_cfa_opcode(DW_CFA_Opcodecfa_opcode);
#endif // DWARF_H
+164 -111
View File
@@ -5,7 +5,7 @@
//~ rjf: Stringification Helpers
internal String8
dw_string_from_reg_off(Arena *arena, Arch arch, U64 reg_idx, S64 reg_off)
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);
@@ -19,6 +19,12 @@ dw_string_from_reg_off(Arena *arena, Arch arch, U64 reg_idx, S64 reg_off)
return result;
}
internal String8
dw_string_from_reg(Arena *arena, Arch arch, DW_Reg reg_idx)
{
return dw_string_from_reg_off(arena, arch, reg_idx, 0);
}
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)
{
@@ -337,166 +343,153 @@ dw_string_list_from_cfi_program(Arena *arena,
DW_Ext ext,
DW_Format format,
U64 pc_begin,
DW_UnpackedCIE *cie,
DW_ReadCfiPtrFunc *read_cfi_ptr_func,
void *read_cfi_ptr_ud,
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; cursor < program.size; ) {
DW_CFA opcode = 0;
cursor += str8_deserial_read_struct(program, cursor, &opcode);
U64 operand = 0;
if ((opcode & DW_CFAMask_OpcodeHi) != 0) {
operand = opcode & DW_CFAMask_Operand;
opcode = opcode & DW_CFAMask_OpcodeHi;
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 (opcode) {
switch (inst.opcode) {
case DW_CFA_Nop: { operand_str = str8_zero(); } break;
case DW_CFA_SetLoc: {
U64 address = 0;
cursor += read_cfi_ptr_func(program, cursor, read_cfi_ptr_ud, &address);
operand_str = str8f(arena, "0x%X", address);
operand_str = str8f(arena, "0x%X", inst.operands[0].u64);
pc = inst.operands[0].u64;
} break;
case DW_CFA_AdvanceLoc1: {
U8 delta = 0;
cursor += str8_deserial_read_struct(program, cursor, &delta);
delta *= cie->code_align_factor;
U64 delta = inst.operands[0].u64;
pc += delta;
operand_str = str8f(arena, "%+u; PC 0x%I64x", delta, pc);
operand_str = str8f(arena, "%+u `PC 0x%I64x`", delta, pc);
} break;
case DW_CFA_AdvanceLoc2: {
U16 delta = 0;
cursor += str8_deserial_read_struct(program, cursor, &delta);
delta *= cie->code_align_factor;
U64 delta = inst.operands[0].u64;
pc += delta;
operand_str = str8f(arena, "%+u; PC 0x%I64x", delta, pc);
operand_str = str8f(arena, "%+u `PC 0x%I64x`", delta, pc);
} break;
case DW_CFA_AdvanceLoc4: {
U32 delta = 0;
cursor += str8_deserial_read_struct(program, cursor, &delta);
delta *= cie->code_align_factor;
U64 delta = inst.operands[0].u64;
pc += delta;
operand_str = str8f(arena, "%+u; PC 0x%I64x", delta, pc);
operand_str = str8f(arena, "%+u `PC 0x%I64x`", delta, pc);
} break;
case DW_CFA_OffsetExt: {
U64 reg = 0, offset = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &reg);
cursor += str8_deserial_read_uleb128(program, cursor, &offset);
operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, (S64)offset * cie->data_align_factor));
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: {
U64 reg = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &reg);
operand_str = str8f(arena, "%I64u", reg);
operand_str = str8f(arena, "%I64u", inst.operands[0].u64);
} break;
case DW_CFA_SameValue: {
U64 reg = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &reg);
operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, 0));
operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, 0);
} break;
case DW_CFA_Register: {
U64 reg = 0, offset = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &reg);
cursor += str8_deserial_read_uleb128(program, cursor, &offset);
operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, (S64)offset));
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: {
U64 reg = 0, offset = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &reg);
cursor += str8_deserial_read_uleb128(program, cursor, &offset);
operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, offset));
operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].u64);
} break;
case DW_CFA_DefCfaRegister: {
U64 reg = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &reg);
operand_str = str8f(arena, "%S", dw_string_from_reg_off(scratch.arena, arch, reg, 0));
operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, 0);
} break;
case DW_CFA_DefCfaOffset: {
U64 offset = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &offset);
operand_str = str8f(arena, "+%I64u", offset);
operand_str = str8f(arena, "+%I64u", inst.operands[0].u64);
} break;
case DW_CFA_DefCfaExpr: {
U64 expr_size = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &expr_size);
String8 expr = str8_substr(program, rng_1u64(cursor, cursor + expr_size));
String8 expr_str = dw_string_from_expression(scratch.arena, expr, cu_base, cie->address_size, arch, ver, ext, format);
operand_str = str8f(arena, "%S", expr_str);
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: {
U64 reg = 0, expr_size = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &reg);
cursor += str8_deserial_read_uleb128(program, cursor, &expr_size);
String8 expr = str8_substr(program, rng_1u64(cursor, cursor + expr_size));
String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, reg, 0);
String8 expr_str = dw_string_from_expression(scratch.arena, expr, cu_base, cie->address_size, arch, ver, ext, format);
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: {
U64 reg = 0; S64 offset = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &reg);
cursor += str8_deserial_read_sleb128(program, cursor, &offset);
String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, reg, offset * cie->data_align_factor);
operand_str = str8f(arena, "%S", reg_str);
operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, inst.operands[1].s64);
} break;
case DW_CFA_DefCfaSf: {
U64 reg = 0; S64 offset = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &reg);
cursor += str8_deserial_read_sleb128(program, cursor, &offset);
String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, reg, offset * cie->data_align_factor);
operand_str = str8f(arena, "%S", reg_str);
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: {
U64 val = 0, offset = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &val);
cursor += str8_deserial_read_uleb128(program, cursor, &offset);
operand_str = str8f(arena, "value 0x%llx, offset %+I64d", val, offset);
operand_str = str8f(arena, "value 0x%llx, offset %+I64d", inst.operands[0].u64, inst.operands[1].u64);
} break;
case DW_CFA_ValOffsetSf: {
U64 val = 0; S64 offset = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &val);
cursor += str8_deserial_read_sleb128(program, cursor, &offset);
operand_str = str8f(arena, "value %llu, offset %+I64d", val, offset);
operand_str = str8f(arena, "value %llu, offset %+I64d", inst.operands[0].u64, inst.operands[1].s64);
} break;
case DW_CFA_ValExpr: {
U64 val = 0; U64 expr_size = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &val);
cursor += str8_deserial_read_uleb128(program, cursor, &expr_size);
String8 expr = str8_substr(program, rng_1u64(cursor, cursor + expr_size));
String8 expr_str = dw_string_from_expression(scratch.arena, expr, cu_base, cie->address_size, arch, ver, ext, format);
operand_str = str8f(arena, "value +%I64u, expression %S", val, expr_str);
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 = operand * cie->code_align_factor;
U64 delta = inst.operands[0].u64;
pc += delta;
operand_str = str8f(arena, "+%I64u; PC 0x%I64x", delta, pc);
operand_str = str8f(arena, "+%I64u `PC 0x%I64x`", delta, pc);
} break;
case DW_CFA_Offset: {
U64 offset = 0;
cursor += str8_deserial_read_uleb128(program, cursor, &offset);
S64 v = (S64)offset * cie->data_align_factor;
operand_str = dw_string_from_reg_off(scratch.arena, arch, operand, v);
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: {
String8 reg_str = dw_string_from_reg_off(scratch.arena, arch, operand, 0);
operand_str = str8f(arena, "%S", reg_str);
operand_str = dw_string_from_reg_off(arena, arch, inst.operands[0].u64, 0);
} break;
default: { NotImplemented; } break;
default: {
str8_list_pushf(arena, &list, "ERROR: unknown CFA opcode 0x%I64u", inst.opcode);
} goto exit;
}
str8_list_pushf(arena, &list, "DW_CFA_%S: %S", dw_string_from_cfa_opcode(opcode), operand_str);
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;
}
@@ -514,7 +507,7 @@ dw_single_line_string_from_expression(Arena *arena, String8 raw_data, U64 cu_bas
#if 0
internal String8
dw_string_from_eh_ptr_enc(Arena *arena, EH_PtrEnc enc)
w_string_from_eh_ptr_enc(Arena *arena, EH_PtrEnc enc)
{
U8 type = enc & EH_PtrEnc_TypeMask;
String8 type_str = str8_lit("NULL");
@@ -549,7 +542,7 @@ 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)
{
Temp scratch = scratch_begin(&arena, 1);
DW_UnpackedCIE cie = {0};
DW_CIE cie = {0};
for (U64 cursor = 0; cursor < raw_eh_frame.size; ) {
U64 header_offset = cursor;
@@ -592,7 +585,7 @@ dw_print_eh_frame(Arena *arena, String8List *out, String8 indent, String8 raw_eh
}
// FDE
else {
DW_UnpackedFDE fde = {0};
DW_FDE fde = {0};
dw_unwind_parse_fde_x64(raw_eh_frame.str, rng_1u64(0,raw_eh_frame.size), ptr_ctx, &cie, 0, &fde);
cfi_range = fde.cfi_range;
@@ -2166,11 +2159,11 @@ dw_dump_list_from_sections(Arena *arena,
if (desc.type == DW_DescriptorEntryType_CIE) {
String8 raw_cie = str8_substr(debug_frame, desc.entry_range);
U64 restore_pos = arena_pos(scratch.arena);
DW_UnpackedCIE *cie = push_array(scratch.arena, DW_UnpackedCIE, 1);
if (dw_unpack_cie(raw_cie, desc.format, arch, cie)) {
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(arena, restore_pos);
arena_pop_to(scratch.arena, restore_pos);
}
}
}
@@ -2182,9 +2175,9 @@ dw_dump_list_from_sections(Arena *arena,
switch (desc.type) {
case DW_DescriptorEntryType_Null: {} break;
case DW_DescriptorEntryType_CIE: {
DW_UnpackedCIE cie = {0};
if (dw_unpack_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_read_cfi_ptr, &cie, cie.init_insts);
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);
dumpf("CIE: // entry range: %r\n", desc.entry_range);
dumpf("{\n");
@@ -2193,7 +2186,7 @@ dw_dump_list_from_sections(Arena *arena,
dumpf(" Aug string: %S\n", cie.aug_string.size ? cie.aug_string : str8_lit("None"));
dumpf(" Code align: %I64u\n", cie.code_align_factor);
dumpf(" Data align: %I64d\n", cie.data_align_factor);
dumpf(" Return addr reg: %S\n", dw_string_from_register(scratch.arena, arch, cie.ret_addr_reg));
dumpf(" Return addr reg: %u\n", cie.ret_addr_reg);
if (cie.version > DW_Version_3) {
dumpf(" Address size: %u\n", cie.address_size);
dumpf(" Segment selector size: %u\n", cie.segment_selector_size);
@@ -2208,10 +2201,13 @@ dw_dump_list_from_sections(Arena *arena,
}
} break;
case DW_DescriptorEntryType_FDE: {
DW_UnpackedFDE fde = {0};
if (dw_unpack_fde(raw_desc, desc.format, dwarf_dump_cie_from_offset, cie_ht, &fde)) {
DW_UnpackedCIE *cie = hash_table_search_u64_raw(cie_ht, fde.cie_pointer);
String8List insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, DW_Ext_All, fde.format, fde.pc_range.min, cie, dw_read_cfi_ptr, cie, fde.insts);
DW_FDE fde = {0};
if (dw_parse_fde(raw_desc, desc.format, dwarf_dump_cie_from_offset, cie_ht, &fde)) {
DW_Version version = DW_Version_5;
DW_Ext ext = DW_Ext_All;
DW_CIE *cie = hash_table_search_u64_raw(cie_ht, fde.cie_pointer);
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);
dumpf("FDE: // entry range: %r\n", desc.entry_range, dw_string_from_format(fde.format), fde.cie_pointer, fde.pc_range);
dumpf("{\n");
@@ -2224,6 +2220,63 @@ dw_dump_list_from_sections(Arena *arena,
for EachNode(n, String8Node, insts_str_list.first) { dumpf(" %S\n", n->string); }
dumpf(" }\n");
}
dumpf(" Unwind:\n");
dumpf(" {\n");
DW_CFI_Unwind *cfi_unwind = dw_cfi_unwind_init(scratch.arena, arch, cie, &fde, dw_decode_ptr_debug_frame, cie);
do {
String8 cfa_str = str8_lit("???");
DW_CFA cfa = cfi_unwind->row->cfa;
switch (cfa.rule) {
case DW_CFA_Rule_Null: {} break;
case DW_CFA_Rule_RegOff: { cfa_str = dw_string_from_reg_off(scratch.arena, arch, cfa.reg, cfa.off); } break;
case DW_CFA_Rule_Expression: { cfa_str = dw_string_from_expression(scratch.arena, cfa.expr, max_U64, cie->address_size, arch, version, ext, fde.format); } break;
default: { InvalidPath; } break;
}
String8 cfi_regs_str = {0};
{
String8List cfi_regs_list = {0};
for EachIndex(reg_idx, cfi_unwind->reg_count) {
DW_CFI_Register *cfi_reg = &cfi_unwind->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_reg(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_Expression: {
rule_str = str8f(scratch.arena, "Expression(%S)", dw_string_from_expression(scratch.arena, cfi_reg->expr, max_U64, cie->address_size, arch, version, ext, fde.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, cie->address_size, arch, version, ext, fde.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_reg(scratch.arena, arch, reg_idx), rule_str);
}
}
cfi_regs_str = str8_list_join(scratch.arena, &cfi_regs_list, &(StringJoin){.sep=str8_lit(", ")});
}
dumpf(" { 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));
dumpf(" }\n");
dumpf("}\n");
} else {
dumpf("ERROR: unable to parse FDE @ %I64x\n", desc.entry_range.min);
+2 -2
View File
@@ -58,13 +58,13 @@ read_only global String8 dw_name_title_from_dump_subset_table[] =
////////////////////////////////
//~ rjf: Stringification Helpers
internal String8 dw_string_from_reg_off(Arena *arena, Arch arch, U64 reg_idx, S64 reg_off);
internal String8 dw_string_from_reg_off(Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off);
internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
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);
internal String8 dw_string_from_eh_ptr_enc (Arena *arena, EH_PtrEnc enc);
#if 0
internal void dw_string_from_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_UnpackedCIE *cie, EH_PtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
internal void dw_string_from_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIE *cie, EH_PtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
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_Input *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
+336 -15
View File
@@ -3323,15 +3323,30 @@ dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data)
return expr;
}
internal
DW_READ_CFI_PTR(dw_read_cfi_ptr)
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)
{
DW_UnpackedCIE *cie = ud;
U64 read_size = 0;
if (cie->segment_selector_size) {
NotImplemented;
} else {
read_size = str8_deserial_read(data, off, ptr_out, cie->address_size, cie->address_size);
read_size = str8_deserial_read(data, 0, ptr_out, cie->address_size, cie->address_size);
}
return read_size;
}
@@ -3347,10 +3362,10 @@ dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc
U64 length_size = str8_deserial_read_dwarf_packed_size(data, off, &length);
if (length_size == 0) { goto exit; }
Rng1U64 entry_range = rng_1u64(off + length_size, off + length_size + length);
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, 0, format, &id);
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;
@@ -3363,10 +3378,10 @@ exit:;
}
internal B32
dw_unpack_cie(String8 data, DW_Format format, Arch arch, DW_UnpackedCIE *cie_out)
dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out)
{
B32 is_parsed = 0;
U64 cursor = 0;
U64 cursor = format == DW_Format_32Bit ? 4 : 12;
U64 cie_id = 0;
U64 cie_id_size = str8_deserial_read_dwarf_uint(data, cursor, format, &cie_id);
@@ -3416,11 +3431,12 @@ dw_unpack_cie(String8 data, DW_Format format, Arch arch, DW_UnpackedCIE *cie_out
if (aug_string.size > 0) { goto exit; }
cie_out->init_insts = str8_skip(data, cursor);
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;
@@ -3431,14 +3447,14 @@ exit:;
}
internal B32
dw_unpack_fde(String8 data,
dw_parse_fde(String8 data,
DW_Format format,
DW_CIEFromOffsetFunc *cie_from_offset_func,
void *cie_from_offset_ud,
DW_UnpackedFDE *fde_out)
DW_FDE *fde_out)
{
B32 is_parsed = 0;
U64 cursor = 0;
U64 cursor = format == DW_Format_32Bit ? 4 : 12;
// extract CIE pointer
U64 cie_pointer = 0;
@@ -3447,18 +3463,18 @@ dw_unpack_fde(String8 data,
cursor += cie_pointer_size;
// map offset -> CIE
DW_UnpackedCIE *cie = cie_from_offset_func(cie_from_offset_ud, cie_pointer);
DW_CIE *cie = cie_from_offset_func(cie_from_offset_ud, cie_pointer);
if (cie == 0) { goto exit; }
// extract address of first instruction
U64 pc_begin = 0;
U64 pc_begin_size = dw_read_cfi_ptr(data, cursor, cie, &pc_begin);
U64 pc_begin_size = dw_read_debug_frame_ptr(str8_skip(data, cursor), cie, &pc_begin);
if (pc_begin_size == 0) { goto exit; }
cursor += pc_begin_size;
// extract instruction range size
U64 pc_range = 0;
U64 pc_range_size = dw_read_cfi_ptr(data, cursor, cie, &pc_range);
U64 pc_range_size = dw_read_debug_frame_ptr(str8_skip(data, cursor), cie, &pc_range);
if (pc_range_size == 0) { goto exit; }
cursor += pc_range_size;
@@ -3477,3 +3493,308 @@ exit:;
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;
U64 raw_opcode_size = str8_deserial_read_struct(data, cursor, &raw_opcode);
if (raw_opcode_size == 0) { goto exit; }
cursor += raw_opcode_size;
// 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; }
operands[0].u64 = delta * code_align_factor;
} break;
case DW_CFA_DefCfa: {
U64 reg = 0;
U64 reg_size = str8_deserial_read_uleb128(data, cursor, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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].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: { NotImplemented; 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 += 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);
}
+55 -17
View File
@@ -370,9 +370,9 @@ typedef struct DW_DescriptorEntry
Rng1U64 entry_range;
} DW_DescriptorEntry;
typedef struct DW_UnpackedCIE
typedef struct DW_CIE
{
String8 init_insts;
String8 insts;
String8 aug_string;
String8 aug_data;
U64 code_align_factor;
@@ -382,25 +382,55 @@ typedef struct DW_UnpackedCIE
U8 version;
U8 address_size;
U8 segment_selector_size;
Rng1U64 cfi_range;
} DW_UnpackedCIE;
} DW_CIE;
typedef struct DW_UnpackedFDE
typedef struct DW_FDE
{
DW_Format format;
U64 cie_pointer;
Rng1U64 pc_range;
String8 insts;
Rng1U64 cfi_range;
} DW_UnpackedFDE;
DW_Format format;
U64 cie_pointer;
Rng1U64 pc_range;
String8 insts;
} DW_FDE;
#define DW_READ_CFI_PTR(name) U64 name(String8 data, U64 off, void *ud, U64 *ptr_out)
typedef DW_READ_CFI_PTR(DW_ReadCfiPtrFunc);
typedef union DW_CFA_Operand
{
U64 u64;
S64 s64;
String8 block;
} DW_CFA_Operand;
#define DW_CIE_FROM_OFFSET_FUNC(name) DW_UnpackedCIE * name(void *ud, U64 offset)
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);
#define DW_CIE_FROM_OFFSET_FUNC(name) DW_CIE * name(void *ud, U64 offset)
typedef DW_CIE_FROM_OFFSET_FUNC(DW_CIEFromOffsetFunc);
// hasher
internal U64 dw_hash_from_string(String8 string);
@@ -520,8 +550,16 @@ internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size
// 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_unpack_cie(String8 data, DW_Format format, Arch arch, DW_UnpackedCIE *cie_out);
internal B32 dw_unpack_fde(String8 data, DW_Format format, DW_CIEFromOffsetFunc *cie_from_offset_func, void *cie_from_offset_ud, DW_UnpackedFDE *fde_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_CIEFromOffsetFunc *cie_from_offset_func, void *cie_from_offset_ud, 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
+258 -1056
View File
File diff suppressed because it is too large Load Diff
+59 -119
View File
@@ -4,150 +4,90 @@
#ifndef DWARF_UNWIND_H
#define DWARF_UNWIND_H
typedef struct DW_UnwindResult
typedef enum DW_CFI_RegisterRule
{
B32 is_invalid;
B32 missed_read;
U64 missed_read_addr;
U64 stack_pointer;
} DW_UnwindResult;
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;
// EH: Exception Frames
typedef struct DW_UnpackedCIENode
typedef enum DW_CFA_Rule
{
struct DW_UnpackedCIENode *next;
DW_UnpackedCIE cie;
U64 offset;
} DW_UnpackedCIENode;
DW_CFA_Rule_Null,
DW_CFA_Rule_RegOff,
DW_CFA_Rule_Expression
} DW_CFA_Rule;
// CFI: Call Frame Information
typedef struct DW_CFIRecords
typedef struct DW_CFA
{
B32 valid;
DW_UnpackedCIE cie;
DW_UnpackedFDE fde;
} DW_CFIRecords;
typedef enum DW_CFICFARule{
DW_CFI_CFA_Rule_RegOff,
DW_CFI_CFA_Rule_Expr,
} DW_CFICFARule;
typedef struct DW_CFICFACell
{
DW_CFICFARule rule;
DW_CFA_Rule rule;
union {
struct {
U64 reg_idx;
S64 offset;
DW_Reg reg;
S64 off;
};
Rng1U64 expr;
String8 expr;
};
} DW_CFICFACell;
} DW_CFA;
typedef enum DW_CFIRegisterRule
typedef struct DW_CFI_Register
{
DW_CFIRegisterRule_SameValue,
DW_CFIRegisterRule_Undefined,
DW_CFIRegisterRule_Offset,
DW_CFIRegisterRule_ValOffset,
DW_CFIRegisterRule_Register,
DW_CFIRegisterRule_Expression,
DW_CFIRegisterRule_ValExpression,
} DW_CFIRegisterRule;
typedef struct DW_CFICell
{
DW_CFIRegisterRule rule;
DW_CFI_RegisterRule rule;
union {
S64 n;
Rng1U64 expr;
S64 n;
String8 expr;
};
} DW_CFICell;
} DW_CFI_Register;
typedef struct DW_CFIRow
typedef struct DW_CFA_Row
{
struct DW_CFIRow *next;
DW_CFICell *cells;
DW_CFICFACell cfa_cell;
} DW_CFIRow;
DW_CFA cfa;
DW_CFI_Register *regs;
struct DW_CFA_Row *next;
} DW_CFA_Row;
typedef struct DW_CFIMachine
typedef struct DW_CFI_Unwind
{
U64 cells_per_row;
DW_UnpackedCIE *cie;
DW_CFIRow *initial_row;
U64 fde_ip;
EH_PtrCtx *ptr_ctx;
} DW_CFIMachine;
DW_CFA_InstList insts;
DW_CIE *cie;
DW_FDE *fde;
DW_CFA_Row *initial_row;
DW_CFA_Row *row;
DW_CFA_InstNode *curr_inst;
DW_CFA_Row *free_rows;
DW_Reg reg_count;
U64 pc;
Arch arch;
} DW_CFI_Unwind;
typedef U8 DW_CFADecode;
enum
{
DW_CFADecode_Nop = 0x0,
// 1,2,4,8 reserved for literal byte sizes
DW_CFADecode_Address = 0x9,
DW_CFADecode_ULEB128 = 0xA,
DW_CFADecode_SLEB128 = 0xB,
};
typedef enum {
DW_UnwindStatus_Ok,
DW_UnwindStatus_Fail,
DW_UnwindStatus_Maybe
} DW_UnwindStatus;
typedef U16 DW_CFAControlBits;
enum
{
DW_CFAControlBits_Dec1Mask = 0x00F,
DW_CFAControlBits_Dec2Mask = 0x0F0,
DW_CFAControlBits_IsReg0 = 0x100,
DW_CFAControlBits_IsReg1 = 0x200,
DW_CFAControlBits_IsReg2 = 0x400,
DW_CFAControlBits_NewRow = 0x800,
};
#define DW_REG_READ(name) DW_UnwindStatus name(DW_Reg reg_id, void *buffer, U64 buffer_max, void *ud)
typedef DW_REG_READ(DW_RegRead);
global read_only DW_CFAControlBits dw_unwind__cfa_control_bits_kind1[DW_CFA_OplKind1 + 1];
global read_only DW_CFAControlBits dw_unwind__cfa_control_bits_kind2[DW_CFA_OplKind2 + 1];
#define DW_REG_WRITE(name) DW_UnwindStatus name(DW_Reg reg_id, void *value, U64 value_size, void *ud)
typedef DW_REG_WRITE(DW_RegWrite);
// register codes for unwinding match the DW_RegX64 register codes
#define DW_UNWIND_X64__REG_SLOT_COUNT 17
#define DW_MEM_READ(name) DW_UnwindStatus name(U64 addr, U64 size, void *buffer, void *ud)
typedef DW_MEM_READ(DW_MemRead);
////////////////////////////////
// x64 Unwind Function
internal DW_UnwindResult
dw_unwind_x64(String8 raw_text,
String8 raw_eh_frame,
String8 raw_eh_frame_header,
Rng1U64 text_vrange,
Rng1U64 eh_frame_vrange,
Rng1U64 eh_frame_header_vrange,
U64 default_image_base,
U64 image_base,
U64 stack_pointer,
DW_RegsX64 *regs,
DW_ReadMemorySig *read_memory,
void *read_memory_ud);
internal DW_CFA_Row * dw_make_cfa_row(Arena *arena, U64 reg_count);
internal DW_CFA_Row * dw_copy_cfa_row(Arena *arena, U64 reg_count, DW_CFA_Row *row);
internal DW_UnwindResult dw_unwind_x64__apply_frame_rules(String8 raw_eh_frame, DW_CFIRow *row, U64 text_base_vaddr, DW_ReadMemorySig *read_memory, void *read_memory_ud, U64 stack_pointer, DW_RegsX64 *regs);
////////////////////////////////
// x64 Unwind Helper Functions
internal void dw_unwind_init_x64(void);
//- eh_frame parsing
internal DW_CFIRecords dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, EH_PtrCtx *ptr_ctx, U64 ip_voff);
internal DW_CFIRecords dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 ip_voff);
//- cfi machine
internal DW_CFIMachine dw_unwind_make_machine_x64(U64 cells_per_row, DW_UnpackedCIE *cie, EH_PtrCtx *ptr_ctx);
internal void dw_unwind_machine_equip_initial_row_x64(DW_CFIMachine *machine, DW_CFIRow *initial_row);
internal void dw_unwind_machine_equip_fde_ip_x64(DW_CFIMachine *machine, U64 fde_ip);
internal DW_CFIRow* dw_unwind_row_alloc_x64(Arena *arena, U64 cells_per_row);
internal void dw_unwind_row_zero_x64(DW_CFIRow *row, U64 cells_per_row);
internal void dw_unwind_row_copy_x64(DW_CFIRow *dst, DW_CFIRow *src, U64 cells_per_row);
internal B32 dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machine, U64 target_ip, DW_CFIRow *row_out);
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_UnwindStatus dw_cfi_apply_register_rules(DW_CFI_Unwind *uw, DW_MemRead *mem_read_func, void *mem_read_ud, DW_RegRead *reg_read_func, void *reg_read_ud, DW_RegWrite *reg_write_func, void *reg_write_ud);
#endif // DWARF_UNWIND_H
+157
View File
@@ -122,3 +122,160 @@ eh_size_from_aug_data(String8 aug_string, String8 data, EH_PtrCtx *ptr_ctx)
return eh_parse_aug_data(aug_string, data, ptr_ctx, 0);
}
internal U64
eh_frame_hdr_search_linear_x64(String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 location)
{
// Table contains only addresses for first instruction in a function and we cannot
// guarantee that result is FDE that corresponds to the input location.
// So input location must be cheked against range from FDE header again.
U64 closest_location = max_U64;
U64 closest_address = max_U64;
U64 cursor = 0;
U8 version = 0;
cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &version);
if (version == 1) {
#if 0
EH_PtrCtx ptr_ctx = {0};
// Set this to base address of .eh_frame_hdr. Entries are relative
// to this section for some reason.
ptr_ctx.data_vaddr = range.min;
// If input location is VMA then set this to address of .text.
// Pointer parsing function will adjust "init_location" to correct VMA.
ptr_ctx.text_vaddr = 0;
#endif
EH_PtrEnc eh_frame_ptr_enc = 0, fde_count_enc = 0, table_enc = 0;
cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &eh_frame_ptr_enc);
cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &fde_count_enc);
cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &table_enc);
U64 eh_frame_ptr = 0, fde_count = 0;
NotImplemented;
//cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, eh_frame_ptr_enc, cursor, &eh_frame_ptr);
//cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, fde_count_enc, cursor, &fde_count);
for (U64 fde_idx = 0; fde_idx < fde_count; ++fde_idx) {
U64 init_location = 0, address = 0;
NotImplemented;
//cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &init_location);
//cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &address);
S64 current_delta = (S64)(location - init_location);
S64 closest_delta = (S64)(location - closest_location);
if (0 <= current_delta && current_delta < closest_delta) {
closest_location = init_location;
closest_address = address;
}
}
}
// address where to find corresponding FDE, this is an absolute offset
// into the image file.
return closest_address;
}
#if 0
internal DW_CFIRecords
dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 ip_voff)
{
DW_CFIRecords result = {0};
// find FDE offset
void *eh_frame_hdr = raw_eh_frame.str;
U64 fde_offset = dw_search_eh_frame_hdr_linear_x64(raw_eh_frame_hdr, ptr_ctx, ip_voff);
B32 is_fde_offset_valid = (fde_offset != max_U64);
if (is_fde_offset_valid) {
U64 fde_read_offset = (fde_offset - ptr_ctx->raw_base_vaddr);
// read FDE size
U64 fde_size = 0;
fde_read_offset += str8_deserial_read_dwarf_packed_size(raw_eh_frame, fde_read_offset, &fde_size);
// read FDE discriminator
U32 fde_discrim = 0;
fde_read_offset += str8_deserial_read_struct(raw_eh_frame, fde_read_offset, &fde_discrim);
// compute parent CIE offset
U64 cie_read_offset = fde_read_offset - (fde_discrim + sizeof(fde_discrim));
// read CIE size
U64 cie_size = 0;
cie_read_offset += str8_deserial_read_dwarf_packed_size(raw_eh_frame, cie_read_offset, &cie_size);
// read CIE discriminator
U32 cie_discrim = max_U32;
cie_read_offset += str8_deserial_read_struct(raw_eh_frame, cie_read_offset, &cie_discrim);
B32 is_fde = (fde_discrim != 0);
B32 is_cie = (cie_discrim == 0);
if (is_fde && is_cie) {
Rng1U64 cie_range = rng_1u64(0, cie_read_offset + (cie_size - sizeof(cie_discrim)));
Rng1U64 fde_range = rng_1u64(0, fde_read_offset + (fde_size - sizeof(fde_discrim)));
// parse CIE
DW_CIE cie = {0};
dw_unwind_parse_cie_x64(raw_eh_frame.str, cie_range, ptr_ctx, cie_read_offset, &cie);
// parse FDE
DW_FDE fde = {0};
NotImplemented;
//dw_unwind_parse_fde_x64(raw_eh_frame.str, fde_range, ptr_ctx, &cie, fde_read_offset, &fde);
// range check instruction pointer
if (contains_1u64(fde.pc_range, ip_voff)) {
result.valid = 1;
result.cie = cie;
result.fde = fde;
}
}
}
return result;
}
#endif
internal String8
eh_string_from_ptr_enc_type(EH_PtrEnc type)
{
switch (type) {
case EH_PtrEnc_Ptr: return str8_lit("Ptr");
case EH_PtrEnc_ULEB128: return str8_lit("ULEB128");
case EH_PtrEnc_UData2: return str8_lit("UData2");
case EH_PtrEnc_UData4: return str8_lit("UData4");
case EH_PtrEnc_UData8: return str8_lit("UData8");
case EH_PtrEnc_Signed: return str8_lit("Signed");
case EH_PtrEnc_SLEB128: return str8_lit("SLEB128");
case EH_PtrEnc_SData2: return str8_lit("SData2");
case EH_PtrEnc_SData4: return str8_lit("SData4");
case EH_PtrEnc_SData8: return str8_lit("SData8");
}
return str8_zero();
}
internal String8
eh_string_from_ptr_enc_modifier(EH_PtrEnc modifier)
{
switch (modifier) {
case EH_PtrEnc_PcRel: return str8_lit("PcRel");
case EH_PtrEnc_TextRel: return str8_lit("TextRel");
case EH_PtrEnc_DataRel: return str8_lit("DataRel");
case EH_PtrEnc_FuncRel: return str8_lit("FuncRel");
case EH_PtrEnc_Aligned: return str8_lit("Aligned");
}
return str8_zero();
}
internal String8
eh_string_from_ptr_enc(Arena *arena, EH_PtrEnc enc)
{
String8 type_str = eh_string_from_ptr_enc_type(enc & EH_PtrEnc_TypeMask);
String8 modifer_str = eh_string_from_ptr_enc_modifier(enc & EH_PtrEnc_ModifierMask);
String8 indir_str = enc & EH_PtrEnc_Indirect ? str8_lit("Indirect") : str8_zero();
String8 result = str8f(arena, "Type: %S, Modifier %S (%S)", type_str, modifer_str, indir_str);
return result;
}
+7
View File
@@ -70,5 +70,12 @@ internal U64 eh_read_ptr(String8 frame_base, U64 off, EH_PtrCtx *ptr_ctx, EH_Ptr
internal U64 eh_parse_aug_data(String8 aug_string, String8 aug_data, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out);
internal U64 eh_size_from_aug_data(String8 aug_string, String8 data, EH_PtrCtx *ptr_ctx);
////////////////////////////////
//~ Enum -> String
internal String8 eh_string_from_ptr_enc_type(EH_PtrEnc type);
internal String8 eh_string_from_ptr_enc_modifier(EH_PtrEnc modifier);
internal String8 eh_string_from_ptr_enc(Arena *arena, EH_PtrEnc enc);
#endif // EH_FRAME_H