add support for CFA in the eval system

Canonical Frame Address is a DWARF-only concept encoded in the unwind info.
Debugger must store this data for each call frame and provide it to
the eval system based on selected stack frame.

To abstract over format details, we introduce a "Frame Unwind Context".
For DWARF, this context maintains the intermediate unwind state and exposes
the CFA, whereas for PE, it remains empty.
This commit is contained in:
Nikita Smith
2025-11-26 15:42:40 -08:00
parent 2a6d0d737c
commit f9561cb618
9 changed files with 225 additions and 100 deletions
+23 -12
View File
@@ -237,18 +237,14 @@ dw_cfi_row_from_pc(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodeP
}
internal DW_UnwindStatus
dw_cfi_apply_register_rules(Arch arch,
DW_CIE *cie,
DW_CFI_Row *row,
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)
dw_compute_cfa(Arch arch,
DW_CFI_Row *row,
DW_MemRead *mem_read_func, void *mem_read_ud,
DW_RegRead *reg_read_func, void *reg_read_ud,
U64 *cfa_out)
{
Temp scratch = scratch_begin(0,0);
DW_UnwindStatus unwind_status = DW_UnwindStatus_Ok;
DW_UnwindStatus unwind_status = DW_UnwindStatus_Fail;
// establish CFA
U64 cfa = 0;
switch (row->cfa.rule) {
case DW_CFA_Rule_Null: break;
case DW_CFA_Rule_RegOff: {
@@ -257,14 +253,29 @@ dw_cfi_apply_register_rules(Arch arch,
U64 reg_size = dw_reg_size_from_code(arch, row->cfa.reg);
AssertAlways(reg_size <= sizeof(cfa_reg_value));
unwind_status = reg_read_func(row->cfa.reg, &cfa_reg_value, reg_size, reg_read_ud);
if (unwind_status != DW_UnwindStatus_Ok) { goto exit; }
cfa = cfa_reg_value + row->cfa.off;
if (unwind_status != DW_UnwindStatus_Ok) { break; }
*cfa_out = cfa_reg_value + row->cfa.off;
} break;
case DW_CFA_Rule_Expression: {
// TODO: evaluate expression
NotImplemented;
} break;
}
return unwind_status;
}
internal DW_UnwindStatus
dw_cfi_apply_register_rules(Arch arch,
U64 cfa,
DW_CFI_Row *row,
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)
{
Temp scratch = scratch_begin(0,0);
DW_UnwindStatus unwind_status = DW_UnwindStatus_Ok;
U64 max_reg_size = dw_reg_max_size_from_arch(arch);
void *reg_buffer = push_array(scratch.arena, U8, max_reg_size);
+1 -1
View File
@@ -89,7 +89,7 @@ internal DW_CFI_Unwind * dw_cfi_unwind_init(Arena *arena, Arch arch, DW_CIE *cie
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 DW_UnwindStatus dw_cfi_apply_register_rules(Arch arch, DW_CIE *cie, DW_CFI_Row *row, 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);
internal DW_UnwindStatus dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, 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