diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 06b3dcba..f31cd624 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1838,7 +1838,7 @@ DW_MEM_READ(ctrl_unwind_mem_read_dwarf_x64) B32 is_read = ctrl_process_memory_read(ctx->process_handle, r1u64(addr, addr + size), &is_stale, buffer, ctx->endt_us); DW_UnwindStatus status = DW_UnwindStatus_Fail; - if(is_stale && is_read) + if(is_stale) { status = DW_UnwindStatus_Maybe; } @@ -1903,12 +1903,35 @@ DW_REG_WRITE(ctrl_unwind_reg_write_dwarf_x64) } internal CTRL_UnwindStepResult -ctrl_unwind_step__dwarf(CTRL_Handle process_handle, CTRL_Handle module_handle, Arch arch, void *regs, U64 endt_us) +ctrl_unwind_step_result_from_dwarf_status(DW_UnwindStatus s) { - Temp scratch = scratch_begin(0, 0); - + CTRL_UnwindStepResult result = {0}; + switch(s) + { + case DW_UnwindStatus_Ok: + { + result.flags &= ~(CTRL_UnwindFlag_Error|CTRL_UnwindFlag_Stale); + }break; + case DW_UnwindStatus_Fail: + { + result.flags |= CTRL_UnwindFlag_Error; + }break; + case DW_UnwindStatus_Maybe: + { + result.flags &= ~CTRL_UnwindFlag_Error; + result.flags |= CTRL_UnwindFlag_Stale; + }break; + default: { InvalidPath; } break; + } + return result; +} + +internal CTRL_UnwindStepResult +ctrl_establish_frame_unwind_context__dwarf(Arena *arena, CTRL_Handle process_handle, CTRL_Handle module_handle, Arch arch, void *regs, U64 endt_us, CTRL_FrameUnwindContext *ctx_out) +{ + Temp scratch = scratch_begin(&arena, 1); CTRL_UnwindStepResult result = { .flags = CTRL_UnwindFlag_Error }; - + // gather context for virtual stack unwinder U64 cfi_rebase = 0; B32 is_unwind_eh = 0; @@ -1944,9 +1967,9 @@ ctrl_unwind_step__dwarf(CTRL_Handle process_handle, CTRL_Handle module_handle, A if(fde_addr != max_U64) { // parse call frame info - DW_CIE cie = {0}; - DW_FDE fde = {0}; - B32 is_cfi_parsed = 0; + DW_CIE cie = {0}; + DW_FDE fde = {0}; + B32 is_cfi_parsed = 0; if(is_unwind_eh) { B32 is_stale = 0; @@ -2051,16 +2074,14 @@ ctrl_unwind_step__dwarf(CTRL_Handle process_handle, CTRL_Handle module_handle, A } // find register rules for IP - DW_CFI_Row *cfi_row = dw_cfi_row_from_pc(scratch.arena, arch, &cie, &fde, decode_ptr_func, decode_ptr_ctx, ip); + DW_CFI_Row *cfi_row = dw_cfi_row_from_pc(arena, arch, &cie, &fde, decode_ptr_func, decode_ptr_ctx, ip); if(cfi_row) { // setup machine ops void *mem_read_ctx = 0; void *reg_read_ctx = 0; - void *reg_write_ctx = 0; DW_MemRead *mem_read_func = 0; DW_RegRead *reg_read_func = 0; - DW_RegWrite *reg_write_func = 0; switch(arch) { case Arch_Null: break; @@ -2072,11 +2093,9 @@ ctrl_unwind_step__dwarf(CTRL_Handle process_handle, CTRL_Handle module_handle, A mem_read_ctx = mem_read_ctx_x64; reg_read_ctx = regs; - reg_write_ctx = regs; mem_read_func = ctrl_unwind_mem_read_dwarf_x64; reg_read_func = ctrl_unwind_reg_read_dwarf_x64; - reg_write_func = ctrl_unwind_reg_write_dwarf_x64; }break; case Arch_x86: case Arch_arm64: @@ -2084,51 +2103,90 @@ ctrl_unwind_step__dwarf(CTRL_Handle process_handle, CTRL_Handle module_handle, A { NotImplemented; }break; - default: { InvalidPath; } break; + default: { InvalidPath; }break; } - - // apply register rules to the context - DW_UnwindStatus cfi_uw_status = dw_cfi_apply_register_rules(arch, - &cie, - cfi_row, - mem_read_func, - mem_read_ctx, - reg_read_func, - reg_read_ctx, - reg_write_func, - reg_write_ctx); - - // last frame typically has undefined rule for IP - if(cfi_row->regs[cie.ret_addr_reg].rule == DW_CFI_RegisterRule_Undefined) + + // compute CFA for the row + U64 cfa = 0; + DW_UnwindStatus unwind_status = dw_compute_cfa(arch, cfi_row, mem_read_func, mem_read_ctx, reg_read_func, reg_read_ctx, &cfa); + + // on success fill out output + if(unwind_status == DW_UnwindStatus_Ok) { - regs_arch_block_write_rip(arch, regs, 0); - } - - // translate unwind status code to control layer's result flags - switch(cfi_uw_status) - { - case DW_UnwindStatus_Ok: - { - result.flags &= ~(CTRL_UnwindFlag_Error|CTRL_UnwindFlag_Stale); - }break; - case DW_UnwindStatus_Fail: - { - result.flags |= CTRL_UnwindFlag_Error; - }break; - case DW_UnwindStatus_Maybe: - { - result.flags &= ~CTRL_UnwindFlag_Error; - result.flags |= CTRL_UnwindFlag_Stale; - }break; - default: { InvalidPath; } break; + ctx_out->cfa = cfa; + ctx_out->cfi_row = cfi_row; + ctx_out->ret_addr_reg = cie.ret_addr_reg; } + + // translate unwind status code + result = ctrl_unwind_step_result_from_dwarf_status(unwind_status); } } } - else + + scratch_end(scratch); + return result; +} + +internal CTRL_UnwindStepResult +ctrl_unwind_step__dwarf(CTRL_Handle process_handle, CTRL_Handle module_handle, Arch arch, void *regs, CTRL_FrameUnwindContext *frame_ctx, U64 endt_us) +{ + Temp scratch = scratch_begin(0, 0); + + CTRL_UnwindStepResult result = { .flags = CTRL_UnwindFlag_Error }; + + // setup machine ops + void *mem_read_ctx = 0; + void *reg_read_ctx = 0; + void *reg_write_ctx = 0; + DW_MemRead *mem_read_func = 0; + DW_RegRead *reg_read_func = 0; + DW_RegWrite *reg_write_func = 0; + switch(arch) { - // TODO: if IP does not have FDE, does this mean function is a leaf? + case Arch_Null: break; + case Arch_x64: + { + CTRL_MemoryReadContextDwarfX64 *mem_read_ctx_x64 = push_array(scratch.arena, CTRL_MemoryReadContextDwarfX64, 1); + mem_read_ctx_x64->process_handle = process_handle; + mem_read_ctx_x64->endt_us = endt_us; + + mem_read_ctx = mem_read_ctx_x64; + reg_read_ctx = regs; + reg_write_ctx = regs; + + mem_read_func = ctrl_unwind_mem_read_dwarf_x64; + reg_read_func = ctrl_unwind_reg_read_dwarf_x64; + reg_write_func = ctrl_unwind_reg_write_dwarf_x64; + }break; + case Arch_x86: + case Arch_arm64: + case Arch_arm32: + { + NotImplemented; + }break; + default: { InvalidPath; }break; } + + // apply register rules to the context + DW_UnwindStatus unwind_status = dw_cfi_apply_register_rules(arch, + frame_ctx->cfa, + frame_ctx->cfi_row, + mem_read_func, + mem_read_ctx, + reg_read_func, + reg_read_ctx, + reg_write_func, + reg_write_ctx); + + // last frame typically has undefined rule for IP + if(frame_ctx->cfi_row->regs[frame_ctx->ret_addr_reg].rule == DW_CFI_RegisterRule_Undefined) + { + regs_arch_block_write_rip(arch, regs, 0); + } + + // translate unwind status code + result = ctrl_unwind_step_result_from_dwarf_status(unwind_status); scratch_end(scratch); return result; @@ -2977,23 +3035,41 @@ ctrl_unwind_step__pe_x64(CTRL_Handle process_handle, CTRL_Handle module_handle, //- rjf: abstracted unwind step internal CTRL_UnwindStepResult -ctrl_unwind_step(CTRL_Handle process, CTRL_Handle module, U64 module_base_vaddr, Arch arch, void *reg_block, U64 endt_us) +ctrl_establish_frame_unwind_context(Arena *arena, CTRL_Handle process_handle, CTRL_Handle module_handle, Arch arch, void *regs, U64 endt_us, CTRL_FrameUnwindContext *ctx_out) { CTRL_UnwindStepResult result = {0}; - - result = ctrl_unwind_step__dwarf(process, module, arch, reg_block, endt_us); - - if(result.flags == CTRL_UnwindFlag_Error && ~result.flags & CTRL_UnwindFlag_Stale) +#if OS_LINUX + result = ctrl_establish_frame_unwind_context__dwarf(arena, process_handle, module_handle, arch, regs, endt_us, ctx_out); +#elif OS_WINDOWS + // windows does not have a concept of frame context +#else +# error "unwinder is not defined for current OS" +#endif + return result; +} + +internal CTRL_UnwindStepResult +ctrl_unwind_step(CTRL_Handle process, CTRL_Handle module, U64 module_base_vaddr, Arch arch, void *reg_block, CTRL_FrameUnwindContext *frame_ctx, U64 endt_us) +{ + CTRL_UnwindStepResult result = {0}; +#if OS_LINUX + result = ctrl_unwind_step__dwarf(process, module, arch, reg_block, frame_ctx, endt_us); +#elif OS_WINDOWS + switch(arch) { - switch(arch) + case Arch_Null:{}break; + case Arch_x64:{result = ctrl_unwind_step__pe_x64(process, module, module_base_vaddr, reg_block, endt_us);}break; + case Arch_x86: + case Arch_arm32: + case Arch_arm64: { - default:{}break; - case Arch_x64: - { - result = ctrl_unwind_step__pe_x64(process, module, module_base_vaddr, (REGS_RegBlockX64 *)reg_block, endt_us); - }break; - } + NotImplemented; + }break; + default:{InvalidPath;}break; } +#else +# error "unwinder is not defined for current OS" +#endif return result; } @@ -3004,8 +3080,7 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle thread, U { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); - CTRL_Unwind unwind = {0}; - unwind.flags |= CTRL_UnwindFlag_Error; + CTRL_Unwind unwind = { .flags = CTRL_UnwindFlag_Error }; //- rjf: unpack args CTRL_Entity *thread_entity = ctrl_entity_from_handle(ctx, thread); @@ -3023,24 +3098,25 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle thread, U U64 frame_node_count = 0; if(regs_block_good) { - unwind.flags = 0; - for(;;) + for(unwind.flags = 0;;) { - // rjf: regs -> rip*module U64 rip = regs_rip_from_arch_block(arch, regs_block); U64 rsp = regs_rsp_from_arch_block(arch, regs_block); - CTRL_Entity *module = &ctrl_entity_nil; - for(CTRL_Entity *m = process_entity->first; m != &ctrl_entity_nil; m = m->next) + + // rjf: cancel on 0 rip + if(rip == 0) { - if(m->kind == CTRL_EntityKind_Module && contains_1u64(m->vaddr_range, rip)) - { - module = m; - break; - } + break; } - - // rjf: cancel on 0 rip/rsp - if(rsp == 0 && rip == 0) + + // rip -> module + CTRL_Entity *module = ctrl_module_from_process_vaddr(process_entity, rip); + + // establish frame context + CTRL_FrameUnwindContext frame_ctx = {0}; + CTRL_UnwindStepResult frame_ctx_result = ctrl_establish_frame_unwind_context(scratch.arena, process_entity->handle, module->handle, arch, regs_block, endt_us, &frame_ctx); + unwind.flags |= frame_ctx_result.flags; + if(unwind.flags & (CTRL_UnwindFlag_Stale|CTRL_UnwindFlag_Error)) { break; } @@ -3048,19 +3124,19 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle thread, U // rjf: valid step -> push frame CTRL_UnwindFrameNode *frame_node = push_array(scratch.arena, CTRL_UnwindFrameNode, 1); CTRL_UnwindFrame *frame = &frame_node->v; + frame->cfa = frame_ctx.cfa; frame->regs = push_array_no_zero(arena, U8, arch_reg_block_size); MemoryCopy(frame->regs, regs_block, arch_reg_block_size); DLLPushBack(first_frame_node, last_frame_node, frame_node); frame_node_count += 1; // rjf: unwind one step - CTRL_UnwindStepResult step = ctrl_unwind_step(process_entity->handle, module->handle, module->vaddr_range.min, arch, regs_block, endt_us); + CTRL_UnwindStepResult step = ctrl_unwind_step(process_entity->handle, module->handle, module->vaddr_range.min, arch, regs_block, &frame_ctx, endt_us); unwind.flags |= step.flags; - if(step.flags & CTRL_UnwindFlag_Error || - regs_rsp_from_arch_block(arch, regs_block) == 0 || - regs_rip_from_arch_block(arch, regs_block) == 0 || - (regs_rsp_from_arch_block(arch, regs_block) == rsp && - regs_rip_from_arch_block(arch, regs_block) == rip)) + + // stop unwinding on errors or stale data + if(unwind.flags & (CTRL_UnwindFlag_Stale|CTRL_UnwindFlag_Error) || + (regs_rsp_from_arch_block(arch, regs_block) == rsp && regs_rip_from_arch_block(arch, regs_block) == rip)) { break; } @@ -3133,6 +3209,7 @@ ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *bas SLLQueuePush(first_frame, last_frame, dst_inline); dst_inline->v.unwind_count = base_frame_idx; dst_inline->v.regs = src->regs; + dst_inline->v.cfa = src->cfa; frame_count += 1; inline_frame_count += 1; } @@ -3142,6 +3219,7 @@ ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *bas SLLQueuePush(first_frame, last_frame, dst_base); dst_base->v.unwind_count = base_frame_idx; dst_base->v.regs = src->regs; + dst_base->v.cfa = src->cfa; frame_count += 1; // rjf: hook up inline frames to point to concrete frame, and to account for inline depth @@ -4898,6 +4976,8 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C ctx->frame_base = push_array(arena, U64, 1); // TODO(rjf): need to compute this out here somehow... ctx->frame_base[0] = ; ctx->tls_base = push_array(arena, U64, 1); + // TODO: compute CFA + ctx->cfa = 0; } e_select_interpret_ctx(&scope->interpret_ctx, eval_dbg_infos_primary->rdi, thread_rip_voff); diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 69d629a8..650207d8 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -248,6 +248,7 @@ typedef struct CTRL_UnwindFrame CTRL_UnwindFrame; struct CTRL_UnwindFrame { void *regs; + U64 cfa; }; typedef struct CTRL_UnwindFrameNode CTRL_UnwindFrameNode; @@ -272,6 +273,15 @@ struct CTRL_Unwind CTRL_UnwindFlags flags; }; +typedef struct CTRL_FrameUnwindContext CTRL_FrameUnwindContext; +struct CTRL_FrameUnwindContext +{ + // DWARF + U64 cfa; + DW_CFI_Row *cfi_row; + U64 ret_addr_reg; +}; + //////////////////////////////// //~ rjf: Call Stack Types @@ -281,6 +291,7 @@ struct CTRL_CallStackFrame U64 unwind_count; U64 inline_depth; void *regs; + U64 cfa; }; typedef struct CTRL_CallStack CTRL_CallStack; @@ -948,14 +959,15 @@ internal Arch ctrl_arch_from_process_handle(CTRL_Handle process_handle); internal CTRL_Unwind ctrl_unwind_deep_copy(Arena *arena, Arch arch, CTRL_Unwind *src); //- DWARF -internal CTRL_UnwindStepResult ctrl_unwind_step__dwarf(CTRL_Handle process_handle, CTRL_Handle module_handle, Arch arch, void *regs, U64 endt_us); +internal CTRL_UnwindStepResult ctrl_establish_frame_unwind_context__dwarf(Arena *arena, CTRL_Handle process_handle, CTRL_Handle module_handle, Arch arch, void *regs, U64 endt_us, CTRL_FrameUnwindContext *ctx_out); +internal CTRL_UnwindStepResult ctrl_unwind_step__dwarf(CTRL_Handle process_handle, CTRL_Handle module_handle, Arch arch, void *regs, CTRL_FrameUnwindContext *frame_ctx, U64 endt_us); //- rjf: [x64] internal REGS_Reg64 *ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 gpr_reg); internal CTRL_UnwindStepResult ctrl_unwind_step__pe_x64(CTRL_Handle process_handle, CTRL_Handle module_handle, U64 module_base_vaddr, REGS_RegBlockX64 *regs, U64 endt_us); //- rjf: abstracted unwind step -internal CTRL_UnwindStepResult ctrl_unwind_step(CTRL_Handle process, CTRL_Handle module, U64 module_base_vaddr, Arch arch, void *reg_block, U64 endt_us); +internal CTRL_UnwindStepResult ctrl_unwind_step(CTRL_Handle process, CTRL_Handle module, U64 module_base_vaddr, Arch arch, void *reg_block, CTRL_FrameUnwindContext *frame_ctx, U64 endt_us); //- rjf: abstracted full unwind internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle thread, U64 endt_us); diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index a0a9295f..67ff4c22 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -1138,6 +1138,20 @@ d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count) return result; } +internal U64 +d_query_cached_cfa_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count) +{ + U64 cfa = 0; + Access *access = access_open(); + CTRL_CallStack callstack = ctrl_call_stack_from_thread(access, thread->handle, 1, 0); + if(callstack.concrete_frames_count != 0) + { + cfa = callstack.concrete_frames[unwind_count%callstack.concrete_frames_count]->cfa; + } + access_close(access); + return cfa; +} + internal U64 d_query_cached_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 rip_vaddr) { diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index 1104bd33..03b4a8f8 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -418,6 +418,7 @@ internal DI_KeyList d_push_active_dbgi_key_list(Arena *arena); //- rjf: per-run caches internal U64 d_query_cached_rip_from_thread(CTRL_Entity *thread); internal U64 d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count); +internal U64 d_query_cached_cfa_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count); internal U64 d_query_cached_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 rip_vaddr); internal E_String2NumMap *d_query_cached_locals_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff); internal E_String2NumMap *d_query_cached_member_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff); diff --git a/src/dwarf/dwarf_unwind.c b/src/dwarf/dwarf_unwind.c index c444dbc2..27c37e66 100644 --- a/src/dwarf/dwarf_unwind.c +++ b/src/dwarf/dwarf_unwind.c @@ -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); diff --git a/src/dwarf/dwarf_unwind.h b/src/dwarf/dwarf_unwind.h index bc8b2c57..afe2b294 100644 --- a/src/dwarf/dwarf_unwind.h +++ b/src/dwarf/dwarf_unwind.h @@ -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 diff --git a/src/eval/eval_interpret.c b/src/eval/eval_interpret.c index 53710f16..19f69266 100644 --- a/src/eval/eval_interpret.c +++ b/src/eval/eval_interpret.c @@ -26,10 +26,10 @@ e_select_interpret_ctx(E_InterpretCtx *ctx, RDI_Parsed *primary_rdi, U64 ip_voff RDI_LocationKind loc_kind = *(RDI_LocationKind *)(all_location_data + block->location_data_off); if(loc_kind == RDI_LocationKind_ValBytecodeStream || loc_kind == RDI_LocationKind_AddrBytecodeStream) { - U8 *bytecode_ptr = all_location_data + block->location_data_off + sizeof(RDI_LocationKind); + U8 *bytecode_ptr = all_location_data + block->location_data_off; U8 *bytecode_opl = all_location_data + all_location_data_size; U64 bytecode_size = rdi_size_from_bytecode_stream(bytecode_ptr, bytecode_opl); - String8 bytecode = str8(bytecode_ptr, bytecode_size); + String8 bytecode = str8(bytecode_ptr + sizeof(RDI_LocationKind), bytecode_size); frame_base = e_interpret(bytecode); } else if(loc_kind != RDI_LocationKind_NULL) @@ -960,6 +960,11 @@ e_interpret(String8 bytecode) // TODO: add support for pushing multiple values onto the stack NotImplemented; }break; + + case RDI_EvalOp_PushCfa: + { + nval.u64 = e_interpret_ctx->cfa; + }break; } // rjf: push diff --git a/src/eval/eval_interpret.h b/src/eval/eval_interpret.h index 590d4e4e..83a82c59 100644 --- a/src/eval/eval_interpret.h +++ b/src/eval/eval_interpret.h @@ -17,6 +17,7 @@ struct E_InterpretCtx U64 *module_base; U64 *frame_base; U64 *tls_base; + U64 cfa; }; //////////////////////////////// diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 01cfcb8d..8da90017 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -11912,6 +11912,7 @@ rd_frame(void) ctx->frame_base = push_array(scratch.arena, U64, 1); ctx->tls_base = push_array(scratch.arena, U64, 1); ctx->tls_base[0] = d_query_cached_tls_base_vaddr_from_process_root_rip(process, tls_root_vaddr, rip_vaddr); + ctx->cfa = d_query_cached_cfa_from_thread_unwind(thread, unwind_count); } e_select_interpret_ctx(interpret_ctx, eval_dbg_infos_primary->rdi, rip_voff);