From 95f4ade10d5e4c9a4345fb460363bf60b15aed0e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 19 May 2026 14:35:29 -0700 Subject: [PATCH] lift wait-for-process-memory-cache-update out of d_process_write, since that path runs on control thread now too as the general 'process handle write' abstraction - just move into the rd_eval_space_write path, since that wait was only for UI benefit anyways --- src/arch/arch.c | 2 + src/arch/arch.h | 3 +- src/dbg_engine/dbg_engine_ctrl.c | 149 +++++++++++++++++-------------- src/dbg_engine/dbg_engine_ctrl.h | 10 ++- src/dbg_engine/dbg_engine_user.c | 12 +-- src/demon/demon_core.c | 69 -------------- src/demon/demon_core.h | 20 ----- src/linux/demon/linux_demon.c | 44 ++++++--- src/linux/demon/linux_demon.h | 23 ++++- src/raddbg/raddbg_core.c | 34 +++++-- 10 files changed, 177 insertions(+), 189 deletions(-) diff --git a/src/arch/arch.c b/src/arch/arch.c index 1a31d949..f8521b21 100644 --- a/src/arch/arch.c +++ b/src/arch/arch.c @@ -14,12 +14,14 @@ arch_info_from_arch(Arch arch) #if defined(X64_H) case Arch_x64: { + local_persist U8 trap_inst_bytes[] = {0xcc}; local_persist read_only ARCH_Info info = { .reg_block_size = sizeof(X64_RegBlock), .instruction_pointer_reg_code = X64_RegCode_rip, .stack_pointer_reg_code = X64_RegCode_rsp, .reg_code_count = X64_RegCode_COUNT, + .trap_instruction = {trap_inst_bytes, sizeof(trap_inst_bytes)}, .reg_code_rng_table = x64_reg_code_rng_table, .reg_code_name_table = x64_reg_code_name_table, .reg_code_base_table = x64_reg_code_base_table, diff --git a/src/arch/arch.h b/src/arch/arch.h index 824cfe7a..fa1b1e64 100644 --- a/src/arch/arch.h +++ b/src/arch/arch.h @@ -16,6 +16,7 @@ struct ARCH_Info ARCH_RegCode instruction_pointer_reg_code; ARCH_RegCode stack_pointer_reg_code; U16 reg_code_count; + String8 trap_instruction; Rng1U16 *reg_code_rng_table; String8 *reg_code_name_table; U8 *reg_code_base_table; @@ -29,7 +30,7 @@ global read_only Rng1U16 arch_reg_code_rng_nil = {0}; global read_only String8 arch_reg_code_name_nil = {0}; global read_only U8 arch_reg_code_u8_nil = 0; global read_only B8 arch_reg_code_b8_nil = 0; -global read_only ARCH_Info arch_info_nil = {0, 0, 0, 0, &arch_reg_code_rng_nil, &arch_reg_code_name_nil, &arch_reg_code_u8_nil, &arch_reg_code_b8_nil}; +global read_only ARCH_Info arch_info_nil = {0, 0, 0, 0, {0}, &arch_reg_code_rng_nil, &arch_reg_code_name_nil, &arch_reg_code_u8_nil, &arch_reg_code_b8_nil}; //////////////////////////////// //~ rjf: Abstracted Architecture Functions diff --git a/src/dbg_engine/dbg_engine_ctrl.c b/src/dbg_engine/dbg_engine_ctrl.c index 60ed51e4..6c1d7947 100644 --- a/src/dbg_engine/dbg_engine_ctrl.c +++ b/src/dbg_engine/dbg_engine_ctrl.c @@ -845,7 +845,7 @@ internal D_Entity * d_module_from_thread_candidates(D_Entity *thread, D_EntityList *candidates) { D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); - U64 thread_rip_vaddr = d_rip_from_thread(thread->handle); + U64 thread_rip_vaddr = d_cached_ip_from_thread(thread->handle); D_Entity *src_module = d_module_from_process_vaddr(process, thread_rip_vaddr); D_Entity *module = &d_entity_nil; for(D_EntityNode *n = candidates->first; n != 0; n = n->next) @@ -1357,7 +1357,7 @@ d_entity_store_apply_events(D_EntityCtxRWStore *store, D_EventList *list) } thread->stack_base = event->stack_base; } - //d_rip_from_thread(&store->ctx, event->entity); + //d_cached_ip_from_thread(&store->ctx, event->entity); }break; case D_EventKind_EndThread: { @@ -1595,10 +1595,46 @@ d_thread_write_reg_block(D_Handle thread, void *block) return result; } +internal U64 +d_ip_from_thread(D_Handle handle) +{ + U64 result = 0; + Temp scratch = scratch_begin(0, 0); + D_Entity *thread = d_entity_from_handle(handle); + Arch arch = thread->arch; + ARCH_Info *arch_info = arch_info_from_arch(arch); + U64 reg_block_size = arch_info->reg_block_size; + void *reg_block = push_array(scratch.arena, U8, reg_block_size); + if(d_thread_read_reg_block(handle, reg_block)) + { + result = arch_ip_from_reg_block(arch_info, reg_block); + } + scratch_end(scratch); + return result; +} + +internal U64 +d_sp_from_thread(D_Handle handle) +{ + U64 result = 0; + Temp scratch = scratch_begin(0, 0); + D_Entity *thread = d_entity_from_handle(handle); + Arch arch = thread->arch; + ARCH_Info *arch_info = arch_info_from_arch(arch); + U64 reg_block_size = arch_info->reg_block_size; + void *reg_block = push_array(scratch.arena, U8, reg_block_size); + if(d_thread_read_reg_block(handle, reg_block)) + { + result = arch_sp_from_reg_block(arch_info, reg_block); + } + scratch_end(scratch); + return result; +} + //- rjf: thread register cache reading internal void * -d_reg_block_from_thread(Arena *arena, D_Handle handle) +d_cached_reg_block_from_thread(Arena *arena, D_Handle handle) { D_ThreadRegCache *cache = &d_ctrl_state->thread_reg_cache; D_Entity *thread_entity = d_entity_from_handle(handle); @@ -1658,7 +1694,7 @@ d_reg_block_from_thread(Arena *arena, D_Handle handle) } internal U64 -d_tls_root_vaddr_from_thread(D_Handle handle) +d_cached_tls_root_vaddr_from_thread(D_Handle handle) { DMN_Handle handle_dmn = d_dmn_from_handle(handle); U64 result = dmn_tls_root_vaddr_from_thread(handle_dmn); @@ -1666,26 +1702,26 @@ d_tls_root_vaddr_from_thread(D_Handle handle) } internal U64 -d_rip_from_thread(D_Handle handle) +d_cached_ip_from_thread(D_Handle handle) { Temp scratch = scratch_begin(0, 0); D_Entity *thread_entity = d_entity_from_handle(handle); Arch arch = thread_entity->arch; ARCH_Info *arch_info = arch_info_from_arch(arch); - void *block = d_reg_block_from_thread(scratch.arena, handle); + void *block = d_cached_reg_block_from_thread(scratch.arena, handle); U64 result = arch_ip_from_reg_block(arch_info, block); scratch_end(scratch); return result; } internal U64 -d_rsp_from_thread(D_Handle handle) +d_cached_sp_from_thread(D_Handle handle) { Temp scratch = scratch_begin(0, 0); D_Entity *thread_entity = d_entity_from_handle(handle); Arch arch = thread_entity->arch; ARCH_Info *arch_info = arch_info_from_arch(arch); - void *block = d_reg_block_from_thread(scratch.arena, handle); + void *block = d_cached_reg_block_from_thread(scratch.arena, handle); U64 result = arch_sp_from_reg_block(arch_info, block); scratch_end(scratch); return result; @@ -2978,7 +3014,7 @@ d_unwind_from_thread(Arena *arena, D_Handle thread, U64 endt_us) U64 arch_reg_block_size = arch_info->reg_block_size; //- rjf: grab initial register block - void *regs_block = d_reg_block_from_thread(scratch.arena, thread); + void *regs_block = d_cached_reg_block_from_thread(scratch.arena, thread); B32 regs_block_good = (arch != Arch_Null && regs_block != 0); //- rjf: loop & unwind @@ -3572,7 +3608,7 @@ d_ctrl_thread__entry_point(void *p) for EachIndex(idx, threads.count) { Temp scratch = scratch_begin(0, 0); - d_reg_block_from_thread(scratch.arena, threads.v[idx]->handle); + d_cached_reg_block_from_thread(scratch.arena, threads.v[idx]->handle); scratch_end(scratch); } } @@ -4715,7 +4751,7 @@ d_ctrl_eval_space_read(E_Space space, void *out, E_SpaceRangeInfo *out_range_inf Temp scratch = scratch_begin(0, 0); ARCH_Info *arch_info = arch_info_from_arch(entity->arch); U64 regs_size = arch_info->reg_block_size; - void *regs = d_reg_block_from_thread(scratch.arena, entity->handle); + void *regs = d_cached_reg_block_from_thread(scratch.arena, entity->handle); Rng1U64 legal_range = r1u64(0, regs_size); Rng1U64 read_range = intersect_1u64(legal_range, range); U64 read_size = dim_1u64(read_range); @@ -4737,14 +4773,13 @@ d_ctrl_thread__eval_scope_begin(Arena *arena, D_BreakpointList *user_bps, D_Enti ProfBeginFunction(); D_EntityCtx *entity_ctx = &d_ctrl_state->ctrl_thread_entity_store->ctx; D_EvalScope *scope = push_array(arena, D_EvalScope, 1); - DMN_Handle thread_dmn = d_dmn_from_handle(thread->handle); scope->access = access_open(); ////////////////////////////// //- rjf: unpack thread // Arch arch = thread->arch; - U64 thread_rip_vaddr = dmn_rip_from_thread(thread_dmn); + U64 thread_rip_vaddr = d_ip_from_thread(thread->handle); D_Entity *process = d_process_from_entity(thread); D_Entity *module = d_module_from_process_vaddr(process, thread_rip_vaddr); U64 thread_rip_voff = d_voff_from_vaddr(module, thread_rip_vaddr); @@ -5709,7 +5744,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) // threads, because otherwise, their stack pointer may change, if single-stepping // causes e.g. entrance into a function via a call instruction. // - U64 sp_check_value = dmn_rsp_from_thread(target_thread_dmn); + U64 sp_check_value = d_sp_from_thread(target_thread); log_infof("sp_check_value := 0x%I64x\n", sp_check_value); ////////////////////////////// @@ -5740,7 +5775,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) for(D_Entity *thread = process->first; thread != &d_entity_nil; thread = thread->next) { if(thread->kind != D_EntityKind_Thread) { continue; } - U64 rip = dmn_rip_from_thread(d_dmn_from_handle(thread->handle)); + U64 rip = d_ip_from_thread(thread->handle); // rjf: determine if thread is frozen B32 thread_is_frozen = thread->is_frozen; @@ -5788,27 +5823,26 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) node != 0; node = node->next) { - DMN_Handle thread = node->v; - U64 thread_pre_rip = dmn_rip_from_thread(thread); + D_Handle thread = d_handle_from_dmn(D_MachineID_Local, node->v); + U64 thread_pre_rip = d_ip_from_thread(thread); U64 thread_post_rip = thread_pre_rip; for(B32 done = 0; !done;) { - log_infof("single_step_stuck_thread([0x%I64x])\n", thread.u64[0]); DMN_RunCtrls run_ctrls = {0}; run_ctrls.run_entities_are_unfrozen = 1; - run_ctrls.run_entities = &thread; + run_ctrls.run_entities = &node->v; run_ctrls.run_entity_count = 1; if(thread_post_rip == thread_pre_rip) { - run_ctrls.single_step_thread = thread; + run_ctrls.single_step_thread = node->v; } DMN_Event *event = d_ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); - thread_post_rip = dmn_rip_from_thread(thread); + thread_post_rip = d_ip_from_thread(thread); switch(event->kind) { default:{}break; case DMN_EventKind_ExitThread: - if(dmn_handle_match(event->thread, thread)) + if(d_handle_match(d_handle_from_dmn(D_MachineID_Local, event->thread), thread)) { stop_cause = D_EventCause_Error; goto stop; @@ -6273,7 +6307,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) D_Entity *thread = d_entity_from_handle(d_handle_from_dmn(D_MachineID_Local, event->thread)); D_Entity *process = d_entity_from_handle(d_handle_from_dmn(D_MachineID_Local, event->process)); Arch arch = thread->arch; - U64 thread_rip_vaddr = dmn_rip_from_thread(event->thread); + U64 thread_rip_vaddr = d_ip_from_thread(thread->handle); D_Entity *module = d_module_from_process_vaddr(process, thread_rip_vaddr); ////////////////////////// @@ -6441,21 +6475,21 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) D_EventCause cond_bp_single_step_stop_cause = D_EventCause_Null; if(hit_conditional_bp_but_filtered) LogInfoNamedBlockF("conditional_bp_hit_single_step") { - DMN_Handle thread = event->thread; - U64 thread_pre_rip = dmn_rip_from_thread(thread); + D_Handle thread = d_handle_from_dmn(D_MachineID_Local, event->thread); + U64 thread_pre_rip = d_ip_from_thread(thread); U64 thread_post_rip = thread_pre_rip; for(B32 single_step_done = 0; !single_step_done;) { DMN_RunCtrls single_step_ctrls = {0}; single_step_ctrls.run_entities_are_unfrozen = 1; - single_step_ctrls.run_entities = &thread; + single_step_ctrls.run_entities = &event->thread; single_step_ctrls.run_entity_count = 1; if(thread_post_rip == thread_pre_rip) { - single_step_ctrls.single_step_thread = thread; + single_step_ctrls.single_step_thread = event->thread; } DMN_Event *event = d_ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &single_step_ctrls, 0); - thread_post_rip = dmn_rip_from_thread(thread); + thread_post_rip = d_ip_from_thread(thread); switch(event->kind) { default:{}break; @@ -6471,7 +6505,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) }break; case DMN_EventKind_SingleStep: { - single_step_done = dmn_handle_match(event->thread, thread); + single_step_done = d_handle_match(d_handle_from_dmn(D_MachineID_Local, event->thread), thread); cond_bp_single_step_stop_cause = d_event_cause_from_dmn_event_kind(event->kind); }break; } @@ -6519,7 +6553,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) B32 stack_pointer_matches = 0; if(use_trap_net_logic) { - U64 sp = dmn_rsp_from_thread(d_dmn_from_handle(target_thread)); + U64 sp = d_sp_from_thread(target_thread); stack_pointer_matches = (sp == sp_check_value); } @@ -6530,7 +6564,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) { if(hit_trap_flags & D_TrapFlag_SingleStepAfterHit) LogInfoNamedBlockF("trap_net__single_step_after_hit") { - U64 thread_pre_rip = dmn_rip_from_thread(d_dmn_from_handle(target_thread)); + U64 thread_pre_rip = d_ip_from_thread(target_thread); U64 thread_post_rip = thread_pre_rip; for(B32 single_step_done = 0; single_step_done == 0;) { @@ -6543,7 +6577,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) single_step_ctrls.single_step_thread = target_thread_dmn; } DMN_Event *event = d_ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &single_step_ctrls, 0); - thread_post_rip = dmn_rip_from_thread(target_thread_dmn); + thread_post_rip = d_ip_from_thread(target_thread); switch(event->kind) { default:{}break; @@ -6576,7 +6610,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) { // rjf: setup spoof mode begin_spoof_mode = 1; - U64 spoof_sp = dmn_rsp_from_thread(target_thread_dmn); + U64 spoof_sp = d_sp_from_thread(target_thread); spoof_mode = 1; spoof.process = target_process; spoof.thread = target_thread; @@ -6594,7 +6628,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) if(stack_pointer_matches) LogInfoNamedBlockF("trap_net__save_sp") { save_stack_pointer = 1; - sp_check_value = dmn_rsp_from_thread(target_thread_dmn); + sp_check_value = d_sp_from_thread(target_thread); log_infof("sp_check_value = 0x%I64x\n", sp_check_value); } } @@ -6625,21 +6659,21 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) D_EventCause step_past_trap_net_stop_cause = D_EventCause_Null; if(step_past_trap_net) LogInfoNamedBlockF("trap_net__single_step_past_trap_net") { - DMN_Handle thread = event->thread; - U64 thread_pre_rip = dmn_rip_from_thread(thread); + D_Handle thread = d_handle_from_dmn(D_MachineID_Local, event->thread); + U64 thread_pre_rip = d_ip_from_thread(thread); U64 thread_post_rip = thread_pre_rip; for(B32 single_step_done = 0; single_step_done == 0;) { DMN_RunCtrls single_step_ctrls = {0}; single_step_ctrls.run_entities_are_unfrozen = 1; - single_step_ctrls.run_entities = &thread; + single_step_ctrls.run_entities = &event->thread; single_step_ctrls.run_entity_count = 1; if(thread_post_rip == thread_pre_rip) { - single_step_ctrls.single_step_thread = thread; + single_step_ctrls.single_step_thread = event->thread; } DMN_Event *event = d_ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &single_step_ctrls, 0); - thread_post_rip = dmn_rip_from_thread(thread); + thread_post_rip = d_ip_from_thread(thread); switch(event->kind) { default:{}break; @@ -6654,7 +6688,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) }break; case DMN_EventKind_SingleStep: { - single_step_done = dmn_handle_match(event->thread, thread); + single_step_done = d_handle_match(d_handle_from_dmn(D_MachineID_Local, event->thread), thread); step_past_trap_net_stop_cause = d_event_cause_from_dmn_event_kind(event->kind); }break; } @@ -6751,26 +6785,27 @@ d_ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) } //- rjf: single step - DMN_Handle thread = d_dmn_from_handle(msg->entity); - B32 thread_is_valid = !dmn_handle_match(thread, dmn_handle_zero()); + D_Handle thread = msg->entity; + B32 thread_is_valid = !d_handle_match(thread, d_handle_zero()); DMN_Event *stop_event = 0; D_EventCause stop_cause = D_EventCause_Null; if(thread_is_valid) { - U64 thread_pre_rip = dmn_rip_from_thread(thread); + U64 thread_pre_rip = d_ip_from_thread(thread); U64 thread_post_rip = thread_pre_rip; for(B32 done = 0; done == 0;) { + DMN_Handle thread_dmn = d_dmn_from_handle(thread); DMN_RunCtrls run_ctrls = {0}; run_ctrls.run_entities_are_unfrozen = 1; - run_ctrls.run_entities = &thread; + run_ctrls.run_entities = &thread_dmn; run_ctrls.run_entity_count = 1; if(thread_post_rip == thread_pre_rip) { - run_ctrls.single_step_thread = d_dmn_from_handle(msg->entity); + run_ctrls.single_step_thread = thread_dmn; } DMN_Event *event = d_ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); - thread_post_rip = dmn_rip_from_thread(d_dmn_from_handle(msg->entity)); + thread_post_rip = d_ip_from_thread(thread); switch(event->kind) { default:{}break; @@ -6886,32 +6921,10 @@ d_process_write(D_Handle process, Rng1U64 range, void *src) case D_ControllerKind_Demon: { result = dmn_process_write(d_dmn_from_handle(process), range, src); - - //- rjf: success -> bump generation if(result) { ins_atomic_u64_inc_eval(&d_ctrl_state->mem_gen); } - - //- rjf: success -> wait for cache updates, for small regions - prefer relatively seamless - // writes within calling frame's "view" of the memory, at the expense of a small amount of - // time. - if(result) - { - U64 endt_us = now_time_us()+10000; - U64 page_size = get_system_info()->page_size; // TODO(rjf): @page_size_from_process - Rng1U64 page_range = r1u64(range.min/page_size, (range.max+page_size-1)/page_size); - for EachInRange(page_idx, page_range) - { - Temp scratch = scratch_begin(0, 0); - D_ProcessMemorySlice slice = d_process_memory_slice_from_vaddr_range(scratch.arena, process, r1u64(page_idx*page_size, (page_idx+1)*page_size), 1, endt_us); - scratch_end(scratch); - if(!slice.stale || now_time_us() >= endt_us) - { - break; - } - } - } }break; case D_ControllerKind_Dump: diff --git a/src/dbg_engine/dbg_engine_ctrl.h b/src/dbg_engine/dbg_engine_ctrl.h index 4dc4090c..7463567c 100644 --- a/src/dbg_engine/dbg_engine_ctrl.h +++ b/src/dbg_engine/dbg_engine_ctrl.h @@ -546,12 +546,14 @@ internal void d_set_wakeup_hook(D_WakeupFunctionType *wakeup_hook); //- rjf: thread handle read/write internal B32 d_thread_read_reg_block(D_Handle handle, void *reg_block); internal B32 d_thread_write_reg_block(D_Handle thread, void *reg_block); +internal U64 d_ip_from_thread(D_Handle handle); +internal U64 d_sp_from_thread(D_Handle handle); //- rjf: thread register cache reading -internal void *d_reg_block_from_thread(Arena *arena, D_Handle handle); -internal U64 d_tls_root_vaddr_from_thread(D_Handle handle); -internal U64 d_rip_from_thread(D_Handle handle); -internal U64 d_rsp_from_thread(D_Handle handle); +internal void *d_cached_reg_block_from_thread(Arena *arena, D_Handle handle); +internal U64 d_cached_tls_root_vaddr_from_thread(D_Handle handle); +internal U64 d_cached_ip_from_thread(D_Handle handle); +internal U64 d_cached_sp_from_thread(D_Handle handle); //////////////////////////////// //~ rjf: Module Image Info Functions diff --git a/src/dbg_engine/dbg_engine_user.c b/src/dbg_engine/dbg_engine_user.c index 1744db1c..13ac7665 100644 --- a/src/dbg_engine/dbg_engine_user.c +++ b/src/dbg_engine/dbg_engine_user.c @@ -297,7 +297,7 @@ d_trap_net_from_thread__step_over_inst(Arena *arena, D_Entity *thread) // rjf: thread => unpacked info D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); Arch arch = thread->arch; - U64 ip_vaddr = d_rip_from_thread(thread->handle); + U64 ip_vaddr = d_cached_ip_from_thread(thread->handle); // rjf: ip => machine code String8 machine_code = {0}; @@ -336,7 +336,7 @@ d_trap_net_from_thread__step_over_line(Arena *arena, D_Entity *thread) // rjf: thread => info Arch arch = thread->arch; - U64 ip_vaddr = d_rip_from_thread(thread->handle); + U64 ip_vaddr = d_cached_ip_from_thread(thread->handle); D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); D_Entity *module = d_module_from_process_vaddr(process, ip_vaddr); DI_Key dbgi_key = d_dbgi_key_from_module(module); @@ -549,7 +549,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, D_Entity *thread) // rjf: thread => info Arch arch = thread->arch; - U64 ip_vaddr = d_rip_from_thread(thread->handle); + U64 ip_vaddr = d_cached_ip_from_thread(thread->handle); D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); D_Entity *module = d_module_from_process_vaddr(process, ip_vaddr); DI_Key dbgi_key = d_dbgi_key_from_module(module); @@ -753,7 +753,7 @@ d_trap_net_from_thread__step_out_scope(Arena *arena, D_Entity *thread) // rjf: unpack thread Arch arch = thread->arch; - U64 ip_vaddr = d_rip_from_thread(thread->handle); + U64 ip_vaddr = d_cached_ip_from_thread(thread->handle); D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); D_Entity *module = d_module_from_process_vaddr(process, ip_vaddr); DI_Key dbgi_key = d_dbgi_key_from_module(module); @@ -1327,7 +1327,7 @@ d_query_cached_rip_from_thread_unwind(D_Entity *thread, U64 unwind_count) U64 result = 0; if(unwind_count == 0) { - result = d_rip_from_thread(thread->handle); + result = d_cached_ip_from_thread(thread->handle); } else { @@ -1977,7 +1977,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P D_Entity *thread = d_entity_from_handle(params->thread); ARCH_Info *arch_info = arch_info_from_arch(thread->arch); U64 vaddr = params->vaddr; - void *block = d_reg_block_from_thread(scratch.arena, thread->handle); + void *block = d_cached_reg_block_from_thread(scratch.arena, thread->handle); arch_reg_block_write_ip(arch_info, block, vaddr); B32 result = d_thread_write_reg_block(thread->handle, block); (void)result; diff --git a/src/demon/demon_core.c b/src/demon/demon_core.c index 756f8068..4fd59c89 100644 --- a/src/demon/demon_core.c +++ b/src/demon/demon_core.c @@ -121,72 +121,3 @@ dmn_event_list_push(Arena *arena, DMN_EventList *list) DMN_Event *result = &n->v; return result; } - -//////////////////////////////// -//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once) - -internal U64 -dmn_rip_from_thread(DMN_Handle thread) -{ - U64 result = 0; - Temp scratch = scratch_begin(0, 0); - { - Arch arch = dmn_arch_from_thread(thread); - ARCH_Info *arch_info = arch_info_from_arch(arch); - U64 reg_block_size = arch_info->reg_block_size; - void *reg_block = push_array(scratch.arena, U8, reg_block_size); - dmn_thread_read_reg_block(thread, reg_block); - result = arch_ip_from_reg_block(arch_info, reg_block); - } - scratch_end(scratch); - return result; -} - -internal U64 -dmn_rsp_from_thread(DMN_Handle thread) -{ - U64 result = 0; - Temp scratch = scratch_begin(0, 0); - { - Arch arch = dmn_arch_from_thread(thread); - ARCH_Info *arch_info = arch_info_from_arch(arch); - U64 reg_block_size = arch_info->reg_block_size; - void *reg_block = push_array(scratch.arena, U8, reg_block_size); - dmn_thread_read_reg_block(thread, reg_block); - result = arch_sp_from_reg_block(arch_info, reg_block); - } - scratch_end(scratch); - return result; -} - -//////////////////////////////// -//~ rjf: Process Reading Helper Functions (Helpers, Implemented Once) - -internal String8 -dmn_get_trap_inst(void) -{ -#if ARCH_X64 - local_persist U8 inst[] = { 0xcc }; -#else -# error "trap instruction is not defined for this arch" -#endif - return str8_array_fixed(inst); -} - -internal DMN_ActiveTrap * -dmn_set_trap(Arena *arena, DMN_Trap *trap) -{ - String8 trap_inst = dmn_get_trap_inst(); - U8 *swap_bytes = push_array(arena, U8, trap_inst.size); - B32 good_read = dmn_process_read(trap->process, r1u64(trap->vaddr, trap->vaddr + trap_inst.size), swap_bytes); - B32 good_write = 0; - if(good_read) - { - good_write = dmn_process_write(trap->process, r1u64(trap->vaddr, trap->vaddr + trap_inst.size), trap_inst.str); - } - DMN_ActiveTrap *result = push_array(arena, DMN_ActiveTrap, 1); - result->good = (good_read && good_write); - result->trap = trap; - result->swap_bytes = str8(swap_bytes, trap_inst.size); - return result; -} diff --git a/src/demon/demon_core.h b/src/demon/demon_core.h index fa4ed70d..802766c4 100644 --- a/src/demon/demon_core.h +++ b/src/demon/demon_core.h @@ -152,15 +152,6 @@ struct DMN_TrapChunkList U64 trap_count; }; -typedef struct DMN_ActiveTrap DMN_ActiveTrap; -struct DMN_ActiveTrap -{ - DMN_ActiveTrap *next; - B32 good; - DMN_Trap *trap; - String8 swap_bytes; -}; - typedef struct DMN_RunCtrls DMN_RunCtrls; struct DMN_RunCtrls { @@ -210,12 +201,6 @@ internal DMN_HandleArray dmn_handle_array_copy(Arena *arena, DMN_HandleArray *sr //- rjf: event list building internal DMN_Event *dmn_event_list_push(Arena *arena, DMN_EventList *list); -//////////////////////////////// -//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once) - -internal U64 dmn_rip_from_thread(DMN_Handle thread); -internal U64 dmn_rsp_from_thread(DMN_Handle thread); - //////////////////////////////// //~ rjf: Process Reading Helper Functions (Helpers, Implemented Once) @@ -273,9 +258,4 @@ internal void dmn_process_iter_begin(DMN_ProcessIter *iter); internal B32 dmn_process_iter_next(Arena *arena, DMN_ProcessIter *iter, DMN_ProcessInfo *info_out); internal void dmn_process_iter_end(DMN_ProcessIter *iter); -//- arch trap -internal String8 dmn_get_trap_inst(void); - -internal DMN_ActiveTrap * dmn_set_trap(Arena *arena, DMN_Trap *trap); - #endif // DEMON_CORE_H diff --git a/src/linux/demon/linux_demon.c b/src/linux/demon/linux_demon.c index 1f187af9..9a16e3aa 100644 --- a/src/linux/demon/linux_demon.c +++ b/src/linux/demon/linux_demon.c @@ -292,6 +292,28 @@ lnx_dmn_process_from_pid(pid_t pid) return hash_table_search_u64_raw(lnx_dmn_state->pid_ht, pid); } +//////////////////////////////// +//~ rjf: Trap Setting + +internal LNX_DMN_ActiveTrap * +lnx_dmn_set_trap(Arena *arena, DMN_Trap *trap) +{ + ARCH_Info *arch = arch_info_from_arch(Arch_CURRENT); + String8 trap_inst = arch->trap_instruction; + U8 *swap_bytes = push_array(arena, U8, trap_inst.size); + B32 good_read = dmn_process_read(trap->process, r1u64(trap->vaddr, trap->vaddr + trap_inst.size), swap_bytes); + B32 good_write = 0; + if(good_read) + { + good_write = dmn_process_write(trap->process, r1u64(trap->vaddr, trap->vaddr + trap_inst.size), trap_inst.str); + } + LNX_DMN_ActiveTrap *result = push_array(arena, LNX_DMN_ActiveTrap, 1); + result->good = (good_read && good_write); + result->trap = trap; + result->swap_bytes = str8(swap_bytes, trap_inst.size); + return result; +} + internal Rng1U64 lnx_dmn_compute_image_vrange(int memory_fd, ELF_Class elf_class, U64 rebase, U64 e_phaddr, U64 e_phentsize, U64 e_phnum) { @@ -976,7 +998,7 @@ lnx_dmn_process_ctx_clone(LNX_DMN_Process *new_owner, LNX_DMN_ProcessCtx *ctx) } // clone probe traps - for EachNode(src, DMN_ActiveTrap, ctx->first_probe_trap) + for EachNode(src, LNX_DMN_ActiveTrap, ctx->first_probe_trap) { DMN_Trap *src_trap = src->trap; DMN_Trap *dst_trap = push_array(result->arena, DMN_Trap, 1); @@ -986,7 +1008,7 @@ lnx_dmn_process_ctx_clone(LNX_DMN_Process *new_owner, LNX_DMN_ProcessCtx *ctx) dst_trap->flags = src_trap->flags; dst_trap->size = src_trap->size; - DMN_ActiveTrap *dst = push_array(result->arena, DMN_ActiveTrap, 1); + LNX_DMN_ActiveTrap *dst = push_array(result->arena, LNX_DMN_ActiveTrap, 1); dst->trap = dst_trap; dst->swap_bytes = str8_copy(result->arena, src->swap_bytes); @@ -1112,7 +1134,7 @@ lnx_dmn_process_trap_probes(LNX_DMN_Process *process) trap->vaddr = process->ctx->probes[i]->pc; trap->id = i; - DMN_ActiveTrap *active_trap = dmn_set_trap(process->ctx->arena, trap); + LNX_DMN_ActiveTrap *active_trap = lnx_dmn_set_trap(process->ctx->arena, trap); SLLQueuePush(process->ctx->first_probe_trap, process->ctx->last_probe_trap, active_trap); if(BUILD_DEBUG && process->ctx->arch == Arch_x64) @@ -1966,17 +1988,17 @@ lnx_dmn_event_unload_module(Arena *arena, DMN_EventList *events, LNX_DMN_Process } internal void -lnx_dmn_event_breakpoint(Arena *arena, DMN_EventList *events, DMN_ActiveTrap *user_traps, pid_t tid) +lnx_dmn_event_breakpoint(Arena *arena, DMN_EventList *events, LNX_DMN_ActiveTrap *user_traps, pid_t tid) { LNX_DMN_Thread *thread = lnx_dmn_thread_from_pid(tid); LNX_DMN_Process *process = thread->process; U64 ip = lnx_dmn_thread_read_ip(thread); // is this user trap? - DMN_ActiveTrap *hit_user_trap = 0; + LNX_DMN_ActiveTrap *hit_user_trap = 0; { DMN_Handle process_handle = lnx_dmn_handle_from_process(process); - for EachNode(active_trap, DMN_ActiveTrap, user_traps) + for EachNode(active_trap, LNX_DMN_ActiveTrap, user_traps) { if(MemoryCompare(&active_trap->trap->process, &process_handle, sizeof(DMN_Handle)) == 0) { @@ -1993,7 +2015,7 @@ lnx_dmn_event_breakpoint(Arena *arena, DMN_EventList *events, DMN_ActiveTrap *us LNX_DMN_ProbeType probe_type = LNX_DMN_ProbeType_Null; if(hit_user_trap == 0) { - for EachNode(active_trap, DMN_ActiveTrap, process->ctx->first_probe_trap) + for EachNode(active_trap, LNX_DMN_ActiveTrap, process->ctx->first_probe_trap) { if(active_trap->trap->vaddr == ip-1) { @@ -2397,7 +2419,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) if(lnx_dmn_state->process_count > 0) { // write traps to memory - DMN_ActiveTrap *active_trap_first = 0, *active_trap_last = 0; + LNX_DMN_ActiveTrap *active_trap_first = 0, *active_trap_last = 0; { HashTable *process_ht = hash_table_init(scratch.arena, lnx_dmn_state->process_count); for EachNode(n, DMN_TrapChunkNode, ctrls->traps.first) @@ -2416,7 +2438,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) } // TODO: ctrl sends down duplicate traps - DMN_ActiveTrap *is_set = hash_table_search_u64_raw(active_trap_ht, trap->vaddr); + LNX_DMN_ActiveTrap *is_set = hash_table_search_u64_raw(active_trap_ht, trap->vaddr); if(is_set) { continue; } // TODO: ctrl sends down traps for exited process @@ -2424,7 +2446,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) if(!process) { continue; } // trap instruction - DMN_ActiveTrap *active_trap = dmn_set_trap(scratch.arena, trap); + LNX_DMN_ActiveTrap *active_trap = lnx_dmn_set_trap(scratch.arena, trap); // add trap to the active list SLLQueuePush(active_trap_first, active_trap_last, active_trap); @@ -2854,7 +2876,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) } // restore original instruction bytes - for EachNode(active_trap, DMN_ActiveTrap, active_trap_first) + for EachNode(active_trap, LNX_DMN_ActiveTrap, active_trap_first) { // skip process that exited during the wait LNX_DMN_Process *process = lnx_dmn_process_from_handle(active_trap->trap->process); diff --git a/src/linux/demon/linux_demon.h b/src/linux/demon/linux_demon.h index 128b34f1..a84a573c 100644 --- a/src/linux/demon/linux_demon.h +++ b/src/linux/demon/linux_demon.h @@ -285,8 +285,8 @@ typedef struct LNX_DMN_ProcessCtx ELF_Class dl_class; HashTable *loaded_modules_ht; LNX_DMN_Probe **probes; - DMN_ActiveTrap *first_probe_trap; - DMN_ActiveTrap *last_probe_trap; + LNX_DMN_ActiveTrap *first_probe_trap; + LNX_DMN_ActiveTrap *last_probe_trap; LNX_DMN_Module *first_module; LNX_DMN_Module *last_module; U64 module_count; @@ -331,6 +331,18 @@ typedef struct LNX_DMN_EntityList LNX_DMN_EntityNode *last; } LNX_DMN_EntityList; +//////////////////////////////// +//~ rjf: Active Trap Data Structure + +typedef struct LNX_DMN_ActiveTrap LNX_DMN_ActiveTrap; +struct LNX_DMN_ActiveTrap +{ + LNX_DMN_ActiveTrap *next; + B32 good; + DMN_Trap *trap; + String8 swap_bytes; +}; + //////////////////////////////// //~ Global State @@ -389,6 +401,11 @@ internal String8 lnx_dmn_read_string(Arena *arena, int memory_fd, U64 base_vaddr #define lnx_dmn_read_struct(fd, vaddr, ptr) lnx_dmn_read((fd), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr)) #define lnx_dmn_write_struct(fd, vaddr, ptr) lnx_dmn_write((fd), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr)) +//////////////////////////////// +//~ rjf: Trap Setting + +internal LNX_DMN_ActiveTrap *lnx_dmn_set_trap(Arena *arena, DMN_Trap *trap); + //////////////////////////////// //~ ELF/GNU info @@ -491,7 +508,7 @@ internal LNX_DMN_Process * lnx_dmn_event_create_process(Arena *arena, DMN_EventL internal void lnx_dmn_event_exit_process(Arena *arena, DMN_EventList *events, pid_t pid); internal void lnx_dmn_event_load_module(Arena *arena, DMN_EventList *events, LNX_DMN_Thread *thread, U64 name_space_id, U64 new_link_map_vaddr); internal void lnx_dmn_event_unload_module(Arena *arena, DMN_EventList *events, LNX_DMN_Process *process, U64 rdebug_vaddr); -internal void lnx_dmn_event_breakpoint(Arena *arena, DMN_EventList *events, DMN_ActiveTrap *user_traps, pid_t tid); +internal void lnx_dmn_event_breakpoint(Arena *arena, DMN_EventList *events, LNX_DMN_ActiveTrap *user_traps, pid_t tid); internal void lnx_dmn_event_data_breakpoint(Arena *arena, DMN_EventList *events, pid_t tid); internal void lnx_dmn_event_halt(Arena *arena, DMN_EventList *events); internal void lnx_dmn_event_single_step(Arena *arena, DMN_EventList *events, pid_t tid); diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index f8dd89a9..ee659835 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -797,7 +797,7 @@ rd_eval_space_read(E_Space space, void *out, E_SpaceRangeInfo *out_range_info, R void *regs_block = 0; if(e_interpret_ctx->reg_unwind_count == 0) { - regs_block = d_reg_block_from_thread(scratch.arena, entity->handle); + regs_block = d_cached_reg_block_from_thread(scratch.arena, entity->handle); } else { @@ -1037,6 +1037,26 @@ rd_eval_space_write(E_Space space, void *in, Rng1U64 range) case D_EntityKind_Process: { result = d_process_write(entity->handle, range, in); + + //- rjf: success -> wait for cache updates, for small regions - prefer relatively seamless + // writes within calling frame's "view" of the memory, at the expense of a small amount of + // time. + if(result) + { + U64 endt_us = now_time_us()+10000; + U64 page_size = get_system_info()->page_size; // TODO(rjf): @page_size_from_process + Rng1U64 page_range = r1u64(range.min/page_size, (range.max+page_size-1)/page_size); + for EachInRange(page_idx, page_range) + { + Temp scratch = scratch_begin(0, 0); + D_ProcessMemorySlice slice = d_process_memory_slice_from_vaddr_range(scratch.arena, entity->handle, r1u64(page_idx*page_size, (page_idx+1)*page_size), 1, endt_us); + scratch_end(scratch); + if(!slice.stale || now_time_us() >= endt_us) + { + break; + } + } + } }break; case D_EntityKind_Thread: { @@ -1046,7 +1066,7 @@ rd_eval_space_write(E_Space space, void *in, Rng1U64 range) Rng1U64 legal_range = r1u64(0, regs_size); Rng1U64 write_range = intersect_1u64(legal_range, range); U64 write_size = dim_1u64(write_range); - void *new_regs = d_reg_block_from_thread(scratch.arena, entity->handle); + void *new_regs = d_cached_reg_block_from_thread(scratch.arena, entity->handle); MemoryCopy((U8 *)new_regs + write_range.min, in, write_size); result = d_thread_write_reg_block(entity->handle, new_regs); scratch_end(scratch); @@ -9847,7 +9867,7 @@ rd_gather_auto_exprs(Arena *arena) //- rjf: unpack thread / module / debug info / lines ARCH_Info *arch_info = arch_info_from_arch(thread->arch); D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); - U64 thread_ip_vaddr = d_rip_from_thread(thread_handle); + U64 thread_ip_vaddr = d_cached_ip_from_thread(thread_handle); D_Entity *module = d_module_from_process_vaddr(process, thread_ip_vaddr); DI_Key dbgi_key = d_dbgi_key_from_module(module); RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); @@ -11360,7 +11380,7 @@ rd_frame(void) U64 rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_count); D_Entity *module = d_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = d_voff_from_vaddr(module, rip_vaddr); - U64 tls_root_vaddr = d_tls_root_vaddr_from_thread(thread->handle); + U64 tls_root_vaddr = d_cached_tls_root_vaddr_from_thread(thread->handle); ProfEnd(); //////////////////////////// @@ -15821,7 +15841,7 @@ rd_frame(void) { D_Entity *thread = d_entity_from_handle(rd_regs()->thread); D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); - D_Entity *module = d_module_from_process_vaddr(process, d_rip_from_thread(thread->handle)); + D_Entity *module = d_module_from_process_vaddr(process, d_cached_ip_from_thread(thread->handle)); D_Entity *machine = d_entity_ancestor_from_kind(process, D_EntityKind_Machine); rd_state->base_regs.v.unwind_count = 0; rd_state->base_regs.v.inline_depth = 0; @@ -16664,7 +16684,7 @@ rd_frame(void) D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); D_Entity *module = d_module_from_process_vaddr(process, vaddr); U64 voff = d_voff_from_vaddr(module, vaddr); - U64 test_cached_vaddr = d_rip_from_thread(thread->handle); + U64 test_cached_vaddr = d_cached_ip_from_thread(thread->handle); // rjf: valid stop thread? -> select & snap if(need_refocus && thread->kind == D_EntityKind_Thread && evt->cause != D_EventCause_InterruptedByHalt) @@ -16734,7 +16754,7 @@ rd_frame(void) // rjf: update the autos-determining code range { D_Handle new_thread_handle = thread->handle; - U64 new_sp = d_rsp_from_thread(new_thread_handle); + U64 new_sp = d_cached_sp_from_thread(new_thread_handle); if(thread == &d_entity_nil) { new_thread_handle = selected_thread->handle;