From 49ccf50fd46e39e88790df297dccbfe22e1a658f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 8 Mar 2024 12:49:06 -0800 Subject: [PATCH 01/33] first pass at integrating new demon2 layer into debugger, need to change ctrl a bit to adopt some of the things that were previously being left up to demon layers --- src/ctrl/ctrl_core.c | 821 ++++++++++++++++++++++--------------- src/ctrl/ctrl_core.h | 273 +++++++----- src/dasm/dasm.c | 4 +- src/dasm/dasm.h | 6 +- src/demon2/demon2_core.h | 12 +- src/df/core/df_core.c | 10 +- src/df/core/df_core.h | 6 +- src/scratch/ryan_scratch.c | 4 +- 8 files changed, 676 insertions(+), 460 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 90f77226..36e00aaa 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -41,6 +41,18 @@ ctrl_init(void) ctrl_state->process_memory_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); ctrl_state->process_memory_cache.stripes[idx].cv = os_condition_variable_alloc(); } + ctrl_state->thread_reg_cache.slots_count = 1024; + ctrl_state->thread_reg_cache.slots = push_array(arena, CTRL_ThreadRegCacheSlot, ctrl_state->thread_reg_cache.slots_count); + ctrl_state->thread_reg_cache.stripes_count = 8; + ctrl_state->thread_reg_cache.stripes = push_array(arena, CTRL_ThreadRegCacheStripe, ctrl_state->thread_reg_cache.stripes_count); + for(U64 idx = 0; idx < ctrl_state->thread_reg_cache.stripes_count; idx += 1) + { + ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); + ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc(); + } + ctrl_state->ctrl_entity_arena = arena_alloc(); + ctrl_state->ctrl_entity_hash_slots_count = 4096; + ctrl_state->ctrl_entity_hash_slots = push_array(arena, CTRL_EntityHashSlot, ctrl_state->ctrl_entity_hash_slots_count); ctrl_state->u2c_ring_size = KB(64); ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); ctrl_state->u2c_ring_mutex = os_mutex_alloc(); @@ -49,7 +61,7 @@ ctrl_init(void) ctrl_state->c2u_ring_base = push_array_no_zero(arena, U8, ctrl_state->c2u_ring_size); ctrl_state->c2u_ring_mutex = os_mutex_alloc(); ctrl_state->c2u_ring_cv = os_condition_variable_alloc(); - ctrl_state->demon_event_arena = arena_alloc(); + ctrl_state->dmn_event_arena = arena_alloc(); ctrl_state->user_entry_point_arena = arena_alloc(); for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1)) { @@ -94,44 +106,35 @@ ctrl_hash_from_string(String8 string) return result; } +internal U64 +ctrl_hash_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle) +{ + U64 buf[] = {machine_id, handle.u64[0]}; + U64 hash = ctrl_hash_from_string(str8((U8 *)buf, sizeof(buf))); + return hash; +} + internal CTRL_EventCause -ctrl_event_cause_from_demon_event_kind(DEMON_EventKind event_kind) +ctrl_event_cause_from_dmn_event_kind(DMN_EventKind event_kind) { CTRL_EventCause cause = CTRL_EventCause_Null; switch(event_kind) { default:{}break; - case DEMON_EventKind_Error: {cause = CTRL_EventCause_Error;}break; - case DEMON_EventKind_Exception:{cause = CTRL_EventCause_InterruptedByException;}break; - case DEMON_EventKind_Trap: {cause = CTRL_EventCause_InterruptedByTrap;}break; - case DEMON_EventKind_Halt: {cause = CTRL_EventCause_InterruptedByHalt;}break; + case DMN_EventKind_Error: {cause = CTRL_EventCause_Error;}break; + case DMN_EventKind_Exception:{cause = CTRL_EventCause_InterruptedByException;}break; + case DMN_EventKind_Trap: {cause = CTRL_EventCause_InterruptedByTrap;}break; + case DMN_EventKind_Halt: {cause = CTRL_EventCause_InterruptedByHalt;}break; } return cause; } internal B32 -ctrl_handle_match(CTRL_Handle a, CTRL_Handle b) +ctrl_handle_match(DMN_Handle a, DMN_Handle b) { return MemoryMatchStruct(&a, &b); } -//////////////////////////////// -//~ rjf: Ctrl <-> Demon Handle Translation Functions - -internal DEMON_Handle -ctrl_demon_handle_from_ctrl(CTRL_Handle h) -{ - DEMON_Handle result = h.u64[0]; - return result; -} - -internal CTRL_Handle -ctrl_handle_from_demon(DEMON_Handle h) -{ - CTRL_Handle result = {h}; - return result; -} - //////////////////////////////// //~ rjf: Machine/Handle Pair Type Functions @@ -206,14 +209,14 @@ ctrl_user_breakpoint_list_copy(Arena *arena, CTRL_UserBreakpointList *src) } internal void -ctrl_append_resolved_module_user_bp_traps(Arena *arena, DEMON_Handle process, DEMON_Handle module, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out) +ctrl_append_resolved_module_user_bp_traps(Arena *arena, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) { Temp scratch = scratch_begin(&arena, 1); DBGI_Scope *scope = dbgi_scope_open(); - String8 exe_path = demon_full_path_from_module(scratch.arena, module); + String8 exe_path = dmn_full_path_from_module(scratch.arena, module); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); RDI_Parsed *rdi = &dbgi->rdi; - U64 base_vaddr = demon_base_vaddr_from_module(module); + U64 base_vaddr = dmn_base_vaddr_from_module(module); for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) { CTRL_UserBreakpoint *bp = &n->v; @@ -265,8 +268,8 @@ ctrl_append_resolved_module_user_bp_traps(Arena *arena, DEMON_Handle process, DE for(U32 i = 0; i < voff_count; i += 1) { U64 vaddr = voffs[i] + base_vaddr; - DEMON_Trap trap = {process, vaddr, (U64)bp}; - demon_trap_chunk_list_push(arena, traps_out, 256, &trap); + DMN_Trap trap = {process, vaddr, (U64)bp}; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); } } }break; @@ -292,8 +295,8 @@ ctrl_append_resolved_module_user_bp_traps(Arena *arena, DEMON_Handle process, DE { U64 proc_voff = rdi_first_voff_from_proc(rdi, ids[match_i]); U64 proc_vaddr = proc_voff + base_vaddr; - DEMON_Trap trap = {process, proc_vaddr + voff, (U64)bp}; - demon_trap_chunk_list_push(arena, traps_out, 256, &trap); + DMN_Trap trap = {process, proc_vaddr + voff, (U64)bp}; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); } } } @@ -306,15 +309,15 @@ ctrl_append_resolved_module_user_bp_traps(Arena *arena, DEMON_Handle process, DE } internal void -ctrl_append_resolved_process_user_bp_traps(Arena *arena, DEMON_Handle process, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out) +ctrl_append_resolved_process_user_bp_traps(Arena *arena, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) { for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) { CTRL_UserBreakpoint *bp = &n->v; if(bp->kind == CTRL_UserBreakpointKind_VirtualAddress) { - DEMON_Trap trap = {process, bp->u64, (U64)bp}; - demon_trap_chunk_list_push(arena, traps_out, 256, &trap); + DMN_Trap trap = {process, bp->u64, (U64)bp}; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); } } } @@ -688,7 +691,7 @@ ctrl_reggen_idx(void) internal void ctrl_halt(void) { - demon_halt(0, 0); + dmn_halt(0, 0); } //- rjf: exe -> dbg path mapping @@ -744,26 +747,25 @@ ctrl_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) //- rjf: handle -> arch internal Architecture -ctrl_arch_from_handle(CTRL_MachineID machine, CTRL_Handle handle) +ctrl_arch_from_handle(CTRL_MachineID machine, DMN_Handle handle) { - return demon_arch_from_object(ctrl_demon_handle_from_ctrl(handle)); + return dmn_arch_from_object(ctrl_dmn_handle_from_ctrl(handle)); } //- rjf: process memory reading/writing internal U64 -ctrl_process_read(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *dst) +ctrl_process_read(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *dst) { - U64 actual_bytes_read = demon_read_memory(ctrl_demon_handle_from_ctrl(process), dst, range.min, dim_1u64(range)); + U64 actual_bytes_read = dmn_process_read(process, range, dst); return actual_bytes_read; } internal B32 -ctrl_process_write(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *src) +ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *src) { ProfBeginFunction(); - U64 size = dim_1u64(range); - B32 result = demon_write_memory(ctrl_demon_handle_from_ctrl(process), range.min, src, size); + B32 result = dmn_process_write(process, range, src); //- rjf: success -> increment memgen if(result) @@ -785,7 +787,7 @@ ctrl_process_write(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range { Task *next; CTRL_MachineID machine_id; - CTRL_Handle process; + DMN_Handle process; Rng1U64 range; }; Task *first_task = 0; @@ -838,7 +840,7 @@ ctrl_process_write(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range //- rjf: process memory cache interaction internal U128 -ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated) +ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated) { U64 key_hash_data[] = { @@ -853,7 +855,7 @@ ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Han } internal U128 -ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated, U64 endt_us) +ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated, U64 endt_us) { U128 result = {0}; U64 size = dim_1u64(range); @@ -986,7 +988,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle //- rjf: process memory cache reading helpers internal CTRL_ProcessMemorySlice -ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, U64 endt_us) +ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, U64 endt_us) { CTRL_ProcessMemorySlice result = {0}; if(range.max > range.min && @@ -1109,7 +1111,7 @@ ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID mac } internal CTRL_ProcessMemorySlice -ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr, U64 limit, U64 endt_us) +ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, U64 vaddr, U64 limit, U64 endt_us) { CTRL_ProcessMemorySlice result = ctrl_query_cached_data_from_process_vaddr_range(arena, machine_id, process, r1u64(vaddr, vaddr+limit), endt_us); for(U64 idx = 0; idx < result.data.size; idx += 1) @@ -1125,42 +1127,42 @@ ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CT //- rjf: register reading/writing -internal void * -ctrl_reg_block_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread) +internal B32 +ctrl_thread_read_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block) { - void *regs = demon_read_regs(ctrl_demon_handle_from_ctrl(thread)); - return regs; + B32 good = dmn_thread_read_reg_block(thread, block); + return good; } internal B32 -ctrl_thread_write_reg_block(CTRL_MachineID machine_id, CTRL_Handle thread, void *block) +ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block) { - B32 good = demon_write_regs(ctrl_demon_handle_from_ctrl(thread), block); + B32 good = dmn_thread_write_reg_block(thread, block); ins_atomic_u64_inc_eval(&ctrl_state->reggen_idx); return good; } internal U64 -ctrl_rip_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread) +ctrl_rip_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) { U64 result = 0; void *regs = ctrl_reg_block_from_thread(machine_id, thread); if(regs != 0) { - Architecture arch = demon_arch_from_object(ctrl_demon_handle_from_ctrl(thread)); + Architecture arch = dmn_arch_from_object(ctrl_dmn_handle_from_ctrl(thread)); result = regs_rip_from_arch_block(arch, regs); } return result; } internal B32 -ctrl_thread_write_rip(CTRL_MachineID machine_id, CTRL_Handle thread, U64 rip) +ctrl_thread_write_rip(CTRL_MachineID machine_id, DMN_Handle thread, U64 rip) { B32 result = 0; void *regs = ctrl_reg_block_from_thread(machine_id, thread); if(regs != 0) { - Architecture arch = demon_arch_from_object(ctrl_demon_handle_from_ctrl(thread)); + Architecture arch = dmn_arch_from_object(ctrl_dmn_handle_from_ctrl(thread)); regs_arch_block_write_rip(arch, regs, rip); ctrl_thread_write_reg_block(machine_id, thread, regs); result = 1; @@ -1169,30 +1171,29 @@ ctrl_thread_write_rip(CTRL_MachineID machine_id, CTRL_Handle thread, U64 rip) } internal U64 -ctrl_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread) +ctrl_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) { U64 result = 0; - DEMON_Handle demon_handle = ctrl_demon_handle_from_ctrl(thread); - result = demon_tls_root_vaddr_from_thread(demon_handle); + result = dmn_tls_root_vaddr_from_thread(thread); return result; } //- rjf: process * vaddr -> module -internal CTRL_Handle -ctrl_module_from_process_vaddr(CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr) +internal DMN_Handle +ctrl_module_from_process_vaddr(CTRL_MachineID machine_id, DMN_Handle process, U64 vaddr) { - CTRL_Handle handle = {0}; + DMN_Handle handle = {0}; { Temp scratch = scratch_begin(0, 0); - DEMON_HandleArray modules = demon_modules_from_process(scratch.arena, ctrl_demon_handle_from_ctrl(process)); + DMN_HandleArray modules = dmn_modules_from_process(scratch.arena, ctrl_dmn_handle_from_ctrl(process)); for(U64 idx = 0; idx < modules.count; idx += 1) { - DEMON_Handle m = modules.handles[idx]; - Rng1U64 m_vaddr_rng = demon_vaddr_range_from_module(m); + DMN_Handle m = modules.handles[idx]; + Rng1U64 m_vaddr_rng = dmn_vaddr_range_from_module(m); if(contains_1u64(m_vaddr_rng, vaddr)) { - handle = ctrl_handle_from_demon(m); + handle = m; break; } } @@ -1204,12 +1205,12 @@ ctrl_module_from_process_vaddr(CTRL_MachineID machine_id, CTRL_Handle process, U //- rjf: unwinding internal CTRL_Unwind -ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, CTRL_Handle thread) +ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle thread) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); DBGI_Scope *scope = dbgi_scope_open(); - Architecture arch = demon_arch_from_object(ctrl_demon_handle_from_ctrl(thread)); + Architecture arch = dmn_arch_from_object(ctrl_dmn_handle_from_ctrl(thread)); U64 arch_reg_block_size = regs_block_size_from_architecture(arch); CTRL_Unwind unwind = {0}; unwind.error = 1; @@ -1235,7 +1236,7 @@ ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Ha UNW_MemView stack_memview = {0}; if(regs_block_good) { - U64 stack_base_unrounded = demon_stack_base_vaddr_from_thread(ctrl_demon_handle_from_ctrl(thread)); + U64 stack_base_unrounded = dmn_stack_base_vaddr_from_thread(thread); U64 stack_top_unrounded = regs_rsp_from_arch_block(arch, regs_block); U64 stack_base = AlignPow2(stack_base_unrounded, KB(4)); U64 stack_top = AlignDownPow2(stack_top_unrounded, KB(4)); @@ -1263,7 +1264,7 @@ ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Ha // rjf: regs -> rip*module*binary U64 rip = regs_rip_from_arch_block(arch, regs_block); - CTRL_Handle module = ctrl_module_from_process_vaddr(machine_id, process, rip); + DMN_Handle module = ctrl_module_from_process_vaddr(machine_id, process, rip); // rjf: cancel on 0 rip if(rip == 0) @@ -1272,7 +1273,7 @@ ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Ha } // rjf: binary -> all the binary info - String8 binary_full_path = demon_full_path_from_module(scratch.arena, ctrl_demon_handle_from_ctrl(module)); + String8 binary_full_path = dmn_full_path_from_module(scratch.arena, ctrl_dmn_handle_from_ctrl(module)); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_full_path, 0); String8 binary_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); @@ -1292,7 +1293,7 @@ ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Ha unwind.count += 1; // rjf: unwind one step - UNW_Result unwind_step = unw_pe_x64(binary_data, &dbgi->pe, demon_vaddr_range_from_module(ctrl_demon_handle_from_ctrl(module)).min, &memview, (UNW_X64_Regs *)regs_block); + UNW_Result unwind_step = unw_pe_x64(binary_data, &dbgi->pe, dmn_vaddr_range_from_module(ctrl_dmn_handle_from_ctrl(module)).min, &memview, (UNW_X64_Regs *)regs_block); // rjf: cancel on bad step if(unwind_step.dead != 0) @@ -1467,7 +1468,7 @@ ctrl_c2u_pop_events(Arena *arena) //~ rjf: User -> Memory Stream Communication internal B32 -ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us) +ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us) { B32 good = 0; OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) @@ -1491,7 +1492,7 @@ ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 va } internal void -ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated) +ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, DMN_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated) { OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) { @@ -1512,6 +1513,135 @@ ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, CTRL_Handle *out_process, //////////////////////////////// //~ rjf: Control-Thread-Only Functions +//- rjf: entity tree construction + +internal CTRL_Entity * +ctrl_thread__entity_alloc(CTRL_Entity *parent, CTRL_EntityKind kind, CTRL_MachineID machine_id, DMN_Handle handle) +{ + // rjf: allocate + CTRL_Entity *entity = ctrl_state->ctrl_entity_free; + { + if(entity != 0) + { + SLLStackPop(ctrl_state->ctrl_entity_free); + } + else + { + entity = push_array_no_zero(ctrl_state->ctrl_entity_arena, CTRL_Entity, 1); + } + MemoryZeroStruct(entity); + } + + // rjf: fill + { + entity->kind = kind; + entity->machine_id = machine_id; + entity->handle = handle; + entity->parent = parent; + entity->next = entity->prev = entity->first = entity->last = &ctrl_entity_nil; + if(parent != &ctrl_entity_nil) + { + DLLPushBack_NPZ(&ctrl_entity_nil, parent->first, parent->last, entity, next, prev); + } + } + + // rjf: insert into hash map + { + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, handle); + U64 slot_idx = hash%ctrl_state->ctrl_entity_hash_slots_count; + CTRL_EntityHashSlot *slot = &ctrl_state->ctrl_entity_hash_slots[slot_idx]; + CTRL_EntityHashNode *node = 0; + for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) + { + if(n->entity->machine_id == machine_id && dmn_handle_match(n->entity->handle, handle)) + { + node = n; + break; + } + } + if(node == 0) + { + node = ctrl_state->ctrl_entity_hash_node_free; + if(node != 0) + { + SLLStackPop(ctrl_state->ctrl_entity_hash_node_free); + } + else + { + node = push_array_no_zero(ctrl_state->ctrl_entity_arena, CTRL_EntityHashNode, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->entity = entity; + } + } + + return entity; +} + +internal void +ctrl_thread__entity_release(CTRL_Entity *entity) +{ + // rjf: unhook root + if(entity->parent != &ctrl_entity_nil) + { + DLLRemove_NPZ(&ctrl_entity_nil, entity->parent->first, entity->parent->last, entity, next, prev); + } + + // rjf: walk every entity in this tree, free each + if(entity != &ctrl_entity_nil) + { + Temp scratch = scratch_begin(0, 0); + typedef struct Task Task; + struct Task + { + Task *next; + CTRL_Entity *e; + }; + Task start_task = {0, entity}; + Task *first_task = &start_task; + Task *last_task = &start_task; + for(Task *t = first_task; t != 0; t = t->next) + { + for(CTRL_Entity *child = entity->first; child != &ctrl_entity_nil; child = child->next) + { + Task *t = push_array(scratch.arena, Task, 1); + t->e = child; + SLLQueuePush(first_task, last_task, t); + } + + // rjf: free entity + SLLStackPush(ctrl_state->ctrl_entity_free, t->e); + + // rjf: remove from hash map + { + U64 hash = ctrl_hash_from_machine_id_handle(t->e->machine_id, t->e->handle); + U64 slot_idx = hash%ctrl_state->ctrl_entity_hash_slots_count; + CTRL_EntityHashSlot *slot = &ctrl_state->ctrl_entity_hash_slots[slot_idx]; + CTRL_EntityHashNode *node = 0; + for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) + { + if(n->entity->machine_id == t->e->machine_id && dmn_handle_match(n->entity->handle, t->e->handle)) + { + DLLRemove(slot->first, slot->last, n); + SLLStackPush(ctrl_state->ctrl_entity_hash_node_free, n); + break; + } + } + } + } + scratch_end(scratch); + } +} + +internal CTRL_Entity * +ctrl_thread__entity_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle) +{ + CTRL_Entity *entity = &ctrl_entity_nil; + + return entity; +} + //- rjf: entry point internal void @@ -1519,7 +1649,15 @@ ctrl_thread__entry_point(void *p) { ThreadNameF("[ctrl] thread"); ProfBeginFunction(); - demon_primary_thread_begin(); + + //- rjf: set up initial entities + { + CTRL_Entity *root = ctrl_thread__entity_alloc(&ctrl_entity_nil, CTRL_EntityKind_Root, 0, dmn_handle_zero()); + CTRL_Entity *local_machine = ctrl_thread__entity_alloc(root, CTRL_EntityKind_Machine, CTRL_MachineID_Local, dmn_handle_zero()); + (void)local_machine; + } + + //- rjf: loop Temp scratch = scratch_begin(0, 0); for(;;) { @@ -1530,7 +1668,6 @@ ctrl_thread__entry_point(void *p) //- rjf: process messages { - demon_exclusive_mode_begin(); B32 done = 0; for(CTRL_MsgNode *msg_n = msgs.first; msg_n != 0 && done == 0; msg_n = msg_n->next) { @@ -1562,20 +1699,20 @@ ctrl_thread__entry_point(void *p) }break; } } - demon_exclusive_mode_end(); } } + scratch_end(scratch); ProfEnd(); } //- rjf: attached process running/event gathering -internal DEMON_Event * -ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_ctrls, CTRL_Spoof *spoof) +internal DMN_Event * +ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof) { ProfBeginFunction(); - DEMON_Event *event = push_array(arena, DEMON_Event, 1); + DMN_Event *event = push_array(arena, DMN_Event, 1); Temp scratch = scratch_begin(&arena, 1); //- rjf: loop -> try to get event, run, repeat @@ -1586,17 +1723,17 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c ProfScope("get next event") { // rjf: grab first event - DEMON_EventNode *next_event_node = ctrl_state->first_demon_event_node; + DMN_EventNode *next_event_node = ctrl_state->first_dmn_event_node; // rjf: determine if we should filter B32 should_filter_event = 0; if(next_event_node != 0) { - DEMON_Event *ev = &next_event_node->v; + DMN_Event *ev = &next_event_node->v; switch(ev->kind) { default:{}break; - case DEMON_EventKind_Exception: + case DMN_EventKind_Exception: { // NOTE(rjf): first chance exceptions -> try ignoring should_filter_event = (ev->exception_repeated == 0 && (spoof == 0 || ev->instruction_pointer != spoof->new_ip_value)); @@ -1631,14 +1768,14 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c (spoof == 0 || ev->instruction_pointer != spoof->new_ip_value)) { DBGI_Scope *scope = dbgi_scope_open(); - DEMON_HandleArray modules = demon_modules_from_process(scratch.arena, ev->process); + DMN_HandleArray modules = dmn_modules_from_process(scratch.arena, ev->process); if(modules.count != 0) { // rjf: determine base address of asan shadow space U64 asan_shadow_base_vaddr = 0; B32 asan_shadow_variable_exists_but_is_zero = 0; - CTRL_Handle module = ctrl_handle_from_demon(modules.handles[0]); - String8 module_path = demon_full_path_from_module(scratch.arena, ctrl_demon_handle_from_ctrl(module)); + DMN_Handle module = modules.handles[0]; + String8 module_path = dmn_full_path_from_module(scratch.arena, ctrl_dmn_handle_from_ctrl(module)); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, module_path, max_U64); RDI_Parsed *rdi = &dbgi->rdi; RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_GlobalVariables); @@ -1656,10 +1793,10 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c { RDI_GlobalVariable *global_var = rdi_element_from_idx(rdi, global_variables, ids[0]); U64 global_var_voff = global_var->voff; - U64 global_var_vaddr = global_var->voff + demon_base_vaddr_from_module(ctrl_demon_handle_from_ctrl(module)); - Architecture arch = demon_arch_from_object(ev->thread); + U64 global_var_vaddr = global_var->voff + dmn_base_vaddr_from_module(ctrl_dmn_handle_from_ctrl(module)); + Architecture arch = dmn_arch_from_object(ev->thread); U64 addr_size = bit_size_from_arch(arch)/8; - ctrl_process_read(CTRL_MachineID_Client, ctrl_handle_from_demon(ev->process), r1u64(global_var_vaddr, global_var_vaddr+addr_size), &asan_shadow_base_vaddr); + ctrl_process_read(CTRL_MachineID_Local, ev->process, r1u64(global_var_vaddr, global_var_vaddr+addr_size), &asan_shadow_base_vaddr); asan_shadow_variable_exists_but_is_zero = (asan_shadow_base_vaddr == 0); } } @@ -1693,7 +1830,7 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c if(next_event_node != 0 && !should_filter_event) { got_event = 1; - SLLQueuePop(ctrl_state->first_demon_event_node, ctrl_state->last_demon_event_node); + SLLQueuePop(ctrl_state->first_dmn_event_node, ctrl_state->last_dmn_event_node); MemoryCopyStruct(event, &next_event_node->v); event->string = push_str8_copy(arena, event->string); run_ctrls->ignore_previous_exception = 1; @@ -1702,55 +1839,55 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c // rjf: good event but filtered? pop from queue if(next_event_node != 0 && should_filter_event) { - SLLQueuePop(ctrl_state->first_demon_event_node, ctrl_state->last_demon_event_node); + SLLQueuePop(ctrl_state->first_dmn_event_node, ctrl_state->last_dmn_event_node); run_ctrls->ignore_previous_exception = 0; } } - //- rjf: no event -> demon_run for a new one - if(got_event == 0) ProfScope("no event -> demon_run for a new one") + //- rjf: no event -> dmn_run for a new one + if(got_event == 0) ProfScope("no event -> dmn_run for a new one") { // rjf: prep spoof - B32 do_spoof = (spoof != 0 && run_ctrls->single_step_thread == 0); + B32 do_spoof = (spoof != 0 && dmn_handle_match(run_ctrls->single_step_thread, dmn_handle_zero())); U64 size_of_spoof = 0; if(do_spoof) ProfScope("prep spoof") { - Architecture arch = demon_arch_from_object(ctrl_demon_handle_from_ctrl(spoof->process)); - demon_read_memory(ctrl_demon_handle_from_ctrl(spoof->process), &spoof_old_ip_value, spoof->vaddr, sizeof(spoof_old_ip_value)); + Architecture arch = dmn_arch_from_object(ctrl_dmn_handle_from_ctrl(spoof->process)); + dmn_read_memory(ctrl_dmn_handle_from_ctrl(spoof->process), &spoof_old_ip_value, spoof->vaddr, sizeof(spoof_old_ip_value)); size_of_spoof = bit_size_from_arch(arch)/8; } // rjf: set spoof if(do_spoof) ProfScope("set spoof") { - demon_write_memory(ctrl_demon_handle_from_ctrl(spoof->process), spoof->vaddr, &spoof->new_ip_value, size_of_spoof); + dmn_write_memory(ctrl_dmn_handle_from_ctrl(spoof->process), spoof->vaddr, &spoof->new_ip_value, size_of_spoof); } // rjf: run for new events ProfScope("run for new events") { - DEMON_EventList events = demon_run(scratch.arena, run_ctrls); - for(DEMON_EventNode *src_n = events.first; src_n != 0; src_n = src_n->next) + DMN_EventList events = dmn_run(scratch.arena, run_ctrls); + for(DMN_EventNode *src_n = events.first; src_n != 0; src_n = src_n->next) { - DEMON_EventNode *dst_n = ctrl_state->free_demon_event_node; + DMN_EventNode *dst_n = ctrl_state->free_dmn_event_node; if(dst_n != 0) { - SLLStackPop(ctrl_state->free_demon_event_node); + SLLStackPop(ctrl_state->free_dmn_event_node); } else { - dst_n = push_array(ctrl_state->demon_event_arena, DEMON_EventNode, 1); + dst_n = push_array(ctrl_state->dmn_event_arena, DMN_EventNode, 1); } MemoryCopyStruct(&dst_n->v, &src_n->v); - dst_n->v.string = push_str8_copy(ctrl_state->demon_event_arena, dst_n->v.string); - SLLQueuePush(ctrl_state->first_demon_event_node, ctrl_state->last_demon_event_node, dst_n); + dst_n->v.string = push_str8_copy(ctrl_state->dmn_event_arena, dst_n->v.string); + SLLQueuePush(ctrl_state->first_dmn_event_node, ctrl_state->last_dmn_event_node, dst_n); } } // rjf: unset spoof if(do_spoof) ProfScope("unset spoof") { - demon_write_memory(ctrl_demon_handle_from_ctrl(spoof->process), spoof->vaddr, &spoof_old_ip_value, size_of_spoof); + dmn_write_memory(ctrl_dmn_handle_from_ctrl(spoof->process), spoof->vaddr, &spoof_old_ip_value, size_of_spoof); } // rjf: inc generation counters @@ -1767,10 +1904,10 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c // simply been sent other debug events first if(spoof != 0) { - U64 spoof_thread_rip = demon_read_ip(ctrl_demon_handle_from_ctrl(spoof->thread)); + U64 spoof_thread_rip = dmn_read_ip(ctrl_dmn_handle_from_ctrl(spoof->thread)); if(spoof_thread_rip == spoof->new_ip_value) { - demon_write_ip(ctrl_demon_handle_from_ctrl(spoof->thread), spoof_old_ip_value); + dmn_write_ip(ctrl_dmn_handle_from_ctrl(spoof->thread), spoof_old_ip_value); } } @@ -1779,95 +1916,95 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c ProfScope("push ctrl events associated with this demon event") switch(event->kind) { default:{}break; - case DEMON_EventKind_CreateProcess: + case DMN_EventKind_CreateProcess: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); out_evt->kind = CTRL_EventKind_NewProc; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->process); - out_evt->arch = demon_arch_from_object(event->process); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->process; + out_evt->arch = dmn_arch_from_object(event->process); out_evt->entity_id = event->code; ctrl_state->process_counter += 1; }break; - case DEMON_EventKind_CreateThread: + case DMN_EventKind_CreateThread: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); out_evt->kind = CTRL_EventKind_NewThread; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->thread); - out_evt->parent = ctrl_handle_from_demon(event->process); - out_evt->arch = demon_arch_from_object(event->process); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->thread; + out_evt->parent = event->process; + out_evt->arch = dmn_arch_from_object(event->process); out_evt->entity_id = event->code; - out_evt->stack_base = demon_stack_base_vaddr_from_thread(event->thread); - out_evt->tls_root = demon_tls_root_vaddr_from_thread(event->thread); + out_evt->stack_base = dmn_stack_base_vaddr_from_thread(event->thread); + out_evt->tls_root = dmn_tls_root_vaddr_from_thread(event->thread); out_evt->rip_vaddr = event->instruction_pointer; out_evt->string = event->string; }break; - case DEMON_EventKind_LoadModule: + case DMN_EventKind_LoadModule: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); String8 module_path = event->string; dbgi_binary_open(module_path); out_evt->kind = CTRL_EventKind_NewModule; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->module); - out_evt->parent = ctrl_handle_from_demon(event->process); - out_evt->arch = demon_arch_from_object(event->module); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->module; + out_evt->parent = event->process; + out_evt->arch = dmn_arch_from_object(event->module); out_evt->entity_id = event->code; out_evt->vaddr_rng = r1u64(event->address, event->address+event->size); - out_evt->rip_vaddr = demon_base_vaddr_from_module(event->module); + out_evt->rip_vaddr = dmn_base_vaddr_from_module(event->module); out_evt->string = module_path; }break; - case DEMON_EventKind_ExitProcess: + case DMN_EventKind_ExitProcess: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); out_evt->kind = CTRL_EventKind_EndProc; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->process); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->process; out_evt->u64_code = event->code; ctrl_state->process_counter -= 1; }break; - case DEMON_EventKind_ExitThread: + case DMN_EventKind_ExitThread: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); out_evt->kind = CTRL_EventKind_EndThread; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->thread); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->thread; out_evt->entity_id = event->code; }break; - case DEMON_EventKind_UnloadModule: + case DMN_EventKind_UnloadModule: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); String8 module_path = event->string; dbgi_binary_close(module_path); out_evt->kind = CTRL_EventKind_EndModule; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->module); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->module; }break; - case DEMON_EventKind_DebugString: + case DMN_EventKind_DebugString: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); out_evt->kind = CTRL_EventKind_DebugString; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->thread); - out_evt->parent = ctrl_handle_from_demon(event->process); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->thread; + out_evt->parent = event->process; out_evt->string = event->string; }break; - case DEMON_EventKind_SetThreadName: + case DMN_EventKind_SetThreadName: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); out_evt->kind = CTRL_EventKind_ThreadName; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->thread); - out_evt->parent = ctrl_handle_from_demon(event->process); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->thread; + out_evt->parent = event->process; out_evt->string = event->string; out_evt->entity_id = event->code; }break; @@ -1875,7 +2012,7 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c ctrl_c2u_push_events(&evts); //- rjf: clear process memory cache, if we've just started a lone process - if(event->kind == DEMON_EventKind_CreateProcess && ctrl_state->process_counter == 1) + if(event->kind == DMN_EventKind_CreateProcess && ctrl_state->process_counter == 1) { CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; for(U64 slot_idx = 0; slot_idx < cache->slots_count; slot_idx += 1) @@ -1896,10 +2033,10 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c } //- rjf: out of queued up demon events -> clear event arena - if(ctrl_state->first_demon_event_node == 0) + if(ctrl_state->first_dmn_event_node == 0) { - ctrl_state->free_demon_event_node = 0; - arena_clear(ctrl_state->demon_event_arena); + ctrl_state->free_dmn_event_node = 0; + arena_clear(ctrl_state->dmn_event_arena); } scratch_end(scratch); @@ -1912,8 +2049,8 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c internal B32 ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size) { - DEMON_Handle process = (DEMON_Handle)u; - U64 read_size = demon_read_memory(process, out, addr, size); + DMN_Handle process = *(DMN_Handle *)u; + U64 read_size = dmn_process_read(process, r1u64(addr, addr+size), out); B32 result = (read_size == size); return result; } @@ -1935,7 +2072,7 @@ ctrl_thread__launch_and_handshake(CTRL_Msg *msg) opts.env = msg->env_string_list; opts.inherit_env = msg->env_inherit; } - U32 id = demon_launch_process(&opts); + U32 id = dmn_launch_process(&opts); //- rjf: record start { @@ -1946,12 +2083,12 @@ ctrl_thread__launch_and_handshake(CTRL_Msg *msg) } //- rjf: run to handshake - DEMON_Event *stop_event = 0; + DMN_Event *stop_event = 0; if(id != 0) { // rjf: prep run controls - DEMON_Handle unfrozen_process = 0; - DEMON_RunCtrls run_ctrls = {0}; + DMN_Handle unfrozen_process = {0}; + DMN_RunCtrls run_ctrls = {0}; { run_ctrls.run_entities_are_unfrozen = 1; run_ctrls.run_entities_are_processes = 1; @@ -1962,20 +2099,20 @@ ctrl_thread__launch_and_handshake(CTRL_Msg *msg) // rjf: run until handshake-signifying events for(B32 done = 0; done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_CreateProcess: + case DMN_EventKind_CreateProcess: { unfrozen_process = event->process; run_ctrls.run_entity_count = 1; }break; - case DEMON_EventKind_Error: - case DEMON_EventKind_Breakpoint: - case DEMON_EventKind_Exception: - case DEMON_EventKind_ExitProcess: - case DEMON_EventKind_HandshakeComplete: + case DMN_EventKind_Error: + case DMN_EventKind_Breakpoint: + case DMN_EventKind_Exception: + case DMN_EventKind_ExitProcess: + case DMN_EventKind_HandshakeComplete: { done = 1; stop_event = event; @@ -2001,10 +2138,10 @@ ctrl_thread__launch_and_handshake(CTRL_Msg *msg) event->kind = CTRL_EventKind_Stopped; if(stop_event != 0) { - event->cause = ctrl_event_cause_from_demon_event_kind(stop_event->kind); - event->machine_id = CTRL_MachineID_Client; - event->entity = ctrl_handle_from_demon(stop_event->thread); - event->parent = ctrl_handle_from_demon(stop_event->process); + event->cause = ctrl_event_cause_from_dmn_event_kind(stop_event->kind); + event->machine_id = CTRL_MachineID_Local; + event->entity = stop_event->thread; + event->parent = stop_event->process; event->exception_code = stop_event->code; event->vaddr_rng = r1u64(stop_event->address, stop_event->address); event->rip_vaddr = stop_event->instruction_pointer; @@ -2017,7 +2154,7 @@ ctrl_thread__launch_and_handshake(CTRL_Msg *msg) CTRL_EventList evts = {0}; CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); evt->kind = CTRL_EventKind_LaunchAndHandshakeDone; - evt->machine_id= CTRL_MachineID_Client; + evt->machine_id= CTRL_MachineID_Local; evt->msg_id = msg->msg_id; evt->entity_id = id; ctrl_c2u_push_events(&evts); @@ -2044,7 +2181,7 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) opts.env = msg->env_string_list; opts.inherit_env = msg->env_inherit; } - U32 id = demon_launch_process(&opts); + U32 id = dmn_launch_process(&opts); ////////////////////////////// //- rjf: record start @@ -2059,22 +2196,22 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) ////////////////////////////// //- rjf: run to initialization (entry point) // - DEMON_Event *stop_event = 0; + DMN_Event *stop_event = 0; if(id != 0) { - DEMON_Handle unfrozen_process[8] = {0}; - DEMON_RunCtrls run_ctrls = {0}; + DMN_Handle unfrozen_process[8] = {0}; + DMN_RunCtrls run_ctrls = {0}; run_ctrls.run_entities_are_unfrozen = 1; run_ctrls.run_entities_are_processes = 1; for(B32 done = 0; done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; //- rjf: new process -> freeze process - case DEMON_EventKind_CreateProcess: + case DMN_EventKind_CreateProcess: if(run_ctrls.run_entity_count < ArrayCount(unfrozen_process)) { unfrozen_process[run_ctrls.run_entity_count] = event->process; @@ -2083,13 +2220,13 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) }break; //- rjf: breakpoint -> if it's the entry point, we're done. otherwise, keep going - case DEMON_EventKind_Breakpoint: + case DMN_EventKind_Breakpoint: { - for(DEMON_TrapChunkNode *n = run_ctrls.traps.first; n != 0; n = n->next) + for(DMN_TrapChunkNode *n = run_ctrls.traps.first; n != 0; n = n->next) { for(U64 idx = 0; idx < n->count; idx += 1) { - if(n->v[idx].address == event->instruction_pointer) + if(n->v[idx].vaddr == event->instruction_pointer) { done = 1; stop_event = event; @@ -2101,21 +2238,21 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) }break; //- rjf: exception -> done - case DEMON_EventKind_Exception: + case DMN_EventKind_Exception: { done = 1; stop_event = event; }break; //- rjf: process ended? -> remove from unfrozen processes. zero processes -> done. - case DEMON_EventKind_ExitProcess: + case DMN_EventKind_ExitProcess: { for(U64 idx = 0; idx < run_ctrls.run_entity_count; idx += 1) { - if(run_ctrls.run_entities[idx] == event->process && + if(dmn_handle_match(run_ctrls.run_entities[idx], event->process) && idx+1 < run_ctrls.run_entity_count) { - MemoryCopy(run_ctrls.run_entities+idx, run_ctrls.run_entities+idx+1, sizeof(DEMON_Handle)*(run_ctrls.run_entity_count-(idx+1))); + MemoryCopy(run_ctrls.run_entities+idx, run_ctrls.run_entities+idx+1, sizeof(DMN_Handle)*(run_ctrls.run_entity_count-(idx+1))); break; } } @@ -2131,7 +2268,7 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) }break; //- rjf: done with handshake -> ready to find entry point. search launched processes - case DEMON_EventKind_HandshakeComplete: + case DMN_EventKind_HandshakeComplete: { DBGI_Scope *scope = dbgi_scope_open(); @@ -2139,11 +2276,11 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) for(U64 process_idx = 0; process_idx < run_ctrls.run_entity_count; process_idx += 1) { //- rjf: unpack first module info - DEMON_HandleArray modules = demon_modules_from_process(scratch.arena, run_ctrls.run_entities[process_idx]); + DMN_HandleArray modules = dmn_modules_from_process(scratch.arena, run_ctrls.run_entities[process_idx]); if(modules.count == 0) { continue; } - DEMON_Handle module = modules.handles[0]; - U64 module_base_vaddr = demon_base_vaddr_from_module(module); - String8 exe_path = demon_full_path_from_module(scratch.arena, module); + DMN_Handle module = modules.handles[0]; + U64 module_base_vaddr = dmn_base_vaddr_from_module(module); + String8 exe_path = dmn_full_path_from_module(scratch.arena, module); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); RDI_Parsed *rdi = &dbgi->rdi; RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Procedures); @@ -2171,8 +2308,8 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) if(voff != 0) { entries_found = 1; - DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; - demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); + DMN_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; + dmn_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); } } } @@ -2196,8 +2333,8 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) U64 voff = rdi_first_voff_from_proc(rdi, procedure_id); if(voff != 0) { - DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; - demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); + DMN_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; + dmn_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); break; } } @@ -2230,8 +2367,8 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) if(voff != 0) { entries_found = 1; - DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; - demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); + DMN_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; + dmn_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); } } } @@ -2242,8 +2379,8 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) U64 voff = dbgi->pe.entry_point; if(voff != 0) { - DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; - demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); + DMN_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; + dmn_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); } } @@ -2274,8 +2411,8 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) if(voff != 0) { entries_found = 1; - DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; - demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); + DMN_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; + dmn_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); } } } @@ -2316,10 +2453,10 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) event->msg_id = msg->msg_id; if(stop_event != 0) { - event->cause = ctrl_event_cause_from_demon_event_kind(stop_event->kind); - event->machine_id = CTRL_MachineID_Client; - event->entity = ctrl_handle_from_demon(stop_event->thread); - event->parent = ctrl_handle_from_demon(stop_event->process); + event->cause = ctrl_event_cause_from_dmn_event_kind(stop_event->kind); + event->machine_id = CTRL_MachineID_Local; + event->entity = stop_event->thread; + event->parent = stop_event->process; event->exception_code = stop_event->code; event->vaddr_rng = r1u64(stop_event->address, stop_event->address); event->rip_vaddr = stop_event->instruction_pointer; @@ -2334,7 +2471,7 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) CTRL_EventList evts = {0}; CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); evt->kind = CTRL_EventKind_LaunchAndInitDone; - evt->machine_id= CTRL_MachineID_Client; + evt->machine_id= CTRL_MachineID_Local; evt->msg_id = msg->msg_id; evt->entity_id = id; ctrl_c2u_push_events(&evts); @@ -2352,28 +2489,28 @@ ctrl_thread__attach(CTRL_Msg *msg) DBGI_Scope *scope = dbgi_scope_open(); //- rjf: attach - B32 attach_successful = demon_attach_process(msg->entity_id); + B32 attach_successful = dmn_attach_process(msg->entity_id); //- rjf: run to handshake if(attach_successful) { - DEMON_Handle unfrozen_process = 0; - DEMON_RunCtrls run_ctrls = {0}; + DMN_Handle unfrozen_process = {0}; + DMN_RunCtrls run_ctrls = {0}; run_ctrls.run_entities_are_unfrozen = 1; run_ctrls.run_entities_are_processes = 1; for(B32 done = 0; done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_CreateProcess: + case DMN_EventKind_CreateProcess: { unfrozen_process = event->process; run_ctrls.run_entities = &unfrozen_process; run_ctrls.run_entity_count = 1; }break; - case DEMON_EventKind_HandshakeComplete: + case DMN_EventKind_HandshakeComplete: { done = 1; }break; @@ -2386,7 +2523,7 @@ ctrl_thread__attach(CTRL_Msg *msg) CTRL_EventList evts = {0}; CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); evt->kind = CTRL_EventKind_AttachDone; - evt->machine_id= CTRL_MachineID_Client; + evt->machine_id= CTRL_MachineID_Local; evt->msg_id = msg->msg_id; evt->entity_id = !!attach_successful * msg->entity_id; ctrl_c2u_push_events(&evts); @@ -2403,24 +2540,24 @@ ctrl_thread__kill(CTRL_Msg *msg) ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); DBGI_Scope *scope = dbgi_scope_open(); - DEMON_Handle process = ctrl_demon_handle_from_ctrl(msg->entity); + DMN_Handle process = msg->entity; U32 exit_code = msg->exit_code; //- rjf: send kill - B32 kill_worked = demon_kill_process(process, exit_code); + B32 kill_worked = dmn_kill_process(process, exit_code); //- rjf: wait for process to be dead - if(demon_object_exists(process) && kill_worked) + if(dmn_object_exists(process) && kill_worked) { - DEMON_RunCtrls run_ctrls = {0}; + DMN_RunCtrls run_ctrls = {0}; run_ctrls.run_entities_are_unfrozen = 1; run_ctrls.run_entities_are_processes = 1; run_ctrls.run_entities = &process; run_ctrls.run_entity_count = 1; for(B32 done = 0; done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); - if(event->kind == DEMON_EventKind_ExitProcess && event->process == process) + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process)) { done = 1; } @@ -2432,7 +2569,7 @@ ctrl_thread__kill(CTRL_Msg *msg) CTRL_EventList evts = {0}; CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); evt->kind = CTRL_EventKind_KillDone; - evt->machine_id= CTRL_MachineID_Client; + evt->machine_id= CTRL_MachineID_Local; evt->msg_id = msg->msg_id; if(kill_worked) { @@ -2452,23 +2589,23 @@ ctrl_thread__detach(CTRL_Msg *msg) ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); DBGI_Scope *scope = dbgi_scope_open(); - DEMON_Handle process = ctrl_demon_handle_from_ctrl(msg->entity); + DMN_Handle process = msg->entity; //- rjf: detach - B32 detach_worked = demon_detach_process(process); + B32 detach_worked = dmn_detach_process(process); //- rjf: wait for process to be dead - if(demon_object_exists(process) && detach_worked) + if(dmn_object_exists(process) && detach_worked) { - DEMON_RunCtrls run_ctrls = {0}; + DMN_RunCtrls run_ctrls = {0}; run_ctrls.run_entities_are_unfrozen = 1; run_ctrls.run_entities_are_processes = 1; run_ctrls.run_entities = &process; run_ctrls.run_entity_count = 1; for(B32 done = 0; done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); - if(event->kind == DEMON_EventKind_ExitProcess && event->process == process) + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process)) { done = 1; } @@ -2480,7 +2617,7 @@ ctrl_thread__detach(CTRL_Msg *msg) CTRL_EventList evts = {0}; CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); evt->kind = CTRL_EventKind_DetachDone; - evt->machine_id= CTRL_MachineID_Client; + evt->machine_id= CTRL_MachineID_Local; evt->msg_id = msg->msg_id; if(detach_worked) { @@ -2500,30 +2637,30 @@ ctrl_thread__run(CTRL_Msg *msg) ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); DBGI_Scope *scope = dbgi_scope_open(); - DEMON_Event *stop_event = 0; + DMN_Event *stop_event = 0; CTRL_EventCause stop_cause = CTRL_EventCause_Null; - DEMON_Handle target_thread = ctrl_demon_handle_from_ctrl(msg->entity); - DEMON_Handle target_process = ctrl_demon_handle_from_ctrl(msg->parent); + DMN_Handle target_thread = msg->entity; + DMN_Handle target_process = msg->parent; U64 spoof_ip_vaddr = 911; ////////////////////////////// //- rjf: gather processes // - DEMON_HandleArray processes = demon_all_processes(scratch.arena); + DMN_HandleArray processes = dmn_all_processes(scratch.arena); ////////////////////////////// //- rjf: gather all initial breakpoints // - DEMON_TrapChunkList user_traps = {0}; + DMN_TrapChunkList user_traps = {0}; { // rjf: resolve module-dependent user bps for(U64 process_idx = 0; process_idx < processes.count; process_idx += 1) { - DEMON_Handle process = processes.handles[process_idx]; - DEMON_HandleArray modules = demon_modules_from_process(scratch.arena, process); + DMN_Handle process = processes.handles[process_idx]; + DMN_HandleArray modules = dmn_modules_from_process(scratch.arena, process); for(U64 module_idx = 0; module_idx < modules.count; module_idx += 1) { - DEMON_Handle module = modules.handles[module_idx]; + DMN_Handle module = modules.handles[module_idx]; ctrl_append_resolved_module_user_bp_traps(scratch.arena, process, module, &msg->user_bps, &user_traps); } } @@ -2551,21 +2688,21 @@ ctrl_thread__run(CTRL_Msg *msg) if(stop_event == 0) { // rjf: gather stuck threads - DEMON_HandleList stuck_threads = {0}; + DMN_HandleList stuck_threads = {0}; for(U64 i = 0; i < processes.count; i += 1) { - DEMON_Handle process = processes.handles[i]; - DEMON_HandleArray threads = demon_threads_from_process(scratch.arena, process); + DMN_Handle process = processes.handles[i]; + DMN_HandleArray threads = dmn_threads_from_process(scratch.arena, process); for(U64 j = 0; j < threads.count; j += 1) { - DEMON_Handle thread = threads.handles[j]; - U64 rip = demon_read_ip(thread); + DMN_Handle thread = threads.handles[j]; + U64 rip = dmn_read_ip(thread); // rjf: determine if thread is frozen B32 thread_is_frozen = !msg->freeze_state_is_frozen; for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next) { - if(ctrl_demon_handle_from_ctrl(n->v.handle) == thread) + if(dmn_handle_match(n->v.handle, thread)) { thread_is_frozen ^= 1; break; @@ -2575,12 +2712,12 @@ ctrl_thread__run(CTRL_Msg *msg) // rjf: not frozen? -> check if stuck & gather if so if(thread_is_frozen == 0) { - for(DEMON_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) + for(DMN_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) { B32 is_on_user_bp = 0; - for(DEMON_Trap *trap_ptr = n->v; trap_ptr < n->v+n->count; trap_ptr += 1) + for(DMN_Trap *trap_ptr = n->v; trap_ptr < n->v+n->count; trap_ptr += 1) { - if(trap_ptr->process == process && trap_ptr->address == rip) + if(dmn_handle_match(trap_ptr->process, process) && trap_ptr->vaddr == rip) { is_on_user_bp = 1; } @@ -2595,12 +2732,12 @@ ctrl_thread__run(CTRL_Msg *msg) } } - if(is_on_user_bp && (!is_on_net_trap || thread != target_thread)) + if(is_on_user_bp && (!is_on_net_trap || !dmn_handle_match(thread, target_thread))) { - demon_handle_list_push(scratch.arena, &stuck_threads, thread); + dmn_handle_list_push(scratch.arena, &stuck_threads, thread); } - if(is_on_user_bp && is_on_net_trap && thread == target_thread) + if(is_on_user_bp && is_on_net_trap && dmn_handle_match(thread, target_thread)) { target_thread_is_on_user_bp_and_trap_net_trap = 1; } @@ -2610,28 +2747,28 @@ ctrl_thread__run(CTRL_Msg *msg) } // rjf: actually step stuck threads - for(DEMON_HandleNode *node = stuck_threads.first; + for(DMN_HandleNode *node = stuck_threads.first; node != 0; node = node->next) { - DEMON_RunCtrls run_ctrls = {0}; + DMN_RunCtrls run_ctrls = {0}; run_ctrls.single_step_thread = node->v; for(B32 done = 0; done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_Error: stop_cause = CTRL_EventCause_Error; goto stop; - case DEMON_EventKind_Exception: stop_cause = CTRL_EventCause_InterruptedByException; goto stop; - case DEMON_EventKind_Trap: stop_cause = CTRL_EventCause_InterruptedByTrap; goto stop; - case DEMON_EventKind_Halt: stop_cause = CTRL_EventCause_InterruptedByHalt; goto stop; + case DMN_EventKind_Error: stop_cause = CTRL_EventCause_Error; goto stop; + case DMN_EventKind_Exception: stop_cause = CTRL_EventCause_InterruptedByException; goto stop; + case DMN_EventKind_Trap: stop_cause = CTRL_EventCause_InterruptedByTrap; goto stop; + case DMN_EventKind_Halt: stop_cause = CTRL_EventCause_InterruptedByHalt; goto stop; stop:; { stop_event = event; done = 1; }break; - case DEMON_EventKind_SingleStep: + case DMN_EventKind_SingleStep: { done = 1; }break; @@ -2643,22 +2780,22 @@ ctrl_thread__run(CTRL_Msg *msg) ////////////////////////////// //- rjf: resolve trap net // - DEMON_TrapChunkList trap_net_traps = {0}; + DMN_TrapChunkList trap_net_traps = {0}; for(CTRL_TrapNode *node = msg->traps.first; node != 0; node = node->next) { - DEMON_Trap trap = {target_process, node->v.vaddr}; - demon_trap_chunk_list_push(scratch.arena, &trap_net_traps, 256, &trap); + DMN_Trap trap = {target_process, node->v.vaddr}; + dmn_trap_chunk_list_push(scratch.arena, &trap_net_traps, 256, &trap); } ////////////////////////////// //- rjf: join user breakpoints and trap net traps // - DEMON_TrapChunkList joined_traps = {0}; + DMN_TrapChunkList joined_traps = {0}; { - demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &user_traps); - demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &trap_net_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &user_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &trap_net_traps); } ////////////////////////////// @@ -2677,7 +2814,7 @@ ctrl_thread__run(CTRL_Msg *msg) // if(stop_event == 0) { - U64 sp_check_value = demon_read_sp(target_thread); + U64 sp_check_value = dmn_read_sp(target_thread); B32 spoof_mode = 0; CTRL_Spoof spoof = {0}; for(;;) @@ -2685,7 +2822,7 @@ ctrl_thread__run(CTRL_Msg *msg) ////////////////////////// //- rjf: choose low level traps // - DEMON_TrapChunkList *trap_list = &joined_traps; + DMN_TrapChunkList *trap_list = &joined_traps; if(spoof_mode) { trap_list = &user_traps; @@ -2703,16 +2840,16 @@ ctrl_thread__run(CTRL_Msg *msg) ////////////////////////// //- rjf: setup run controls // - DEMON_RunCtrls run_ctrls = {0}; + DMN_RunCtrls run_ctrls = {0}; run_ctrls.ignore_previous_exception = 1; run_ctrls.run_entity_count = msg->freeze_state_threads.count; - run_ctrls.run_entities = push_array(scratch.arena, DEMON_Handle, run_ctrls.run_entity_count); + run_ctrls.run_entities = push_array(scratch.arena, DMN_Handle, run_ctrls.run_entity_count); run_ctrls.run_entities_are_unfrozen = !msg->freeze_state_is_frozen; { U64 idx = 0; for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next) { - run_ctrls.run_entities[idx] = ctrl_demon_handle_from_ctrl(n->v.handle); + run_ctrls.run_entities[idx] = n->v.handle; idx += 1; } } @@ -2721,61 +2858,61 @@ ctrl_thread__run(CTRL_Msg *msg) ////////////////////////// //- rjf: get next event // - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, run_spoof); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, run_spoof); ////////////////////////// //- rjf: determine event handling // B32 hard_stop = 0; - CTRL_EventCause hard_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + CTRL_EventCause hard_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); B32 use_stepping_logic = 0; switch(event->kind) { default:{}break; - case DEMON_EventKind_Error: - case DEMON_EventKind_Halt: - case DEMON_EventKind_SingleStep: - case DEMON_EventKind_Trap: + case DMN_EventKind_Error: + case DMN_EventKind_Halt: + case DMN_EventKind_SingleStep: + case DMN_EventKind_Trap: { hard_stop = 1; }break; - case DEMON_EventKind_Exception: - case DEMON_EventKind_Breakpoint: + case DMN_EventKind_Exception: + case DMN_EventKind_Breakpoint: { use_stepping_logic = 1; }break; - case DEMON_EventKind_CreateProcess: + case DMN_EventKind_CreateProcess: { - DEMON_TrapChunkList new_traps = {0}; + DMN_TrapChunkList new_traps = {0}; ctrl_append_resolved_process_user_bp_traps(scratch.arena, event->process, &msg->user_bps, &new_traps); - demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); }break; - case DEMON_EventKind_LoadModule: + case DMN_EventKind_LoadModule: { - DEMON_TrapChunkList new_traps = {0}; + DMN_TrapChunkList new_traps = {0}; ctrl_append_resolved_module_user_bp_traps(scratch.arena, event->process, event->module, &msg->user_bps, &new_traps); - demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); - demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); }break; } ////////////////////////// //- rjf: unpack info about thread attached to event // - Architecture arch = demon_arch_from_object(event->thread); + Architecture arch = dmn_arch_from_object(event->thread); U64 reg_size = regs_block_size_from_architecture(arch); - void *thread_regs_block = demon_read_regs(event->thread); + void *thread_regs_block = dmn_read_regs(event->thread); U64 thread_rip_vaddr = regs_rip_from_arch_block(arch, thread_regs_block); - DEMON_Handle module = 0; + DMN_Handle module = {0}; U64 thread_rip_voff = 0; { Temp temp = temp_begin(scratch.arena); - DEMON_HandleArray modules = demon_modules_from_process(temp.arena, event->process); + DMN_HandleArray modules = dmn_modules_from_process(temp.arena, event->process); if(modules.count != 0) { for(U64 idx = 0; idx < modules.count; idx += 1) { - Rng1U64 vaddr_range = demon_vaddr_range_from_module(modules.handles[idx]); + Rng1U64 vaddr_range = dmn_vaddr_range_from_module(modules.handles[idx]); if(contains_1u64(vaddr_range, thread_rip_vaddr)) { module = modules.handles[idx]; @@ -2799,12 +2936,12 @@ ctrl_thread__run(CTRL_Msg *msg) B32 exception_stop = 0; if(use_stepping_logic) { - if(event->kind == DEMON_EventKind_Exception) + if(event->kind == DMN_EventKind_Exception) { // rjf: spoof check if(spoof_mode && - target_process == event->process && - target_thread == event->thread && + dmn_handle_match(target_process, event->process) && + dmn_handle_match(target_thread, event->thread) && spoof.new_ip_value == event->instruction_pointer) { hit_spoof = 1; @@ -2837,21 +2974,21 @@ ctrl_thread__run(CTRL_Msg *msg) CTRL_TrapFlags hit_trap_flags = 0; if(use_stepping_logic) { - if(event->kind == DEMON_EventKind_Breakpoint) + if(event->kind == DMN_EventKind_Breakpoint) { Temp temp = temp_begin(scratch.arena); String8List conditions = {0}; // rjf: user breakpoints - for(DEMON_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) + for(DMN_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) { - DEMON_Trap *trap = n->v; - DEMON_Trap *opl = n->v + n->count; + DMN_Trap *trap = n->v; + DMN_Trap *opl = n->v + n->count; for(;trap < opl; trap += 1) { - if(trap->process == event->process && - trap->address == event->instruction_pointer && - (event->thread != target_thread || !target_thread_is_on_user_bp_and_trap_net_trap)) + if(dmn_handle_match(trap->process, event->process) && + trap->vaddr == event->instruction_pointer && + (!dmn_handle_match(event->thread, target_thread) || !target_thread_is_on_user_bp_and_trap_net_trap)) { CTRL_UserBreakpoint *user_bp = (CTRL_UserBreakpoint *)trap->id; hit_user_bp = 1; @@ -2866,7 +3003,7 @@ ctrl_thread__run(CTRL_Msg *msg) // rjf: evaluate hit stop conditions if(conditions.node_count != 0) { - String8 exe_path = demon_full_path_from_module(temp.arena, module); + String8 exe_path = dmn_full_path_from_module(temp.arena, module); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); RDI_Parsed *rdi = &dbgi->rdi; for(String8Node *condition_n = conditions.first; condition_n != 0; condition_n = condition_n->next) @@ -2906,10 +3043,10 @@ ctrl_thread__run(CTRL_Msg *msg) EVAL_Result eval = {0}; if(bytecode.size != 0) { - U64 module_base = demon_base_vaddr_from_module(module); + U64 module_base = dmn_base_vaddr_from_module(module); U64 tls_base = 0; // TODO(rjf) EVAL_Machine machine = {0}; - machine.u = (void *)event->process; + machine.u = &event->process; machine.arch = arch; machine.memory_read = ctrl_eval_memory_read; machine.reg_data = thread_regs_block; @@ -2933,7 +3070,7 @@ ctrl_thread__run(CTRL_Msg *msg) } // rjf: gather trap net hits - if(!hit_user_bp && event->process == target_process) + if(!hit_user_bp && dmn_handle_match(event->process, target_process)) { for(CTRL_TrapNode *node = msg->traps.first; node != 0; @@ -2956,28 +3093,28 @@ ctrl_thread__run(CTRL_Msg *msg) CTRL_EventCause cond_bp_single_step_stop_cause = CTRL_EventCause_Null; if(hit_conditional_bp_but_filtered) { - DEMON_RunCtrls single_step_ctrls = {0}; + DMN_RunCtrls single_step_ctrls = {0}; single_step_ctrls.single_step_thread = event->thread; for(B32 single_step_done = 0; single_step_done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &single_step_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &single_step_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_Error: - case DEMON_EventKind_Exception: - case DEMON_EventKind_Halt: - case DEMON_EventKind_Trap: + case DMN_EventKind_Error: + case DMN_EventKind_Exception: + case DMN_EventKind_Halt: + case DMN_EventKind_Trap: { cond_bp_single_step_stop = 1; single_step_done = 1; use_stepping_logic = 0; - cond_bp_single_step_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + cond_bp_single_step_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); }break; - case DEMON_EventKind_SingleStep: + case DMN_EventKind_SingleStep: { single_step_done = 1; - cond_bp_single_step_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + cond_bp_single_step_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); }break; } } @@ -2995,7 +3132,7 @@ ctrl_thread__run(CTRL_Msg *msg) B32 step_past_trap_net = 0; if(use_stepping_logic && hit_trap_net_bp) { - if(event->thread != target_thread) + if(!dmn_handle_match(event->thread, target_thread)) { step_past_trap_net = 1; use_stepping_logic = 0; @@ -3006,7 +3143,7 @@ ctrl_thread__run(CTRL_Msg *msg) B32 use_trap_net_logic = 0; if(use_stepping_logic && hit_trap_net_bp) { - if(event->thread == target_thread) + if(dmn_handle_match(event->thread, target_thread)) { use_trap_net_logic = 1; } @@ -3016,7 +3153,7 @@ ctrl_thread__run(CTRL_Msg *msg) B32 stack_pointer_matches = 0; if(use_trap_net_logic) { - U64 sp = demon_read_sp(target_thread); + U64 sp = dmn_read_sp(target_thread); stack_pointer_matches = (sp == sp_check_value); } @@ -3027,29 +3164,29 @@ ctrl_thread__run(CTRL_Msg *msg) { if(hit_trap_flags & CTRL_TrapFlag_SingleStepAfterHit) { - DEMON_RunCtrls single_step_ctrls = {0}; + DMN_RunCtrls single_step_ctrls = {0}; single_step_ctrls.single_step_thread = target_thread; for(B32 single_step_done = 0; single_step_done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &single_step_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &single_step_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_Error: - case DEMON_EventKind_Exception: - case DEMON_EventKind_Halt: - case DEMON_EventKind_Trap: + case DMN_EventKind_Error: + case DMN_EventKind_Exception: + case DMN_EventKind_Halt: + case DMN_EventKind_Trap: { single_step_stop = 1; single_step_done = 1; use_stepping_logic = 0; use_trap_net_logic = 0; - single_step_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + single_step_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); }break; - case DEMON_EventKind_SingleStep: + case DMN_EventKind_SingleStep: { single_step_done = 1; - single_step_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + single_step_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); }break; } } @@ -3064,10 +3201,10 @@ ctrl_thread__run(CTRL_Msg *msg) { // rjf: setup spoof mode begin_spoof_mode = 1; - U64 spoof_sp = demon_read_sp(target_thread); + U64 spoof_sp = dmn_read_sp(target_thread); spoof_mode = 1; - spoof.process = ctrl_handle_from_demon(target_process); - spoof.thread = ctrl_handle_from_demon(target_thread); + spoof.process = target_process; + spoof.thread = target_thread; spoof.vaddr = spoof_sp; spoof.new_ip_value = spoof_ip_vaddr; } @@ -3082,7 +3219,7 @@ ctrl_thread__run(CTRL_Msg *msg) if(stack_pointer_matches) { save_stack_pointer = 1; - sp_check_value = demon_read_sp(target_thread); + sp_check_value = dmn_read_sp(target_thread); } } } @@ -3112,27 +3249,27 @@ ctrl_thread__run(CTRL_Msg *msg) CTRL_EventCause step_past_trap_net_stop_cause = CTRL_EventCause_Null; if(step_past_trap_net) { - DEMON_RunCtrls single_step_ctrls = {0}; + DMN_RunCtrls single_step_ctrls = {0}; single_step_ctrls.single_step_thread = event->thread; for(B32 single_step_done = 0; single_step_done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &single_step_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &single_step_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_Error: - case DEMON_EventKind_Exception: - case DEMON_EventKind_Halt: - case DEMON_EventKind_Trap: + case DMN_EventKind_Error: + case DMN_EventKind_Exception: + case DMN_EventKind_Halt: + case DMN_EventKind_Trap: { step_past_trap_net_stop = 1; single_step_done = 1; - step_past_trap_net_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + step_past_trap_net_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); }break; - case DEMON_EventKind_SingleStep: + case DMN_EventKind_SingleStep: { single_step_done = 1; - step_past_trap_net_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + step_past_trap_net_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); }break; } } @@ -3186,9 +3323,9 @@ ctrl_thread__run(CTRL_Msg *msg) CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); event->kind = CTRL_EventKind_Stopped; event->cause = stop_cause; - event->machine_id = CTRL_MachineID_Client; - event->entity = ctrl_handle_from_demon(stop_event->thread); - event->parent = ctrl_handle_from_demon(stop_event->process); + event->machine_id = CTRL_MachineID_Local; + event->entity = stop_event->thread; + event->parent = stop_event->process; event->exception_code = stop_event->code; event->vaddr_rng = r1u64(stop_event->address, stop_event->address); event->rip_vaddr = stop_event->instruction_pointer; @@ -3216,23 +3353,23 @@ ctrl_thread__single_step(CTRL_Msg *msg) } //- rjf: single step - DEMON_Event *stop_event = 0; + DMN_Event *stop_event = 0; CTRL_EventCause stop_cause = CTRL_EventCause_Null; { - DEMON_RunCtrls run_ctrls = {0}; - run_ctrls.single_step_thread = ctrl_demon_handle_from_ctrl(msg->entity); + DMN_RunCtrls run_ctrls = {0}; + run_ctrls.single_step_thread = msg->entity; for(B32 done = 0; done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_Error: {stop_cause = CTRL_EventCause_Error;}goto end_single_step; - case DEMON_EventKind_Exception: {stop_cause = CTRL_EventCause_InterruptedByException;}goto end_single_step; - case DEMON_EventKind_Halt: {stop_cause = CTRL_EventCause_InterruptedByHalt;}goto end_single_step; - case DEMON_EventKind_Trap: {stop_cause = CTRL_EventCause_InterruptedByTrap;}goto end_single_step; - case DEMON_EventKind_SingleStep: {stop_cause = CTRL_EventCause_Finished;}goto end_single_step; - case DEMON_EventKind_Breakpoint: {stop_cause = CTRL_EventCause_UserBreakpoint;}goto end_single_step; + case DMN_EventKind_Error: {stop_cause = CTRL_EventCause_Error;}goto end_single_step; + case DMN_EventKind_Exception: {stop_cause = CTRL_EventCause_InterruptedByException;}goto end_single_step; + case DMN_EventKind_Halt: {stop_cause = CTRL_EventCause_InterruptedByHalt;}goto end_single_step; + case DMN_EventKind_Trap: {stop_cause = CTRL_EventCause_InterruptedByTrap;}goto end_single_step; + case DMN_EventKind_SingleStep: {stop_cause = CTRL_EventCause_Finished;}goto end_single_step; + case DMN_EventKind_Breakpoint: {stop_cause = CTRL_EventCause_UserBreakpoint;}goto end_single_step; end_single_step: { stop_event = event; @@ -3249,9 +3386,9 @@ ctrl_thread__single_step(CTRL_Msg *msg) CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); event->kind = CTRL_EventKind_Stopped; event->cause = stop_cause; - event->machine_id = CTRL_MachineID_Client; - event->entity = ctrl_handle_from_demon(stop_event->thread); - event->parent = ctrl_handle_from_demon(stop_event->process); + event->machine_id = CTRL_MachineID_Local; + event->entity = stop_event->thread; + event->parent = stop_event->process; event->exception_code = stop_event->code; event->vaddr_rng = r1u64(stop_event->address, stop_event->address); event->rip_vaddr = stop_event->instruction_pointer; @@ -3276,7 +3413,7 @@ ctrl_mem_stream_thread__entry_point(void *p) { //- rjf: unpack next request CTRL_MachineID machine_id = 0; - CTRL_Handle process = {0}; + DMN_Handle process = {0}; Rng1U64 vaddr_range = {0}; B32 zero_terminated = 0; ctrl_u2ms_dequeue_req(&machine_id, &process, &vaddr_range, &zero_terminated); diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index f507548d..840cef5c 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -10,16 +10,7 @@ typedef U64 CTRL_MsgID; typedef U64 CTRL_MachineID; -#define CTRL_MachineID_Client (1) - -//////////////////////////////// -//~ rjf: Handle Type - -typedef struct CTRL_Handle CTRL_Handle; -struct CTRL_Handle -{ - U64 u64[1]; -}; +#define CTRL_MachineID_Local (1) //////////////////////////////// //~ rjf: Machine/Handle Pair Types @@ -28,7 +19,7 @@ typedef struct CTRL_MachineIDHandlePair CTRL_MachineIDHandlePair; struct CTRL_MachineIDHandlePair { CTRL_MachineID machine_id; - CTRL_Handle handle; + DMN_Handle handle; }; typedef struct CTRL_MachineIDHandlePairNode CTRL_MachineIDHandlePairNode; @@ -46,6 +37,52 @@ struct CTRL_MachineIDHandlePairList U64 count; }; +//////////////////////////////// +//~ rjf: Entity Types + +typedef enum CTRL_EntityKind +{ + CTRL_EntityKind_Null, + CTRL_EntityKind_Root, + CTRL_EntityKind_Machine, + CTRL_EntityKind_Process, + CTRL_EntityKind_Thread, + CTRL_EntityKind_Module, + CTRL_EntityKind_COUNT +} +CTRL_EntityKind; + +typedef struct CTRL_Entity CTRL_Entity; +struct CTRL_Entity +{ + CTRL_Entity *first; + CTRL_Entity *last; + CTRL_Entity *next; + CTRL_Entity *prev; + CTRL_Entity *parent; + CTRL_EntityKind kind; + Architecture arch; + CTRL_MachineID machine_id; + DMN_Handle handle; + Rng1U64 vaddr_range; + String8 name; +}; + +typedef struct CTRL_EntityHashNode CTRL_EntityHashNode; +struct CTRL_EntityHashNode +{ + CTRL_EntityHashNode *next; + CTRL_EntityHashNode *prev; + CTRL_Entity *entity; +}; + +typedef struct CTRL_EntityHashSlot CTRL_EntityHashSlot; +struct CTRL_EntityHashSlot +{ + CTRL_EntityHashNode *first; + CTRL_EntityHashNode *last; +}; + //////////////////////////////// //~ rjf: Unwind Types @@ -105,8 +142,8 @@ struct CTRL_TrapList typedef struct CTRL_Spoof CTRL_Spoof; struct CTRL_Spoof { - CTRL_Handle process; - CTRL_Handle thread; + DMN_Handle process; + DMN_Handle thread; U64 vaddr; U64 new_ip_value; }; @@ -177,8 +214,8 @@ struct CTRL_Msg CTRL_MsgKind kind; CTRL_MsgID msg_id; CTRL_MachineID machine_id; - CTRL_Handle entity; - CTRL_Handle parent; + DMN_Handle entity; + DMN_Handle parent; U32 entity_id; U32 exit_code; B32 env_inherit; @@ -281,8 +318,8 @@ struct CTRL_Event CTRL_ExceptionKind exception_kind; CTRL_MsgID msg_id; CTRL_MachineID machine_id; - CTRL_Handle entity; - CTRL_Handle parent; + DMN_Handle entity; + DMN_Handle parent; Architecture arch; U64 u64_code; U32 entity_id; @@ -338,7 +375,7 @@ struct CTRL_ProcessMemoryCacheNode CTRL_ProcessMemoryCacheNode *prev; Arena *arena; CTRL_MachineID machine_id; - CTRL_Handle process; + DMN_Handle process; U64 range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_hash_slots; }; @@ -374,6 +411,42 @@ struct CTRL_ProcessMemorySlice U64 *byte_changed_flags; }; +//////////////////////////////// +//~ rjf: Thread Register Cache Types + +typedef struct CTRL_ThreadRegCacheNode CTRL_ThreadRegCacheNode; +struct CTRL_ThreadRegCacheNode +{ + CTRL_ThreadRegCacheNode *next; + CTRL_ThreadRegCacheNode *prev; + CTRL_MachineID machine_id; + DMN_Handle thread; + U128 regs_hash; +}; + +typedef struct CTRL_ThreadRegCacheSlot CTRL_ThreadRegCacheSlot; +struct CTRL_ThreadRegCacheSlot +{ + CTRL_ThreadRegCacheNode *first; + CTRL_ThreadRegCacheNode *last; +}; + +typedef struct CTRL_ThreadRegCacheStripe CTRL_ThreadRegCacheStripe; +struct CTRL_ThreadRegCacheStripe +{ + Arena *arena; + OS_Handle rw_mutex; +}; + +typedef struct CTRL_ThreadRegCache CTRL_ThreadRegCache; +struct CTRL_ThreadRegCache +{ + U64 slots_count; + CTRL_ThreadRegCacheSlot *slots; + U64 stripes_count; + CTRL_ThreadRegCacheStripe *stripes; +}; + //////////////////////////////// //~ rjf: Wakeup Hook Function Types @@ -396,8 +469,9 @@ struct CTRL_State EVAL_String2NumMap arch_string2reg_tables[Architecture_COUNT]; EVAL_String2NumMap arch_string2alias_tables[Architecture_COUNT]; - // rjf: process memory cache + // rjf: caches CTRL_ProcessMemoryCache process_memory_cache; + CTRL_ThreadRegCache thread_reg_cache; // rjf: user -> ctrl msg ring buffer U64 u2c_ring_size; @@ -417,10 +491,16 @@ struct CTRL_State // rjf: ctrl thread state OS_Handle ctrl_thread; - Arena *demon_event_arena; - DEMON_EventNode *first_demon_event_node; - DEMON_EventNode *last_demon_event_node; - DEMON_EventNode *free_demon_event_node; + Arena *ctrl_entity_arena; + CTRL_Entity *ctrl_entity_root; + CTRL_Entity *ctrl_entity_free; + CTRL_EntityHashSlot *ctrl_entity_hash_slots; + CTRL_EntityHashNode *ctrl_entity_hash_node_free; + U64 ctrl_entity_hash_slots_count; + Arena *dmn_event_arena; + DMN_EventNode *first_dmn_event_node; + DMN_EventNode *last_dmn_event_node; + DMN_EventNode *free_dmn_event_node; Arena *user_entry_point_arena; String8List user_entry_points; U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]; @@ -443,29 +523,22 @@ struct CTRL_State //~ rjf: Globals global CTRL_State *ctrl_state = 0; - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void ctrl_init(void); - -//////////////////////////////// -//~ rjf: Wakeup Callback Registration - -internal void ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook); +read_only global CTRL_Entity ctrl_entity_nil = +{ + &ctrl_entity_nil, + &ctrl_entity_nil, + &ctrl_entity_nil, + &ctrl_entity_nil, + &ctrl_entity_nil, +}; //////////////////////////////// //~ rjf: Basic Type Functions internal U64 ctrl_hash_from_string(String8 string); -internal CTRL_EventCause ctrl_event_cause_from_demon_event_kind(DEMON_EventKind event_kind); -internal B32 ctrl_handle_match(CTRL_Handle a, CTRL_Handle b); - -//////////////////////////////// -//~ rjf: Ctrl <-> Demon Handle Translation Functions - -internal DEMON_Handle ctrl_demon_handle_from_ctrl(CTRL_Handle h); -internal CTRL_Handle ctrl_handle_from_demon(DEMON_Handle h); +internal U64 ctrl_hash_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle); +internal CTRL_EventCause ctrl_event_cause_from_dmn_event_kind(DMN_EventKind event_kind); +internal B32 ctrl_handle_match(DMN_Handle a, DMN_Handle b); //////////////////////////////// //~ rjf: Machine/Handle Pair Type Functions @@ -484,8 +557,8 @@ internal CTRL_TrapList ctrl_trap_list_copy(Arena *arena, CTRL_TrapList *src); internal void ctrl_user_breakpoint_list_push(Arena *arena, CTRL_UserBreakpointList *list, CTRL_UserBreakpoint *bp); internal CTRL_UserBreakpointList ctrl_user_breakpoint_list_copy(Arena *arena, CTRL_UserBreakpointList *src); -internal void ctrl_append_resolved_module_user_bp_traps(Arena *arena, DEMON_Handle process, DEMON_Handle module, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out); -internal void ctrl_append_resolved_process_user_bp_traps(Arena *arena, DEMON_Handle process, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out); +internal void ctrl_append_resolved_module_user_bp_traps(Arena *arena, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +internal void ctrl_append_resolved_process_user_bp_traps(Arena *arena, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); //////////////////////////////// //~ rjf: Message Type Functions @@ -512,80 +585,82 @@ internal String8 ctrl_serialized_string_from_event(Arena *arena, CTRL_Event *eve internal CTRL_Event ctrl_event_from_serialized_string(Arena *arena, String8 string); //////////////////////////////// -//~ rjf: Shared Functions +//~ rjf: Main Layer Initialization -//- rjf: run index +internal void ctrl_init(void); + +//////////////////////////////// +//~ rjf: Wakeup Callback Registration + +internal void ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook); + +//////////////////////////////// +//~ rjf: Process Memory Functions + +//- rjf: process memory cache interaction +internal U128 ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated); +internal U128 ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated, U64 endt_us); + +//- rjf: process memory cache reading helpers +internal CTRL_ProcessMemorySlice ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, U64 endt_us); +internal CTRL_ProcessMemorySlice ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, U64 vaddr, U64 limit, U64 endt_us); + +//- rjf: process memory writing +internal B32 ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *src); + +//////////////////////////////// +//~ rjf: Thread Register Functions + +//- rjf: thread register cache reading +internal void *ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us); +internal U64 ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, DMN_Handle thread); + +//- rjf: thread register writing +internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block); + +//////////////////////////////// +//~ rjf: Unwinding Functions + +internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread); + +//////////////////////////////// +//~ rjf: Halting All Attached Processes + +internal void ctrl_halt(void); + +//////////////////////////////// +//~ rjf: Shared Accessor Functions + +//- rjf: run indices internal U64 ctrl_run_idx(void); internal U64 ctrl_memgen_idx(void); internal U64 ctrl_reggen_idx(void); -//- rjf: halt everything -internal void ctrl_halt(void); - -//- rjf: exe -> dbg path mapping -internal String8 ctrl_inferred_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path); -internal String8 ctrl_forced_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path); -internal String8 ctrl_natural_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path); -internal String8 ctrl_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path); - -//- rjf: handle -> arch -internal Architecture ctrl_arch_from_handle(CTRL_MachineID machine, CTRL_Handle handle); - -//- rjf: process memory reading/writing -internal U64 ctrl_process_read(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *dst); -internal B32 ctrl_process_write(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *src); - -//- rjf: process memory cache interaction -internal U128 ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated); -internal U128 ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated, U64 endt_us); - -//- rjf: process memory cache reading helpers -internal CTRL_ProcessMemorySlice ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, U64 endt_us); -internal CTRL_ProcessMemorySlice ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr, U64 limit, U64 endt_us); - -//- rjf: register reading/writing -internal void *ctrl_reg_block_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread); -internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, CTRL_Handle thread, void *block); -internal U64 ctrl_rip_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread); -internal B32 ctrl_thread_write_rip(CTRL_MachineID machine_id, CTRL_Handle thread, U64 rip); -internal U64 ctrl_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread); - -//- rjf: process * vaddr -> module -internal CTRL_Handle ctrl_module_from_process_vaddr(CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr); - -//- rjf: unwinding -internal CTRL_Unwind ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, CTRL_Handle thread); - //- rjf: name -> register/alias hash tables, for eval internal EVAL_String2NumMap *ctrl_string2reg_from_arch(Architecture arch); internal EVAL_String2NumMap *ctrl_string2alias_from_arch(Architecture arch); //////////////////////////////// -//~ rjf: User -> Ctrl Communication +//~ rjf: Control-Thread Functions +//- rjf: user -> control thread communication internal B32 ctrl_u2c_push_msgs(CTRL_MsgList *msgs, U64 endt_us); internal CTRL_MsgList ctrl_u2c_pop_msgs(Arena *arena); -//////////////////////////////// -//~ rjf: Ctrl -> User Communication - +//- rjf: control -> user thread communication internal void ctrl_c2u_push_events(CTRL_EventList *events); internal CTRL_EventList ctrl_c2u_pop_events(Arena *arena); -//////////////////////////////// -//~ rjf: User -> Memory Stream Communication - -internal B32 ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us); -internal void ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated); - -//////////////////////////////// -//~ rjf: Control-Thread-Only Functions +//- rjf: entity tree construction +internal CTRL_Entity *ctrl_thread__entity_alloc(CTRL_Entity *parent, CTRL_EntityKind kind, CTRL_MachineID machine_id, DMN_Handle handle); +internal void ctrl_thread__entity_release(CTRL_Entity *entity); +internal CTRL_Entity *ctrl_thread__entity_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle); //- rjf: entry point internal void ctrl_thread__entry_point(void *p); //- rjf: attached process running/event gathering -internal DEMON_Event *ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_ctrls, CTRL_Spoof *spoof); +internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof); //- rjf: eval helpers internal B32 ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size); @@ -600,9 +675,13 @@ internal void ctrl_thread__run(CTRL_Msg *msg); internal void ctrl_thread__single_step(CTRL_Msg *msg); //////////////////////////////// -//~ rjf: Memory-Stream-Thread-Only Functions +//~ rjf: Memory-Stream Thread Functions + +//- rjf: user -> memory stream communication +internal B32 ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us); +internal void ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, DMN_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated); //- rjf: entry point internal void ctrl_mem_stream_thread__entry_point(void *p); -#endif //CTRL_CORE_H +#endif // CTRL_CORE_H diff --git a/src/dasm/dasm.c b/src/dasm/dasm.c index 734b35f5..0a0c9855 100644 --- a/src/dasm/dasm.c +++ b/src/dasm/dasm.c @@ -179,7 +179,7 @@ dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_coun //- rjf: opening handles & correllation with module internal DASM_Handle -dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range) +dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, DMN_Handle process, Rng1U64 vaddr_range) { DASM_Handle result = {0}; if(machine != 0 && process.u64[0] != 0) @@ -389,7 +389,7 @@ dasm_decode_thread_entry_point(void *p) //- rjf: request -> ctrl info B32 is_first_to_task = 0; CTRL_MachineID ctrl_machine_id = 0; - CTRL_Handle ctrl_process = {0}; + DMN_Handle ctrl_process = {0}; Rng1U64 vaddr_range = {0}; Architecture arch = Architecture_Null; U64 *bytes_processed_counter = 0; diff --git a/src/dasm/dasm.h b/src/dasm/dasm.h index a49412e0..61200578 100644 --- a/src/dasm/dasm.h +++ b/src/dasm/dasm.h @@ -77,7 +77,7 @@ struct DASM_Entity // rjf: key info CTRL_MachineID machine_id; - CTRL_Handle process; + DMN_Handle process; Rng1U64 vaddr_range; U64 id; @@ -114,7 +114,7 @@ typedef struct DASM_BinaryInfo DASM_BinaryInfo; struct DASM_BinaryInfo { CTRL_MachineID machine_id; - CTRL_Handle process; + DMN_Handle process; Rng1U64 vaddr_range; U64 bytes_processed; U64 bytes_to_process; @@ -187,7 +187,7 @@ internal DASM_InstChunkList dasm_inst_chunk_list_from_arch_addr_data(Arena *aren //~ rjf: Cache Lookups //- rjf: opening handles & correllation with module -internal DASM_Handle dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range); +internal DASM_Handle dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, DMN_Handle process, Rng1U64 vaddr_range); //- rjf: asking for top-level info of a handle internal DASM_BinaryInfo dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle); diff --git a/src/demon2/demon2_core.h b/src/demon2/demon2_core.h index 0beedca4..5eeacd22 100644 --- a/src/demon2/demon2_core.h +++ b/src/demon2/demon2_core.h @@ -182,16 +182,16 @@ internal B32 dmn_detach_process(DMN_Handle process); //~ rjf: @dmn_os_hooks Process/Thread Reads/Writes (Implemented Per-OS) //- rjf: processes -internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst); -internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src); +internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst); +internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src); #define dmn_process_read_struct(process, vaddr, ptr) dmn_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) #define dmn_process_write_struct(process, vaddr, ptr) dmn_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) //- rjf: threads -internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle); -internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle); -internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block); -internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block); +internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle); +internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle); +internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block); +internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block); //////////////////////////////// //~ rjf: @dmn_os_hooks System Process Listing (Implemented Per-OS) diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 7f48339e..46e3ffac 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -2025,7 +2025,7 @@ df_entity_equip_ctrl_machine_id(DF_Entity *entity, CTRL_MachineID machine_id) } internal void -df_entity_equip_ctrl_handle(DF_Entity *entity, CTRL_Handle handle) +df_entity_equip_ctrl_handle(DF_Entity *entity, DMN_Handle handle) { df_require_entity_nonnil(entity, return); entity->ctrl_handle = handle; @@ -2419,7 +2419,7 @@ df_machine_entity_from_machine_id(CTRL_MachineID machine_id) } internal DF_Entity * -df_entity_from_ctrl_handle(CTRL_MachineID machine_id, CTRL_Handle handle) +df_entity_from_ctrl_handle(CTRL_MachineID machine_id, DMN_Handle handle) { DF_Entity *result = &df_g_nil_entity; if(handle.u64[0] != 0) @@ -6417,7 +6417,7 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist) // rjf: set up initial entities { DF_Entity *local_machine = df_entity_alloc(0, df_state->entities_root, DF_EntityKind_Machine); - df_entity_equip_ctrl_machine_id(local_machine, CTRL_MachineID_Client); + df_entity_equip_ctrl_machine_id(local_machine, CTRL_MachineID_Local); df_entity_equip_name(0, local_machine, str8_lit("This PC")); } @@ -7512,7 +7512,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) }break; case DF_CoreCmdKind_FreezeLocalMachine: { - CTRL_MachineID machine_id = CTRL_MachineID_Client; + CTRL_MachineID machine_id = CTRL_MachineID_Local; DF_CmdParams params = df_cmd_params_zero(); params.entity = df_handle_from_entity(df_machine_entity_from_machine_id(machine_id)); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); @@ -7520,7 +7520,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) }break; case DF_CoreCmdKind_ThawLocalMachine: { - CTRL_MachineID machine_id = CTRL_MachineID_Client; + CTRL_MachineID machine_id = CTRL_MachineID_Local; DF_CmdParams params = df_cmd_params_zero(); params.entity = df_handle_from_entity(df_machine_entity_from_machine_id(machine_id)); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index df3e866d..5edc70ae 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -447,7 +447,7 @@ struct DF_Entity // rjf: ctrl entity equipment CTRL_MachineID ctrl_machine_id; - CTRL_Handle ctrl_handle; + DMN_Handle ctrl_handle; Architecture arch; U32 ctrl_id; U64 stack_base; @@ -1447,7 +1447,7 @@ internal void df_entity_equip_cfg_src(DF_Entity *entity, DF_CfgSrc cfg_src); //- rjf: control layer correllation equipment internal void df_entity_equip_ctrl_machine_id(DF_Entity *entity, CTRL_MachineID machine_id); -internal void df_entity_equip_ctrl_handle(DF_Entity *entity, CTRL_Handle handle); +internal void df_entity_equip_ctrl_handle(DF_Entity *entity, DMN_Handle handle); internal void df_entity_equip_arch(DF_Entity *entity, Architecture arch); internal void df_entity_equip_ctrl_id(DF_Entity *entity, U32 id); internal void df_entity_equip_stack_base(DF_Entity *entity, U64 stack_base); @@ -1468,7 +1468,7 @@ internal DF_Entity *df_entity_root(void); internal DF_EntityList df_push_entity_list_with_kind(Arena *arena, DF_EntityKind kind); internal DF_Entity *df_entity_from_id(DF_EntityID id); internal DF_Entity *df_machine_entity_from_machine_id(CTRL_MachineID machine_id); -internal DF_Entity *df_entity_from_ctrl_handle(CTRL_MachineID machine_id, CTRL_Handle handle); +internal DF_Entity *df_entity_from_ctrl_handle(CTRL_MachineID machine_id, DMN_Handle handle); internal DF_Entity *df_entity_from_ctrl_id(CTRL_MachineID machine_id, U32 id); internal DF_Entity *df_entity_from_name_and_kind(String8 string, DF_EntityKind kind); internal DF_Entity *df_entity_from_u64_and_kind(U64 u64, DF_EntityKind kind); diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index 02e32ecf..d21ad724 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -46,7 +46,7 @@ #include "demon2/demon2_inc.h" #include "eval/eval_inc.h" #include "unwind/unwind.h" -#include "ctrl2/ctrl2_inc.h" +#include "ctrl/ctrl_inc.h" //- rjf: [c] #include "base/base_inc.c" @@ -74,7 +74,7 @@ #include "demon2/demon2_inc.c" #include "eval/eval_inc.c" #include "unwind/unwind.c" -#include "ctrl2/ctrl2_inc.c" +#include "ctrl/ctrl_inc.c" //////////////////////////////// //~ rjf: Entry Point From 27493017776bf28c508679ed3a5b2c4fbf498875 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 12 Mar 2024 11:41:53 -0700 Subject: [PATCH 02/33] checkpoint - moving ctrl mostly over to demon2; sketching out a few missing cache pieces --- src/ctrl/ctrl_core.c | 1335 ++++++++++++-------------- src/ctrl/ctrl_core.h | 29 +- src/demon2/demon2_core.h | 1 + src/demon2/win32/demon2_core_win32.c | 9 + 4 files changed, 660 insertions(+), 714 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 36e00aaa..cd951f07 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -6,92 +6,6 @@ #include "generated/ctrl.meta.c" -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -ctrl_init(void) -{ - Arena *arena = arena_alloc(); - ctrl_state = push_array(arena, CTRL_State, 1); - ctrl_state->arena = arena; - for(Architecture arch = (Architecture)0; arch < Architecture_COUNT; arch = (Architecture)(arch+1)) - { - String8 *reg_names = regs_reg_code_string_table_from_architecture(arch); - U64 reg_count = regs_reg_code_count_from_architecture(arch); - String8 *alias_names = regs_alias_code_string_table_from_architecture(arch); - U64 alias_count = regs_alias_code_count_from_architecture(arch); - ctrl_state->arch_string2reg_tables[arch] = eval_string2num_map_make(ctrl_state->arena, 256); - ctrl_state->arch_string2alias_tables[arch] = eval_string2num_map_make(ctrl_state->arena, 256); - for(U64 idx = 1; idx < reg_count; idx += 1) - { - eval_string2num_map_insert(ctrl_state->arena, &ctrl_state->arch_string2reg_tables[arch], reg_names[idx], idx); - } - for(U64 idx = 1; idx < alias_count; idx += 1) - { - eval_string2num_map_insert(ctrl_state->arena, &ctrl_state->arch_string2alias_tables[arch], alias_names[idx], idx); - } - } - ctrl_state->process_memory_cache.slots_count = 256; - ctrl_state->process_memory_cache.slots = push_array(arena, CTRL_ProcessMemoryCacheSlot, ctrl_state->process_memory_cache.slots_count); - ctrl_state->process_memory_cache.stripes_count = 8; - ctrl_state->process_memory_cache.stripes = push_array(arena, CTRL_ProcessMemoryCacheStripe, ctrl_state->process_memory_cache.stripes_count); - for(U64 idx = 0; idx < ctrl_state->process_memory_cache.stripes_count; idx += 1) - { - ctrl_state->process_memory_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); - ctrl_state->process_memory_cache.stripes[idx].cv = os_condition_variable_alloc(); - } - ctrl_state->thread_reg_cache.slots_count = 1024; - ctrl_state->thread_reg_cache.slots = push_array(arena, CTRL_ThreadRegCacheSlot, ctrl_state->thread_reg_cache.slots_count); - ctrl_state->thread_reg_cache.stripes_count = 8; - ctrl_state->thread_reg_cache.stripes = push_array(arena, CTRL_ThreadRegCacheStripe, ctrl_state->thread_reg_cache.stripes_count); - for(U64 idx = 0; idx < ctrl_state->thread_reg_cache.stripes_count; idx += 1) - { - ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); - ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc(); - } - ctrl_state->ctrl_entity_arena = arena_alloc(); - ctrl_state->ctrl_entity_hash_slots_count = 4096; - ctrl_state->ctrl_entity_hash_slots = push_array(arena, CTRL_EntityHashSlot, ctrl_state->ctrl_entity_hash_slots_count); - ctrl_state->u2c_ring_size = KB(64); - ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); - ctrl_state->u2c_ring_mutex = os_mutex_alloc(); - ctrl_state->u2c_ring_cv = os_condition_variable_alloc(); - ctrl_state->c2u_ring_size = KB(64); - ctrl_state->c2u_ring_base = push_array_no_zero(arena, U8, ctrl_state->c2u_ring_size); - ctrl_state->c2u_ring_mutex = os_mutex_alloc(); - ctrl_state->c2u_ring_cv = os_condition_variable_alloc(); - ctrl_state->dmn_event_arena = arena_alloc(); - ctrl_state->user_entry_point_arena = arena_alloc(); - for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1)) - { - if(ctrl_exception_code_kind_default_enable_table[k]) - { - ctrl_state->exception_code_filters[k/64] |= 1ull<<(k%64); - } - } - ctrl_state->u2ms_ring_size = KB(64); - ctrl_state->u2ms_ring_base = push_array(arena, U8, ctrl_state->u2ms_ring_size); - ctrl_state->u2ms_ring_mutex = os_mutex_alloc(); - ctrl_state->u2ms_ring_cv = os_condition_variable_alloc(); - ctrl_state->ctrl_thread = os_launch_thread(ctrl_thread__entry_point, 0, 0); - ctrl_state->ms_thread_count = Clamp(1, os_logical_core_count()-1, 4); - ctrl_state->ms_threads = push_array(arena, OS_Handle, ctrl_state->ms_thread_count); - for(U64 idx = 0; idx < ctrl_state->ms_thread_count; idx += 1) - { - ctrl_state->ms_threads[idx] = os_launch_thread(ctrl_mem_stream_thread__entry_point, (void *)idx, 0); - } -} - -//////////////////////////////// -//~ rjf: Wakeup Callback Registration - -internal void -ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook) -{ - ctrl_state->wakeup_hook = wakeup_hook; -} - //////////////////////////////// //~ rjf: Basic Type Functions @@ -208,120 +122,6 @@ ctrl_user_breakpoint_list_copy(Arena *arena, CTRL_UserBreakpointList *src) return dst; } -internal void -ctrl_append_resolved_module_user_bp_traps(Arena *arena, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) -{ - Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); - String8 exe_path = dmn_full_path_from_module(scratch.arena, module); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RDI_Parsed *rdi = &dbgi->rdi; - U64 base_vaddr = dmn_base_vaddr_from_module(module); - for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) - { - CTRL_UserBreakpoint *bp = &n->v; - switch(bp->kind) - { - default:{}break; - - //- rjf: file:line-based breakpoints - case CTRL_UserBreakpointKind_FileNameAndLineColNumber: - { - // rjf: unpack & normalize - TxtPt pt = bp->pt; - String8 filename = bp->string; - String8 filename_normalized = push_str8_copy(scratch.arena, filename); - for(U64 idx = 0; idx < filename_normalized.size; idx += 1) - { - filename_normalized.str[idx] = char_to_lower(filename_normalized.str[idx]); - filename_normalized.str[idx] = char_to_correct_slash(filename_normalized.str[idx]); - } - - // rjf: filename -> src_id - U32 src_id = 0; - { - RDI_NameMap *mapptr = rdi_name_map_from_kind(rdi, RDI_NameMapKind_NormalSourcePaths); - if(mapptr != 0) - { - RDI_ParsedNameMap map = {0}; - rdi_name_map_parse(rdi, mapptr, &map); - RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, filename_normalized.str, filename_normalized.size); - if(node != 0) - { - U32 id_count = 0; - U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); - if(id_count > 0) - { - src_id = ids[0]; - } - } - } - } - - // rjf: src_id * pt -> push - { - RDI_SourceFile *src = rdi_element_from_idx(rdi, source_files, src_id); - RDI_ParsedLineMap line_map = {0}; - rdi_line_map_from_source_file(rdi, src, &line_map); - U32 voff_count = 0; - U64 *voffs = rdi_line_voffs_from_num(&line_map, pt.line, &voff_count); - for(U32 i = 0; i < voff_count; i += 1) - { - U64 vaddr = voffs[i] + base_vaddr; - DMN_Trap trap = {process, vaddr, (U64)bp}; - dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); - } - } - }break; - - //- rjf: symbol:voff-based breakpoints - case CTRL_UserBreakpointKind_SymbolNameAndOffset: - { - String8 symbol_name = bp->string; - U64 voff = bp->u64; - if(rdi != 0 && rdi->procedures != 0) - { - RDI_NameMap *mapptr = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Procedures); - if(mapptr != 0) - { - RDI_ParsedNameMap map = {0}; - rdi_name_map_parse(rdi, mapptr, &map); - RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, symbol_name.str, symbol_name.size); - if(node != 0) - { - U32 id_count = 0; - U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); - for(U32 match_i = 0; match_i < id_count; match_i += 1) - { - U64 proc_voff = rdi_first_voff_from_proc(rdi, ids[match_i]); - U64 proc_vaddr = proc_voff + base_vaddr; - DMN_Trap trap = {process, proc_vaddr + voff, (U64)bp}; - dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); - } - } - } - } - }break; - } - } - dbgi_scope_close(scope); - scratch_end(scratch); -} - -internal void -ctrl_append_resolved_process_user_bp_traps(Arena *arena, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) -{ - for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) - { - CTRL_UserBreakpoint *bp = &n->v; - if(bp->kind == CTRL_UserBreakpointKind_VirtualAddress) - { - DMN_Trap trap = {process, bp->u64, (U64)bp}; - dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); - } - } -} - //////////////////////////////// //~ rjf: Message Type Functions @@ -661,182 +461,96 @@ ctrl_event_from_serialized_string(Arena *arena, String8 string) } //////////////////////////////// -//~ rjf: Shared Functions - -//- rjf: run index - -internal U64 -ctrl_run_idx(void) -{ - U64 result = ins_atomic_u64_eval(&ctrl_state->run_idx); - return result; -} - -internal U64 -ctrl_memgen_idx(void) -{ - U64 result = ins_atomic_u64_eval(&ctrl_state->memgen_idx); - return result; -} - -internal U64 -ctrl_reggen_idx(void) -{ - U64 result = ins_atomic_u64_eval(&ctrl_state->reggen_idx); - return result; -} - -//- rjf: halt everything +//~ rjf: Main Layer Initialization internal void -ctrl_halt(void) +ctrl_init(void) { - dmn_halt(0, 0); -} - -//- rjf: exe -> dbg path mapping - -internal String8 -ctrl_inferred_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) -{ - Temp scratch = scratch_begin(&arena, 1); - String8 result = {0}; + Arena *arena = arena_alloc(); + ctrl_state = push_array(arena, CTRL_State, 1); + ctrl_state->arena = arena; + for(Architecture arch = (Architecture)0; arch < Architecture_COUNT; arch = (Architecture)(arch+1)) { - // TODO(rjf): do preliminary header parse of EXE if possible, look for connected debug info path - } - scratch_end(scratch); - return result; -} - -internal String8 -ctrl_forced_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) -{ - String8 result = {0}; - // TODO(rjf) - return result; -} - -internal String8 -ctrl_natural_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) -{ - String8 exe_extension = str8_skip_last_dot(exe_path); - String8 dbg_extension = {0}; - if(str8_match(exe_extension, str8_lit("exe"), 0)) {dbg_extension = str8_lit("pdb");} - if(str8_match(exe_extension, str8_lit("elf"), 0)) {dbg_extension = str8_lit("debug");} - String8 result = {0}; - if(dbg_extension.size != 0) - { - result = push_str8f(arena, "%S.%S", str8_chop_last_dot(exe_path), dbg_extension); - } - return result; -} - -internal String8 -ctrl_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) -{ - Temp scratch = scratch_begin(&arena, 1); - String8 forced_og_dbg_path = ctrl_forced_og_dbg_path_from_exe_path(scratch.arena, exe_path); - String8 inferred_og_dbg_path = ctrl_inferred_og_dbg_path_from_exe_path(scratch.arena, exe_path); - String8 natural_og_dbg_path = ctrl_natural_og_dbg_path_from_exe_path(scratch.arena, exe_path); - String8 og_dbg_path = forced_og_dbg_path.size?forced_og_dbg_path : inferred_og_dbg_path.size?inferred_og_dbg_path : natural_og_dbg_path; - og_dbg_path = push_str8_copy(arena, og_dbg_path); - scratch_end(scratch); - return og_dbg_path; -} - -//- rjf: handle -> arch - -internal Architecture -ctrl_arch_from_handle(CTRL_MachineID machine, DMN_Handle handle) -{ - return dmn_arch_from_object(ctrl_dmn_handle_from_ctrl(handle)); -} - -//- rjf: process memory reading/writing - -internal U64 -ctrl_process_read(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *dst) -{ - U64 actual_bytes_read = dmn_process_read(process, range, dst); - return actual_bytes_read; -} - -internal B32 -ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *src) -{ - ProfBeginFunction(); - B32 result = dmn_process_write(process, range, src); - - //- rjf: success -> increment memgen - if(result) - { - ins_atomic_u64_inc_eval(&ctrl_state->memgen_idx); - } - - //- 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) - { - Temp scratch = scratch_begin(0, 0); - U64 endt_us = os_now_microseconds()+5000; - - //- rjf: gather tasks for all affected cached regions - typedef struct Task Task; - struct Task + String8 *reg_names = regs_reg_code_string_table_from_architecture(arch); + U64 reg_count = regs_reg_code_count_from_architecture(arch); + String8 *alias_names = regs_alias_code_string_table_from_architecture(arch); + U64 alias_count = regs_alias_code_count_from_architecture(arch); + ctrl_state->arch_string2reg_tables[arch] = eval_string2num_map_make(ctrl_state->arena, 256); + ctrl_state->arch_string2alias_tables[arch] = eval_string2num_map_make(ctrl_state->arena, 256); + for(U64 idx = 1; idx < reg_count; idx += 1) { - Task *next; - CTRL_MachineID machine_id; - DMN_Handle process; - Rng1U64 range; - }; - Task *first_task = 0; - Task *last_task = 0; - CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; - for(U64 slot_idx = 0; slot_idx < cache->slots_count; slot_idx += 1) - { - U64 stripe_idx = slot_idx%cache->stripes_count; - CTRL_ProcessMemoryCacheSlot *slot = &cache->slots[slot_idx]; - CTRL_ProcessMemoryCacheStripe *stripe = &cache->stripes[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) - { - for(CTRL_ProcessMemoryCacheNode *proc_n = slot->first; proc_n != 0; proc_n = proc_n->next) - { - for(U64 range_hash_idx = 0; range_hash_idx < proc_n->range_hash_slots_count; range_hash_idx += 1) - { - CTRL_ProcessMemoryRangeHashSlot *range_slot = &proc_n->range_hash_slots[range_hash_idx]; - for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) - { - Rng1U64 intersection_w_range = intersect_1u64(range, n->vaddr_range); - if(dim_1u64(intersection_w_range) != 0 && dim_1u64(n->vaddr_range) <= KB(64)) - { - Task *task = push_array(scratch.arena, Task, 1); - task->machine_id = proc_n->machine_id; - task->process = proc_n->process; - task->range = n->vaddr_range; - SLLQueuePush(first_task, last_task, task); - } - } - } - } - } + eval_string2num_map_insert(ctrl_state->arena, &ctrl_state->arch_string2reg_tables[arch], reg_names[idx], idx); } - - //- rjf: for all tasks, wait for up-to-date results - for(Task *task = first_task; task != 0; task = task->next) + for(U64 idx = 1; idx < alias_count; idx += 1) { - Temp temp = temp_begin(scratch.arena); - ctrl_query_cached_data_from_process_vaddr_range(temp.arena, task->machine_id, task->process, task->range, endt_us); - temp_end(temp); + eval_string2num_map_insert(ctrl_state->arena, &ctrl_state->arch_string2alias_tables[arch], alias_names[idx], idx); } - - scratch_end(scratch); } - - ProfEnd(); - return result; + ctrl_state->process_memory_cache.slots_count = 256; + ctrl_state->process_memory_cache.slots = push_array(arena, CTRL_ProcessMemoryCacheSlot, ctrl_state->process_memory_cache.slots_count); + ctrl_state->process_memory_cache.stripes_count = 8; + ctrl_state->process_memory_cache.stripes = push_array(arena, CTRL_ProcessMemoryCacheStripe, ctrl_state->process_memory_cache.stripes_count); + for(U64 idx = 0; idx < ctrl_state->process_memory_cache.stripes_count; idx += 1) + { + ctrl_state->process_memory_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); + ctrl_state->process_memory_cache.stripes[idx].cv = os_condition_variable_alloc(); + } + ctrl_state->thread_reg_cache.slots_count = 1024; + ctrl_state->thread_reg_cache.slots = push_array(arena, CTRL_ThreadRegCacheSlot, ctrl_state->thread_reg_cache.slots_count); + ctrl_state->thread_reg_cache.stripes_count = 8; + ctrl_state->thread_reg_cache.stripes = push_array(arena, CTRL_ThreadRegCacheStripe, ctrl_state->thread_reg_cache.stripes_count); + for(U64 idx = 0; idx < ctrl_state->thread_reg_cache.stripes_count; idx += 1) + { + ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); + ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc(); + } + ctrl_state->entity_rw_mutex = os_rw_mutex_alloc(); + ctrl_state->entity_arena = arena_alloc(); + ctrl_state->entity_root = &ctrl_entity_nil; + ctrl_state->entity_hash_slots_count = 4096; + ctrl_state->entity_hash_slots = push_array(arena, CTRL_EntityHashSlot, ctrl_state->entity_hash_slots_count); + ctrl_state->u2c_ring_size = KB(64); + ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); + ctrl_state->u2c_ring_mutex = os_mutex_alloc(); + ctrl_state->u2c_ring_cv = os_condition_variable_alloc(); + ctrl_state->c2u_ring_size = KB(64); + ctrl_state->c2u_ring_base = push_array_no_zero(arena, U8, ctrl_state->c2u_ring_size); + ctrl_state->c2u_ring_mutex = os_mutex_alloc(); + ctrl_state->c2u_ring_cv = os_condition_variable_alloc(); + ctrl_state->dmn_event_arena = arena_alloc(); + ctrl_state->user_entry_point_arena = arena_alloc(); + for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1)) + { + if(ctrl_exception_code_kind_default_enable_table[k]) + { + ctrl_state->exception_code_filters[k/64] |= 1ull<<(k%64); + } + } + ctrl_state->u2ms_ring_size = KB(64); + ctrl_state->u2ms_ring_base = push_array(arena, U8, ctrl_state->u2ms_ring_size); + ctrl_state->u2ms_ring_mutex = os_mutex_alloc(); + ctrl_state->u2ms_ring_cv = os_condition_variable_alloc(); + ctrl_state->ctrl_thread = os_launch_thread(ctrl_thread__entry_point, 0, 0); + ctrl_state->ms_thread_count = Clamp(1, os_logical_core_count()-1, 4); + ctrl_state->ms_threads = push_array(arena, OS_Handle, ctrl_state->ms_thread_count); + for(U64 idx = 0; idx < ctrl_state->ms_thread_count; idx += 1) + { + ctrl_state->ms_threads[idx] = os_launch_thread(ctrl_mem_stream_thread__entry_point, (void *)idx, 0); + } } +//////////////////////////////// +//~ rjf: Wakeup Callback Registration + +internal void +ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook) +{ + ctrl_state->wakeup_hook = wakeup_hook; +} + +//////////////////////////////// +//~ rjf: Process Memory Functions + //- rjf: process memory cache interaction internal U128 @@ -1125,15 +839,115 @@ ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CT return result; } -//- rjf: register reading/writing +//- rjf: process memory writing internal B32 -ctrl_thread_read_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block) +ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *src) { - B32 good = dmn_thread_read_reg_block(thread, block); - return good; + ProfBeginFunction(); + B32 result = dmn_process_write(process, range, src); + + //- rjf: success -> increment memgen + if(result) + { + ins_atomic_u64_inc_eval(&ctrl_state->memgen_idx); + } + + //- 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) + { + Temp scratch = scratch_begin(0, 0); + U64 endt_us = os_now_microseconds()+5000; + + //- rjf: gather tasks for all affected cached regions + typedef struct Task Task; + struct Task + { + Task *next; + CTRL_MachineID machine_id; + DMN_Handle process; + Rng1U64 range; + }; + Task *first_task = 0; + Task *last_task = 0; + CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; + for(U64 slot_idx = 0; slot_idx < cache->slots_count; slot_idx += 1) + { + U64 stripe_idx = slot_idx%cache->stripes_count; + CTRL_ProcessMemoryCacheSlot *slot = &cache->slots[slot_idx]; + CTRL_ProcessMemoryCacheStripe *stripe = &cache->stripes[stripe_idx]; + OS_MutexScopeW(stripe->rw_mutex) + { + for(CTRL_ProcessMemoryCacheNode *proc_n = slot->first; proc_n != 0; proc_n = proc_n->next) + { + for(U64 range_hash_idx = 0; range_hash_idx < proc_n->range_hash_slots_count; range_hash_idx += 1) + { + CTRL_ProcessMemoryRangeHashSlot *range_slot = &proc_n->range_hash_slots[range_hash_idx]; + for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) + { + Rng1U64 intersection_w_range = intersect_1u64(range, n->vaddr_range); + if(dim_1u64(intersection_w_range) != 0 && dim_1u64(n->vaddr_range) <= KB(64)) + { + Task *task = push_array(scratch.arena, Task, 1); + task->machine_id = proc_n->machine_id; + task->process = proc_n->process; + task->range = n->vaddr_range; + SLLQueuePush(first_task, last_task, task); + } + } + } + } + } + } + + //- rjf: for all tasks, wait for up-to-date results + for(Task *task = first_task; task != 0; task = task->next) + { + Temp temp = temp_begin(scratch.arena); + ctrl_query_cached_data_from_process_vaddr_range(temp.arena, task->machine_id, task->process, task->range, endt_us); + temp_end(temp); + } + + scratch_end(scratch); + } + + ProfEnd(); + return result; } +//////////////////////////////// +//~ rjf: Thread Register Functions + +//- rjf: thread register cache reading + +internal void * +ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us) +{ + return 0; +} + +internal U64 +ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) +{ + return 0; +} + +internal U64 +ctrl_query_cached_rip_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) +{ + return 0; +} + +internal U64 +ctrl_query_cached_rsp_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) +{ + return 0; +} + +//- rjf: thread register writing + internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block) { @@ -1142,75 +956,18 @@ ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void * return good; } -internal U64 -ctrl_rip_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) -{ - U64 result = 0; - void *regs = ctrl_reg_block_from_thread(machine_id, thread); - if(regs != 0) - { - Architecture arch = dmn_arch_from_object(ctrl_dmn_handle_from_ctrl(thread)); - result = regs_rip_from_arch_block(arch, regs); - } - return result; -} - -internal B32 -ctrl_thread_write_rip(CTRL_MachineID machine_id, DMN_Handle thread, U64 rip) -{ - B32 result = 0; - void *regs = ctrl_reg_block_from_thread(machine_id, thread); - if(regs != 0) - { - Architecture arch = dmn_arch_from_object(ctrl_dmn_handle_from_ctrl(thread)); - regs_arch_block_write_rip(arch, regs, rip); - ctrl_thread_write_reg_block(machine_id, thread, regs); - result = 1; - } - return result; -} - -internal U64 -ctrl_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) -{ - U64 result = 0; - result = dmn_tls_root_vaddr_from_thread(thread); - return result; -} - -//- rjf: process * vaddr -> module - -internal DMN_Handle -ctrl_module_from_process_vaddr(CTRL_MachineID machine_id, DMN_Handle process, U64 vaddr) -{ - DMN_Handle handle = {0}; - { - Temp scratch = scratch_begin(0, 0); - DMN_HandleArray modules = dmn_modules_from_process(scratch.arena, ctrl_dmn_handle_from_ctrl(process)); - for(U64 idx = 0; idx < modules.count; idx += 1) - { - DMN_Handle m = modules.handles[idx]; - Rng1U64 m_vaddr_rng = dmn_vaddr_range_from_module(m); - if(contains_1u64(m_vaddr_rng, vaddr)) - { - handle = m; - break; - } - } - scratch_end(scratch); - } - return handle; -} - -//- rjf: unwinding +//////////////////////////////// +//~ rjf: Unwinding Functions internal CTRL_Unwind -ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle thread) +ctrl_unwind_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); DBGI_Scope *scope = dbgi_scope_open(); - Architecture arch = dmn_arch_from_object(ctrl_dmn_handle_from_ctrl(thread)); + CTRL_Entity *thread_entity = ctrl_entity_from_machine_id_handle(machine_id, thread); + CTRL_Entity *process_entity = thread_entity->parent; + Architecture arch = thread_entity->arch; U64 arch_reg_block_size = regs_block_size_from_architecture(arch); CTRL_Unwind unwind = {0}; unwind.error = 1; @@ -1220,21 +977,11 @@ ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Han case Architecture_x64: { // rjf: grab initial register block - void *regs_block = push_array(scratch.arena, U8, arch_reg_block_size); - B32 regs_block_good = 0; - { - void *regs_raw = ctrl_reg_block_from_thread(machine_id, thread); - if(regs_raw != 0) - { - MemoryCopy(regs_block, regs_raw, arch_reg_block_size); - regs_block_good = 1; - } - } + void *regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, machine_id, thread, endt_us); // rjf: grab initial memory view B32 stack_memview_good = 0; UNW_MemView stack_memview = {0}; - if(regs_block_good) { U64 stack_base_unrounded = dmn_stack_base_vaddr_from_thread(thread); U64 stack_top_unrounded = regs_rsp_from_arch_block(arch, regs_block); @@ -1243,9 +990,8 @@ ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Han U64 stack_size = stack_base - stack_top; if(stack_base >= stack_top) { - String8 stack_memory = {0}; - stack_memory.str = push_array_no_zero(scratch.arena, U8, stack_size); - stack_memory.size = ctrl_process_read(machine_id, process, r1u64(stack_top, stack_top+stack_size), stack_memory.str); + CTRL_ProcessMemorySlice stack_memory_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, machine_id, process_entity->handle, r1u64(stack_top, stack_top+stack_size), endt_us); + String8 stack_memory = stack_memory_slice.data; if(stack_memory.size != 0) { stack_memview_good = 1; @@ -1262,9 +1008,21 @@ ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Han { unwind.error = 0; - // rjf: regs -> rip*module*binary + // rjf: regs -> rip*module U64 rip = regs_rip_from_arch_block(arch, regs_block); - DMN_Handle module = ctrl_module_from_process_vaddr(machine_id, process, rip); + DMN_Handle module = {0}; + String8 module_name = {0}; + Rng1U64 module_vaddr_range = {0}; + for(CTRL_Entity *m = process_entity->first; m != &ctrl_entity_nil; m = m->next) + { + if(contains_1u64(m->vaddr_range, rip)) + { + module = m->handle; + module_name = m->name; + module_vaddr_range = m->vaddr_range; + break; + } + } // rjf: cancel on 0 rip if(rip == 0) @@ -1272,8 +1030,8 @@ ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Han break; } - // rjf: binary -> all the binary info - String8 binary_full_path = dmn_full_path_from_module(scratch.arena, ctrl_dmn_handle_from_ctrl(module)); + // rjf: module -> all the binary info + String8 binary_full_path = module_name; DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_full_path, 0); String8 binary_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); @@ -1293,7 +1051,7 @@ ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Han unwind.count += 1; // rjf: unwind one step - UNW_Result unwind_step = unw_pe_x64(binary_data, &dbgi->pe, dmn_vaddr_range_from_module(ctrl_dmn_handle_from_ctrl(module)).min, &memview, (UNW_X64_Regs *)regs_block); + UNW_Result unwind_step = unw_pe_x64(binary_data, &dbgi->pe, module_vaddr_range.min, &memview, (UNW_X64_Regs *)regs_block); // rjf: cancel on bad step if(unwind_step.dead != 0) @@ -1318,6 +1076,41 @@ ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Han return unwind; } +//////////////////////////////// +//~ rjf: Halting All Attached Processes + +internal void +ctrl_halt(void) +{ + dmn_halt(0, 0); +} + +//////////////////////////////// +//~ rjf: Shared Accessor Functions + +//- rjf: run indices + +internal U64 +ctrl_run_idx(void) +{ + U64 result = ins_atomic_u64_eval(&ctrl_state->run_idx); + return result; +} + +internal U64 +ctrl_memgen_idx(void) +{ + U64 result = ins_atomic_u64_eval(&ctrl_state->memgen_idx); + return result; +} + +internal U64 +ctrl_reggen_idx(void) +{ + U64 result = ins_atomic_u64_eval(&ctrl_state->reggen_idx); + return result; +} + //- rjf: name -> register/alias hash tables, for eval internal EVAL_String2NumMap * @@ -1332,8 +1125,33 @@ ctrl_string2alias_from_arch(Architecture arch) return &ctrl_state->arch_string2alias_tables[arch]; } +//- rjf: entity state reading + +internal CTRL_Entity * +ctrl_entity_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle) +{ + CTRL_Entity *entity = &ctrl_entity_nil; + { + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, handle); + U64 slot_idx = hash%ctrl_state->entity_hash_slots_count; + CTRL_EntityHashSlot *slot = &ctrl_state->entity_hash_slots[slot_idx]; + CTRL_EntityHashNode *node = 0; + for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) + { + if(n->entity->machine_id == machine_id && dmn_handle_match(n->entity->handle, handle)) + { + entity = n->entity; + break; + } + } + } + return entity; +} + //////////////////////////////// -//~ rjf: User -> Ctrl Communication +//~ rjf: Control-Thread Functions + +//- rjf: user -> control thread communication internal B32 ctrl_u2c_push_msgs(CTRL_MsgList *msgs, U64 endt_us) @@ -1395,8 +1213,7 @@ ctrl_u2c_pop_msgs(Arena *arena) return msgs; } -//////////////////////////////// -//~ rjf: Ctrl -> User Communication +//- rjf: control -> user thread communication internal void ctrl_c2u_push_events(CTRL_EventList *events) @@ -1464,184 +1281,133 @@ ctrl_c2u_pop_events(Arena *arena) return events; } -//////////////////////////////// -//~ rjf: User -> Memory Stream Communication - -internal B32 -ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us) -{ - B32 good = 0; - OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) - { - U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos; - U64 available_size = ctrl_state->u2ms_ring_size-unconsumed_size; - if(available_size >= sizeof(machine_id)+sizeof(process)+sizeof(vaddr_range)) - { - good = 1; - ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &machine_id); - ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &process); - ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &vaddr_range); - ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &zero_terminated); - break; - } - if(os_now_microseconds() >= endt_us) {break;} - os_condition_variable_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, endt_us); - } - os_condition_variable_broadcast(ctrl_state->u2ms_ring_cv); - return good; -} - -internal void -ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, DMN_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated) -{ - OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) - { - U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos; - if(unconsumed_size >= sizeof(*out_machine_id)+sizeof(*out_process)+sizeof(*out_vaddr_range)) - { - ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_machine_id); - ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_process); - ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_vaddr_range); - ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_zero_terminated); - break; - } - os_condition_variable_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, max_U64); - } - os_condition_variable_broadcast(ctrl_state->u2ms_ring_cv); -} - -//////////////////////////////// -//~ rjf: Control-Thread-Only Functions - //- rjf: entity tree construction internal CTRL_Entity * ctrl_thread__entity_alloc(CTRL_Entity *parent, CTRL_EntityKind kind, CTRL_MachineID machine_id, DMN_Handle handle) { - // rjf: allocate - CTRL_Entity *entity = ctrl_state->ctrl_entity_free; + CTRL_Entity *entity = &ctrl_entity_nil; + OS_MutexScopeW(ctrl_state->entity_rw_mutex) { - if(entity != 0) + // rjf: allocate + entity = ctrl_state->entity_free; { - SLLStackPop(ctrl_state->ctrl_entity_free); - } - else - { - entity = push_array_no_zero(ctrl_state->ctrl_entity_arena, CTRL_Entity, 1); - } - MemoryZeroStruct(entity); - } - - // rjf: fill - { - entity->kind = kind; - entity->machine_id = machine_id; - entity->handle = handle; - entity->parent = parent; - entity->next = entity->prev = entity->first = entity->last = &ctrl_entity_nil; - if(parent != &ctrl_entity_nil) - { - DLLPushBack_NPZ(&ctrl_entity_nil, parent->first, parent->last, entity, next, prev); - } - } - - // rjf: insert into hash map - { - U64 hash = ctrl_hash_from_machine_id_handle(machine_id, handle); - U64 slot_idx = hash%ctrl_state->ctrl_entity_hash_slots_count; - CTRL_EntityHashSlot *slot = &ctrl_state->ctrl_entity_hash_slots[slot_idx]; - CTRL_EntityHashNode *node = 0; - for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) - { - if(n->entity->machine_id == machine_id && dmn_handle_match(n->entity->handle, handle)) + if(entity != 0) { - node = n; - break; - } - } - if(node == 0) - { - node = ctrl_state->ctrl_entity_hash_node_free; - if(node != 0) - { - SLLStackPop(ctrl_state->ctrl_entity_hash_node_free); + SLLStackPop(ctrl_state->entity_free); } else { - node = push_array_no_zero(ctrl_state->ctrl_entity_arena, CTRL_EntityHashNode, 1); + entity = push_array_no_zero(ctrl_state->entity_arena, CTRL_Entity, 1); + } + MemoryZeroStruct(entity); + } + + // rjf: fill + { + entity->kind = kind; + entity->machine_id = machine_id; + entity->handle = handle; + entity->parent = parent; + entity->next = entity->prev = entity->first = entity->last = &ctrl_entity_nil; + if(parent != &ctrl_entity_nil) + { + DLLPushBack_NPZ(&ctrl_entity_nil, parent->first, parent->last, entity, next, prev); + } + } + + // rjf: insert into hash map + { + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, handle); + U64 slot_idx = hash%ctrl_state->entity_hash_slots_count; + CTRL_EntityHashSlot *slot = &ctrl_state->entity_hash_slots[slot_idx]; + CTRL_EntityHashNode *node = 0; + for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) + { + if(n->entity->machine_id == machine_id && dmn_handle_match(n->entity->handle, handle)) + { + node = n; + break; + } + } + if(node == 0) + { + node = ctrl_state->entity_hash_node_free; + if(node != 0) + { + SLLStackPop(ctrl_state->entity_hash_node_free); + } + else + { + node = push_array_no_zero(ctrl_state->entity_arena, CTRL_EntityHashNode, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->entity = entity; } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - node->entity = entity; } } - return entity; } internal void ctrl_thread__entity_release(CTRL_Entity *entity) { - // rjf: unhook root - if(entity->parent != &ctrl_entity_nil) + OS_MutexScopeW(ctrl_state->entity_rw_mutex) { - DLLRemove_NPZ(&ctrl_entity_nil, entity->parent->first, entity->parent->last, entity, next, prev); - } - - // rjf: walk every entity in this tree, free each - if(entity != &ctrl_entity_nil) - { - Temp scratch = scratch_begin(0, 0); - typedef struct Task Task; - struct Task + // rjf: unhook root + if(entity->parent != &ctrl_entity_nil) { - Task *next; - CTRL_Entity *e; - }; - Task start_task = {0, entity}; - Task *first_task = &start_task; - Task *last_task = &start_task; - for(Task *t = first_task; t != 0; t = t->next) + DLLRemove_NPZ(&ctrl_entity_nil, entity->parent->first, entity->parent->last, entity, next, prev); + } + + // rjf: walk every entity in this tree, free each + if(entity != &ctrl_entity_nil) { - for(CTRL_Entity *child = entity->first; child != &ctrl_entity_nil; child = child->next) + Temp scratch = scratch_begin(0, 0); + typedef struct Task Task; + struct Task { - Task *t = push_array(scratch.arena, Task, 1); - t->e = child; - SLLQueuePush(first_task, last_task, t); - } - - // rjf: free entity - SLLStackPush(ctrl_state->ctrl_entity_free, t->e); - - // rjf: remove from hash map + Task *next; + CTRL_Entity *e; + }; + Task start_task = {0, entity}; + Task *first_task = &start_task; + Task *last_task = &start_task; + for(Task *t = first_task; t != 0; t = t->next) { - U64 hash = ctrl_hash_from_machine_id_handle(t->e->machine_id, t->e->handle); - U64 slot_idx = hash%ctrl_state->ctrl_entity_hash_slots_count; - CTRL_EntityHashSlot *slot = &ctrl_state->ctrl_entity_hash_slots[slot_idx]; - CTRL_EntityHashNode *node = 0; - for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) + for(CTRL_Entity *child = entity->first; child != &ctrl_entity_nil; child = child->next) { - if(n->entity->machine_id == t->e->machine_id && dmn_handle_match(n->entity->handle, t->e->handle)) + Task *t = push_array(scratch.arena, Task, 1); + t->e = child; + SLLQueuePush(first_task, last_task, t); + } + + // rjf: free entity + SLLStackPush(ctrl_state->entity_free, t->e); + + // rjf: remove from hash map + { + U64 hash = ctrl_hash_from_machine_id_handle(t->e->machine_id, t->e->handle); + U64 slot_idx = hash%ctrl_state->entity_hash_slots_count; + CTRL_EntityHashSlot *slot = &ctrl_state->entity_hash_slots[slot_idx]; + CTRL_EntityHashNode *node = 0; + for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) { - DLLRemove(slot->first, slot->last, n); - SLLStackPush(ctrl_state->ctrl_entity_hash_node_free, n); - break; + if(n->entity->machine_id == t->e->machine_id && dmn_handle_match(n->entity->handle, t->e->handle)) + { + DLLRemove(slot->first, slot->last, n); + SLLStackPush(ctrl_state->entity_hash_node_free, n); + break; + } } } } + scratch_end(scratch); } - scratch_end(scratch); } } -internal CTRL_Entity * -ctrl_thread__entity_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle) -{ - CTRL_Entity *entity = &ctrl_entity_nil; - - return entity; -} - //- rjf: entry point internal void @@ -1706,6 +1472,123 @@ ctrl_thread__entry_point(void *p) ProfEnd(); } +//- rjf: breakpoint resolution + +internal void +ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) +{ + Temp scratch = scratch_begin(&arena, 1); + DBGI_Scope *scope = dbgi_scope_open(); + CTRL_Entity *module_entity = ctrl_entity_from_machine_id_handle(machine_id, module); + String8 exe_path = module_entity->name; + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); + RDI_Parsed *rdi = &dbgi->rdi; + U64 base_vaddr = module_entity->vaddr_range.min; + for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) + { + CTRL_UserBreakpoint *bp = &n->v; + switch(bp->kind) + { + default:{}break; + + //- rjf: file:line-based breakpoints + case CTRL_UserBreakpointKind_FileNameAndLineColNumber: + { + // rjf: unpack & normalize + TxtPt pt = bp->pt; + String8 filename = bp->string; + String8 filename_normalized = push_str8_copy(scratch.arena, filename); + for(U64 idx = 0; idx < filename_normalized.size; idx += 1) + { + filename_normalized.str[idx] = char_to_lower(filename_normalized.str[idx]); + filename_normalized.str[idx] = char_to_correct_slash(filename_normalized.str[idx]); + } + + // rjf: filename -> src_id + U32 src_id = 0; + { + RDI_NameMap *mapptr = rdi_name_map_from_kind(rdi, RDI_NameMapKind_NormalSourcePaths); + if(mapptr != 0) + { + RDI_ParsedNameMap map = {0}; + rdi_name_map_parse(rdi, mapptr, &map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, filename_normalized.str, filename_normalized.size); + if(node != 0) + { + U32 id_count = 0; + U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); + if(id_count > 0) + { + src_id = ids[0]; + } + } + } + } + + // rjf: src_id * pt -> push + { + RDI_SourceFile *src = rdi_element_from_idx(rdi, source_files, src_id); + RDI_ParsedLineMap line_map = {0}; + rdi_line_map_from_source_file(rdi, src, &line_map); + U32 voff_count = 0; + U64 *voffs = rdi_line_voffs_from_num(&line_map, pt.line, &voff_count); + for(U32 i = 0; i < voff_count; i += 1) + { + U64 vaddr = voffs[i] + base_vaddr; + DMN_Trap trap = {process, vaddr, (U64)bp}; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); + } + } + }break; + + //- rjf: symbol:voff-based breakpoints + case CTRL_UserBreakpointKind_SymbolNameAndOffset: + { + String8 symbol_name = bp->string; + U64 voff = bp->u64; + if(rdi != 0 && rdi->procedures != 0) + { + RDI_NameMap *mapptr = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Procedures); + if(mapptr != 0) + { + RDI_ParsedNameMap map = {0}; + rdi_name_map_parse(rdi, mapptr, &map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, symbol_name.str, symbol_name.size); + if(node != 0) + { + U32 id_count = 0; + U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); + for(U32 match_i = 0; match_i < id_count; match_i += 1) + { + U64 proc_voff = rdi_first_voff_from_proc(rdi, ids[match_i]); + U64 proc_vaddr = proc_voff + base_vaddr; + DMN_Trap trap = {process, proc_vaddr + voff, (U64)bp}; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); + } + } + } + } + }break; + } + } + dbgi_scope_close(scope); + scratch_end(scratch); +} + +internal void +ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) +{ + for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) + { + CTRL_UserBreakpoint *bp = &n->v; + if(bp->kind == CTRL_UserBreakpointKind_VirtualAddress) + { + DMN_Trap trap = {process, bp->u64, (U64)bp}; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); + } + } +} + //- rjf: attached process running/event gathering internal DMN_Event * @@ -1768,14 +1651,14 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls (spoof == 0 || ev->instruction_pointer != spoof->new_ip_value)) { DBGI_Scope *scope = dbgi_scope_open(); - DMN_HandleArray modules = dmn_modules_from_process(scratch.arena, ev->process); - if(modules.count != 0) + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(CTRL_MachineID_Local, ev->process); + CTRL_Entity *module = process->first; + if(module != &ctrl_entity_nil) { // rjf: determine base address of asan shadow space U64 asan_shadow_base_vaddr = 0; B32 asan_shadow_variable_exists_but_is_zero = 0; - DMN_Handle module = modules.handles[0]; - String8 module_path = dmn_full_path_from_module(scratch.arena, ctrl_dmn_handle_from_ctrl(module)); + String8 module_path = module->name; DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, module_path, max_U64); RDI_Parsed *rdi = &dbgi->rdi; RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_GlobalVariables); @@ -1793,10 +1676,10 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls { RDI_GlobalVariable *global_var = rdi_element_from_idx(rdi, global_variables, ids[0]); U64 global_var_voff = global_var->voff; - U64 global_var_vaddr = global_var->voff + dmn_base_vaddr_from_module(ctrl_dmn_handle_from_ctrl(module)); - Architecture arch = dmn_arch_from_object(ev->thread); + U64 global_var_vaddr = global_var->voff + module->vaddr_range.min; + Architecture arch = process->arch; U64 addr_size = bit_size_from_arch(arch)/8; - ctrl_process_read(CTRL_MachineID_Local, ev->process, r1u64(global_var_vaddr, global_var_vaddr+addr_size), &asan_shadow_base_vaddr); + dmn_process_read(ev->process, r1u64(global_var_vaddr, global_var_vaddr+addr_size), &asan_shadow_base_vaddr); asan_shadow_variable_exists_but_is_zero = (asan_shadow_base_vaddr == 0); } } @@ -1852,15 +1735,16 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls U64 size_of_spoof = 0; if(do_spoof) ProfScope("prep spoof") { - Architecture arch = dmn_arch_from_object(ctrl_dmn_handle_from_ctrl(spoof->process)); - dmn_read_memory(ctrl_dmn_handle_from_ctrl(spoof->process), &spoof_old_ip_value, spoof->vaddr, sizeof(spoof_old_ip_value)); + CTRL_Entity *spoof_process = ctrl_entity_from_machine_id_handle(CTRL_MachineID_Local, spoof->process); + Architecture arch = spoof_process->arch; size_of_spoof = bit_size_from_arch(arch)/8; + dmn_process_read(spoof_process->handle, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); } // rjf: set spoof if(do_spoof) ProfScope("set spoof") { - dmn_write_memory(ctrl_dmn_handle_from_ctrl(spoof->process), spoof->vaddr, &spoof->new_ip_value, size_of_spoof); + dmn_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof->new_ip_value); } // rjf: run for new events @@ -1887,7 +1771,7 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls // rjf: unset spoof if(do_spoof) ProfScope("unset spoof") { - dmn_write_memory(ctrl_dmn_handle_from_ctrl(spoof->process), spoof->vaddr, &spoof_old_ip_value, size_of_spoof); + dmn_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); } // rjf: inc generation counters @@ -1904,10 +1788,15 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls // simply been sent other debug events first if(spoof != 0) { - U64 spoof_thread_rip = dmn_read_ip(ctrl_dmn_handle_from_ctrl(spoof->thread)); + CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(CTRL_MachineID_Local, spoof->thread); + Architecture arch = thread->arch; + void *regs_block = push_array(scratch.arena, U8, regs_block_size_from_architecture(arch)); + dmn_thread_read_reg_block(spoof->thread, regs_block); + U64 spoof_thread_rip = regs_rip_from_arch_block(arch, regs_block); if(spoof_thread_rip == spoof->new_ip_value) { - dmn_write_ip(ctrl_dmn_handle_from_ctrl(spoof->thread), spoof_old_ip_value); + regs_arch_block_write_rip(arch, regs_block, spoof_old_ip_value); + dmn_thread_write_reg_block(spoof->thread, regs_block); } } @@ -1923,7 +1812,7 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls out_evt->msg_id = msg->msg_id; out_evt->machine_id = CTRL_MachineID_Local; out_evt->entity = event->process; - out_evt->arch = dmn_arch_from_object(event->process); + out_evt->arch = event->arch; out_evt->entity_id = event->code; ctrl_state->process_counter += 1; }break; @@ -1935,7 +1824,7 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls out_evt->machine_id = CTRL_MachineID_Local; out_evt->entity = event->thread; out_evt->parent = event->process; - out_evt->arch = dmn_arch_from_object(event->process); + out_evt->arch = event->arch; out_evt->entity_id = event->code; out_evt->stack_base = dmn_stack_base_vaddr_from_thread(event->thread); out_evt->tls_root = dmn_tls_root_vaddr_from_thread(event->thread); @@ -1952,10 +1841,10 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls out_evt->machine_id = CTRL_MachineID_Local; out_evt->entity = event->module; out_evt->parent = event->process; - out_evt->arch = dmn_arch_from_object(event->module); + out_evt->arch = event->arch; out_evt->entity_id = event->code; out_evt->vaddr_rng = r1u64(event->address, event->address+event->size); - out_evt->rip_vaddr = dmn_base_vaddr_from_module(event->module); + out_evt->rip_vaddr = event->address; out_evt->string = module_path; }break; case DMN_EventKind_ExitProcess: @@ -2275,12 +2164,11 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) //- rjf: add traps for all possible entry points for(U64 process_idx = 0; process_idx < run_ctrls.run_entity_count; process_idx += 1) { - //- rjf: unpack first module info - DMN_HandleArray modules = dmn_modules_from_process(scratch.arena, run_ctrls.run_entities[process_idx]); - if(modules.count == 0) { continue; } - DMN_Handle module = modules.handles[0]; - U64 module_base_vaddr = dmn_base_vaddr_from_module(module); - String8 exe_path = dmn_full_path_from_module(scratch.arena, module); + //- rjf: unpack process & first module info + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(CTRL_MachineID_Local, run_ctrls.run_entities[process_idx]); + CTRL_Entity *module = process->first; + U64 module_base_vaddr = module->vaddr_range.min; + String8 exe_path = module->name; DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); RDI_Parsed *rdi = &dbgi->rdi; RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Procedures); @@ -2547,7 +2435,7 @@ ctrl_thread__kill(CTRL_Msg *msg) B32 kill_worked = dmn_kill_process(process, exit_code); //- rjf: wait for process to be dead - if(dmn_object_exists(process) && kill_worked) + if(kill_worked) { DMN_RunCtrls run_ctrls = {0}; run_ctrls.run_entities_are_unfrozen = 1; @@ -2595,7 +2483,7 @@ ctrl_thread__detach(CTRL_Msg *msg) B32 detach_worked = dmn_detach_process(process); //- rjf: wait for process to be dead - if(dmn_object_exists(process) && detach_worked) + if(detach_worked) { DMN_RunCtrls run_ctrls = {0}; run_ctrls.run_entities_are_unfrozen = 1; @@ -2643,32 +2531,26 @@ ctrl_thread__run(CTRL_Msg *msg) DMN_Handle target_process = msg->parent; U64 spoof_ip_vaddr = 911; - ////////////////////////////// - //- rjf: gather processes - // - DMN_HandleArray processes = dmn_all_processes(scratch.arena); - ////////////////////////////// //- rjf: gather all initial breakpoints // DMN_TrapChunkList user_traps = {0}; + for(CTRL_Entity *machine = ctrl_state->entity_root->first; machine != &ctrl_entity_nil; machine = machine->next) { - // rjf: resolve module-dependent user bps - for(U64 process_idx = 0; process_idx < processes.count; process_idx += 1) + if(machine->kind != CTRL_EntityKind_Machine) { continue; } + for(CTRL_Entity *process = machine->first; process != &ctrl_entity_nil; process = process->next) { - DMN_Handle process = processes.handles[process_idx]; - DMN_HandleArray modules = dmn_modules_from_process(scratch.arena, process); - for(U64 module_idx = 0; module_idx < modules.count; module_idx += 1) + if(process->kind != CTRL_EntityKind_Process) { continue; } + + // rjf: resolve module-dependent user bps + for(CTRL_Entity *module = process->first; module != &ctrl_entity_nil; module = module->next) { - DMN_Handle module = modules.handles[module_idx]; - ctrl_append_resolved_module_user_bp_traps(scratch.arena, process, module, &msg->user_bps, &user_traps); + if(module->kind != CTRL_EntityKind_Module) { continue; } + ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, machine->machine_id, process->handle, module->handle, &msg->user_bps, &user_traps); } - } - - // rjf: push virtual-address user breakpoints per-process - for(U64 process_idx = 0; process_idx < processes.count; process_idx += 1) - { - ctrl_append_resolved_process_user_bp_traps(scratch.arena, processes.handles[process_idx], &msg->user_bps, &user_traps); + + // rjf: push virtual-address user breakpoints per-process + ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, machine->machine_id, process->handle, &msg->user_bps, &user_traps); } } @@ -2689,57 +2571,59 @@ ctrl_thread__run(CTRL_Msg *msg) { // rjf: gather stuck threads DMN_HandleList stuck_threads = {0}; - for(U64 i = 0; i < processes.count; i += 1) + for(CTRL_Entity *machine = ctrl_state->entity_root->first; machine != &ctrl_entity_nil; machine = machine->next) { - DMN_Handle process = processes.handles[i]; - DMN_HandleArray threads = dmn_threads_from_process(scratch.arena, process); - for(U64 j = 0; j < threads.count; j += 1) + if(machine->kind != CTRL_EntityKind_Machine) { continue; } + for(CTRL_Entity *process = machine->first; process != &ctrl_entity_nil; process = process->next) { - DMN_Handle thread = threads.handles[j]; - U64 rip = dmn_read_ip(thread); - - // rjf: determine if thread is frozen - B32 thread_is_frozen = !msg->freeze_state_is_frozen; - for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next) + if(process->kind != CTRL_EntityKind_Process) { continue; } + for(CTRL_Entity *thread = process->first; thread != &ctrl_entity_nil; thread = thread->next) { - if(dmn_handle_match(n->v.handle, thread)) + U64 rip = ctrl_query_cached_rip_from_thread(thread->machine_id, thread->handle); + + // rjf: determine if thread is frozen + B32 thread_is_frozen = !msg->freeze_state_is_frozen; + for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next) { - thread_is_frozen ^= 1; - break; + if(dmn_handle_match(n->v.handle, thread->handle)) + { + thread_is_frozen ^= 1; + break; + } } - } - - // rjf: not frozen? -> check if stuck & gather if so - if(thread_is_frozen == 0) - { - for(DMN_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) + + // rjf: not frozen? -> check if stuck & gather if so + if(thread_is_frozen == 0) { - B32 is_on_user_bp = 0; - for(DMN_Trap *trap_ptr = n->v; trap_ptr < n->v+n->count; trap_ptr += 1) + for(DMN_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) { - if(dmn_handle_match(trap_ptr->process, process) && trap_ptr->vaddr == rip) + B32 is_on_user_bp = 0; + for(DMN_Trap *trap_ptr = n->v; trap_ptr < n->v+n->count; trap_ptr += 1) { - is_on_user_bp = 1; + if(dmn_handle_match(trap_ptr->process, process->handle) && trap_ptr->vaddr == rip) + { + is_on_user_bp = 1; + } } - } - - B32 is_on_net_trap = 0; - for(CTRL_TrapNode *n = msg->traps.first; n != 0; n = n->next) - { - if(n->v.vaddr == rip) + + B32 is_on_net_trap = 0; + for(CTRL_TrapNode *n = msg->traps.first; n != 0; n = n->next) { - is_on_net_trap = 1; + if(n->v.vaddr == rip) + { + is_on_net_trap = 1; + } + } + + if(is_on_user_bp && (!is_on_net_trap || !dmn_handle_match(thread->handle, target_thread))) + { + dmn_handle_list_push(scratch.arena, &stuck_threads, thread->handle); + } + + if(is_on_user_bp && is_on_net_trap && dmn_handle_match(thread->handle, target_thread)) + { + target_thread_is_on_user_bp_and_trap_net_trap = 1; } - } - - if(is_on_user_bp && (!is_on_net_trap || !dmn_handle_match(thread, target_thread))) - { - dmn_handle_list_push(scratch.arena, &stuck_threads, thread); - } - - if(is_on_user_bp && is_on_net_trap && dmn_handle_match(thread, target_thread)) - { - target_thread_is_on_user_bp_and_trap_net_trap = 1; } } } @@ -2814,7 +2698,7 @@ ctrl_thread__run(CTRL_Msg *msg) // if(stop_event == 0) { - U64 sp_check_value = dmn_read_sp(target_thread); + U64 sp_check_value = ctrl_query_cached_rsp_from_thread(CTRL_MachineID_Local, target_thread); B32 spoof_mode = 0; CTRL_Spoof spoof = {0}; for(;;) @@ -2884,13 +2768,13 @@ ctrl_thread__run(CTRL_Msg *msg) case DMN_EventKind_CreateProcess: { DMN_TrapChunkList new_traps = {0}; - ctrl_append_resolved_process_user_bp_traps(scratch.arena, event->process, &msg->user_bps, &new_traps); + ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, CTRL_MachineID_Local, event->process, &msg->user_bps, &new_traps); dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); }break; case DMN_EventKind_LoadModule: { DMN_TrapChunkList new_traps = {0}; - ctrl_append_resolved_module_user_bp_traps(scratch.arena, event->process, event->module, &msg->user_bps, &new_traps); + ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, CTRL_MachineID_Local, event->process, event->module, &msg->user_bps, &new_traps); dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); }break; @@ -2899,29 +2783,27 @@ ctrl_thread__run(CTRL_Msg *msg) ////////////////////////// //- rjf: unpack info about thread attached to event // - Architecture arch = dmn_arch_from_object(event->thread); + CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(CTRL_MachineID_Local, event->thread); + Architecture arch = thread->arch; U64 reg_size = regs_block_size_from_architecture(arch); - void *thread_regs_block = dmn_read_regs(event->thread); + void *thread_regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, CTRL_MachineID_Local, event->thread, max_U64); U64 thread_rip_vaddr = regs_rip_from_arch_block(arch, thread_regs_block); DMN_Handle module = {0}; + String8 module_name = {0}; + U64 module_base_vaddr = 0; U64 thread_rip_voff = 0; { - Temp temp = temp_begin(scratch.arena); - DMN_HandleArray modules = dmn_modules_from_process(temp.arena, event->process); - if(modules.count != 0) + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(CTRL_MachineID_Local, event->thread); + for(CTRL_Entity *module = process->first; module != &ctrl_entity_nil; module = module->next) { - for(U64 idx = 0; idx < modules.count; idx += 1) + if(contains_1u64(module->vaddr_range, thread_rip_vaddr)) { - Rng1U64 vaddr_range = dmn_vaddr_range_from_module(modules.handles[idx]); - if(contains_1u64(vaddr_range, thread_rip_vaddr)) - { - module = modules.handles[idx]; - thread_rip_voff = thread_rip_vaddr - vaddr_range.min; - break; - } + module_name = module->name; + module_base_vaddr = module->vaddr_range.min; + thread_rip_voff = thread_rip_vaddr - module->vaddr_range.min; + break; } } - temp_end(temp); } ////////////////////////// @@ -3003,7 +2885,7 @@ ctrl_thread__run(CTRL_Msg *msg) // rjf: evaluate hit stop conditions if(conditions.node_count != 0) { - String8 exe_path = dmn_full_path_from_module(temp.arena, module); + String8 exe_path = module_name; DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); RDI_Parsed *rdi = &dbgi->rdi; for(String8Node *condition_n = conditions.first; condition_n != 0; condition_n = condition_n->next) @@ -3043,7 +2925,7 @@ ctrl_thread__run(CTRL_Msg *msg) EVAL_Result eval = {0}; if(bytecode.size != 0) { - U64 module_base = dmn_base_vaddr_from_module(module); + U64 module_base = module_base_vaddr; U64 tls_base = 0; // TODO(rjf) EVAL_Machine machine = {0}; machine.u = &event->process; @@ -3153,7 +3035,7 @@ ctrl_thread__run(CTRL_Msg *msg) B32 stack_pointer_matches = 0; if(use_trap_net_logic) { - U64 sp = dmn_read_sp(target_thread); + U64 sp = ctrl_query_cached_rsp_from_thread(CTRL_MachineID_Local, target_thread); stack_pointer_matches = (sp == sp_check_value); } @@ -3201,7 +3083,7 @@ ctrl_thread__run(CTRL_Msg *msg) { // rjf: setup spoof mode begin_spoof_mode = 1; - U64 spoof_sp = dmn_read_sp(target_thread); + U64 spoof_sp = ctrl_query_cached_rsp_from_thread(CTRL_MachineID_Local, target_thread); spoof_mode = 1; spoof.process = target_process; spoof.thread = target_thread; @@ -3219,7 +3101,7 @@ ctrl_thread__run(CTRL_Msg *msg) if(stack_pointer_matches) { save_stack_pointer = 1; - sp_check_value = dmn_read_sp(target_thread); + sp_check_value = ctrl_query_cached_rsp_from_thread(CTRL_MachineID_Local, target_thread); } } } @@ -3403,6 +3285,51 @@ ctrl_thread__single_step(CTRL_Msg *msg) //////////////////////////////// //~ rjf: Memory-Stream-Thread-Only Functions +//- rjf: user -> memory stream communication + +internal B32 +ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us) +{ + B32 good = 0; + OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) + { + U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos; + U64 available_size = ctrl_state->u2ms_ring_size-unconsumed_size; + if(available_size >= sizeof(machine_id)+sizeof(process)+sizeof(vaddr_range)) + { + good = 1; + ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &machine_id); + ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &process); + ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &vaddr_range); + ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &zero_terminated); + break; + } + if(os_now_microseconds() >= endt_us) {break;} + os_condition_variable_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, endt_us); + } + os_condition_variable_broadcast(ctrl_state->u2ms_ring_cv); + return good; +} + +internal void +ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, DMN_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated) +{ + OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) + { + U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos; + if(unconsumed_size >= sizeof(*out_machine_id)+sizeof(*out_process)+sizeof(*out_vaddr_range)) + { + ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_machine_id); + ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_process); + ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_vaddr_range); + ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_zero_terminated); + break; + } + os_condition_variable_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, max_U64); + } + os_condition_variable_broadcast(ctrl_state->u2ms_ring_cv); +} + //- rjf: entry point internal void @@ -3476,7 +3403,7 @@ ctrl_mem_stream_thread__entry_point(void *p) else { range_base = push_array_no_zero(range_arena, U8, range_size); - U64 bytes_read = ctrl_process_read(machine_id, process, vaddr_range_clamped, range_base); + U64 bytes_read = dmn_process_read(process, vaddr_range_clamped, range_base); if(bytes_read == 0) { arena_release(range_arena); diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 840cef5c..e4bd7653 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -473,6 +473,15 @@ struct CTRL_State CTRL_ProcessMemoryCache process_memory_cache; CTRL_ThreadRegCache thread_reg_cache; + // rjf: entity tree + OS_Handle entity_rw_mutex; + Arena *entity_arena; + CTRL_Entity *entity_root; + CTRL_Entity *entity_free; + CTRL_EntityHashSlot *entity_hash_slots; + CTRL_EntityHashNode *entity_hash_node_free; + U64 entity_hash_slots_count; + // rjf: user -> ctrl msg ring buffer U64 u2c_ring_size; U8 *u2c_ring_base; @@ -491,12 +500,6 @@ struct CTRL_State // rjf: ctrl thread state OS_Handle ctrl_thread; - Arena *ctrl_entity_arena; - CTRL_Entity *ctrl_entity_root; - CTRL_Entity *ctrl_entity_free; - CTRL_EntityHashSlot *ctrl_entity_hash_slots; - CTRL_EntityHashNode *ctrl_entity_hash_node_free; - U64 ctrl_entity_hash_slots_count; Arena *dmn_event_arena; DMN_EventNode *first_dmn_event_node; DMN_EventNode *last_dmn_event_node; @@ -557,8 +560,6 @@ internal CTRL_TrapList ctrl_trap_list_copy(Arena *arena, CTRL_TrapList *src); internal void ctrl_user_breakpoint_list_push(Arena *arena, CTRL_UserBreakpointList *list, CTRL_UserBreakpoint *bp); internal CTRL_UserBreakpointList ctrl_user_breakpoint_list_copy(Arena *arena, CTRL_UserBreakpointList *src); -internal void ctrl_append_resolved_module_user_bp_traps(Arena *arena, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); -internal void ctrl_append_resolved_process_user_bp_traps(Arena *arena, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); //////////////////////////////// //~ rjf: Message Type Functions @@ -614,6 +615,8 @@ internal B32 ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, R //- rjf: thread register cache reading internal void *ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us); internal U64 ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, DMN_Handle thread); +internal U64 ctrl_query_cached_rip_from_thread(CTRL_MachineID machine_id, DMN_Handle thread); +internal U64 ctrl_query_cached_rsp_from_thread(CTRL_MachineID machine_id, DMN_Handle thread); //- rjf: thread register writing internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block); @@ -621,7 +624,7 @@ internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle t //////////////////////////////// //~ rjf: Unwinding Functions -internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread); +internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us); //////////////////////////////// //~ rjf: Halting All Attached Processes @@ -640,6 +643,9 @@ internal U64 ctrl_reggen_idx(void); internal EVAL_String2NumMap *ctrl_string2reg_from_arch(Architecture arch); internal EVAL_String2NumMap *ctrl_string2alias_from_arch(Architecture arch); +//- rjf: entity state reading +internal CTRL_Entity *ctrl_entity_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle); + //////////////////////////////// //~ rjf: Control-Thread Functions @@ -654,11 +660,14 @@ internal CTRL_EventList ctrl_c2u_pop_events(Arena *arena); //- rjf: entity tree construction internal CTRL_Entity *ctrl_thread__entity_alloc(CTRL_Entity *parent, CTRL_EntityKind kind, CTRL_MachineID machine_id, DMN_Handle handle); internal void ctrl_thread__entity_release(CTRL_Entity *entity); -internal CTRL_Entity *ctrl_thread__entity_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle); //- rjf: entry point internal void ctrl_thread__entry_point(void *p); +//- rjf: breakpoint resolution +internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); + //- rjf: attached process running/event gathering internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof); diff --git a/src/demon2/demon2_core.h b/src/demon2/demon2_core.h index 5eeacd22..5cff7a56 100644 --- a/src/demon2/demon2_core.h +++ b/src/demon2/demon2_core.h @@ -54,6 +54,7 @@ struct DMN_Event DMN_Handle process; DMN_Handle thread; DMN_Handle module; + Architecture arch; U64 address; U64 size; String8 string; diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index 2f42d85f..afee68fa 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -1462,6 +1462,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) DMN_Event *e = dmn_event_list_push(arena, &events); e->kind = DMN_EventKind_CreateProcess; e->process = dmn_w32_handle_from_entity(process); + e->arch = image_info.arch; e->code = evt.dwProcessId; } @@ -1471,6 +1472,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) e->kind = DMN_EventKind_CreateThread; e->process = dmn_w32_handle_from_entity(process); e->thread = dmn_w32_handle_from_entity(thread); + e->arch = image_info.arch; e->code = evt.dwThreadId; } @@ -1480,6 +1482,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) e->kind = DMN_EventKind_LoadModule; e->process = dmn_w32_handle_from_entity(process); e->module = dmn_w32_handle_from_entity(module); + e->arch = image_info.arch; e->address = module_base; e->size = image_info.size; e->string = dmn_w32_full_path_from_module(arena, module); @@ -1543,6 +1546,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) DMN_W32_Entity *thread = dmn_w32_entity_alloc(process, DMN_W32_EntityKind_Thread, evt.dwThreadId); { thread->handle = evt.u.CreateThread.hThread; + thread->arch = process->arch; thread->thread.thread_local_base = (U64)evt.u.CreateThread.lpThreadLocalBase; } @@ -1573,6 +1577,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) e->kind = DMN_EventKind_CreateThread; e->process = dmn_w32_handle_from_entity(process); e->thread = dmn_w32_handle_from_entity(thread); + e->arch = thread->arch; e->code = evt.dwThreadId; e->string = thread_name; } @@ -1627,6 +1632,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) DMN_W32_Entity *module = dmn_w32_entity_alloc(process, DMN_W32_EntityKind_Module, module_base); { module->handle = evt.u.LoadDll.hFile; + module->arch = image_info.arch; module->module.vaddr_range = r1u64(module_base, module_base+image_info.size); module->module.address_of_name_pointer = (U64)evt.u.LoadDll.lpImageName; module->module.name_is_unicode = (evt.u.LoadDll.fUnicode != 0); @@ -1638,6 +1644,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) e->kind = DMN_EventKind_LoadModule; e->process = dmn_w32_handle_from_entity(process); e->module = dmn_w32_handle_from_entity(module); + e->arch = module->arch; e->address = module_base; e->size = image_info.size; e->string = dmn_w32_full_path_from_module(arena, module); @@ -2299,6 +2306,8 @@ dmn_detach_process(DMN_Handle process) { dmn_handle_list_push(dmn_w32_shared->detach_arena, &dmn_w32_shared->detach_processes, process); } + + return result; } //////////////////////////////// From 4a3cc9bb3961b9380b021a444aba63687e21db05 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 12 Mar 2024 13:55:13 -0700 Subject: [PATCH 03/33] get raddbg building on new demon layer --- project.4coder | 2 +- src/ctrl/ctrl_inc.h | 2 +- src/dasm/dasm.c | 10 ++++++---- src/dasm/dasm.h | 3 ++- src/df/core/df_core.c | 36 +++++++++++++++++++----------------- src/df/gfx/df_views.c | 16 +++++++++------- src/df/gfx/df_views.h | 2 +- src/raddbg/raddbg_main.cpp | 4 ++-- 8 files changed, 41 insertions(+), 34 deletions(-) diff --git a/project.4coder b/project.4coder index f39bd033..be4e0ac7 100644 --- a/project.4coder +++ b/project.4coder @@ -47,7 +47,7 @@ commands = { .rjf_f1 = { - .win = "build ryan_scratch", + .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, diff --git a/src/ctrl/ctrl_inc.h b/src/ctrl/ctrl_inc.h index e485f6d0..24b17db2 100644 --- a/src/ctrl/ctrl_inc.h +++ b/src/ctrl/ctrl_inc.h @@ -74,4 +74,4 @@ #include "ctrl_core.h" -#endif //CTRL_INC_H +#endif // CTRL_INC_H diff --git a/src/dasm/dasm.c b/src/dasm/dasm.c index 0a0c9855..5434c9e9 100644 --- a/src/dasm/dasm.c +++ b/src/dasm/dasm.c @@ -179,7 +179,7 @@ dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_coun //- rjf: opening handles & correllation with module internal DASM_Handle -dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, DMN_Handle process, Rng1U64 vaddr_range) +dasm_handle_from_ctrl_process_range_arch(CTRL_MachineID machine, DMN_Handle process, Rng1U64 vaddr_range, Architecture arch) { DASM_Handle result = {0}; if(machine != 0 && process.u64[0] != 0) @@ -196,7 +196,8 @@ dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, DMN_Handle process, { if(e->machine_id == machine && ctrl_handle_match(e->process, process) && - MemoryMatchStruct(&e->vaddr_range, &vaddr_range)) + MemoryMatchStruct(&e->vaddr_range, &vaddr_range) && + e->arch == arch) { entity = e; break; @@ -209,6 +210,7 @@ dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, DMN_Handle process, entity->machine_id = machine; entity->process = process; entity->vaddr_range= vaddr_range; + entity->arch = arch; entity->id = ins_atomic_u64_inc_eval(&dasm_shared->entity_id_gen); entity->decode_inst_arena = arena_alloc__sized(MB(256), KB(64)); entity->decode_string_arena = arena_alloc__sized(GB(1), KB(64)); @@ -413,7 +415,7 @@ dasm_decode_thread_entry_point(void *p) ctrl_machine_id = entity->machine_id; ctrl_process = entity->process; vaddr_range = entity->vaddr_range; - arch = ctrl_arch_from_handle(ctrl_machine_id, ctrl_process); + arch = entity->arch; bytes_processed_counter = &entity->bytes_processed; U64 bytes_to_process = dim_1u64(vaddr_range); ins_atomic_u64_eval_assign(&entity->bytes_processed, 0); @@ -465,7 +467,7 @@ dasm_decode_thread_entry_point(void *p) if(good_task) { data.str = push_array_no_zero(scratch.arena, U8, dim_1u64(chunk_vaddr_range)); - data.size = ctrl_process_read(ctrl_machine_id, ctrl_process, chunk_vaddr_range, data.str); + data.size = dmn_process_read(ctrl_process, chunk_vaddr_range, data.str); if(data.size != 0) { inst_list = dasm_inst_chunk_list_from_arch_addr_data(scratch.arena, bytes_processed_counter, arch, chunk_vaddr_range.min, data); diff --git a/src/dasm/dasm.h b/src/dasm/dasm.h index 61200578..6bf4450c 100644 --- a/src/dasm/dasm.h +++ b/src/dasm/dasm.h @@ -79,6 +79,7 @@ struct DASM_Entity CTRL_MachineID machine_id; DMN_Handle process; Rng1U64 vaddr_range; + Architecture arch; U64 id; // rjf: top-level info @@ -187,7 +188,7 @@ internal DASM_InstChunkList dasm_inst_chunk_list_from_arch_addr_data(Arena *aren //~ rjf: Cache Lookups //- rjf: opening handles & correllation with module -internal DASM_Handle dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, DMN_Handle process, Rng1U64 vaddr_range); +internal DASM_Handle dasm_handle_from_ctrl_process_range_arch(CTRL_MachineID machine, DMN_Handle process, Rng1U64 vaddr_range, Architecture arch); //- rjf: asking for top-level info of a handle internal DASM_BinaryInfo dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle); diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 46e3ffac..8ef806e3 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -1404,7 +1404,7 @@ internal DASM_Handle df_dasm_handle_from_process_vaddr(DF_Entity *process, U64 vaddr) { Rng1U64 disasm_vaddr_rng = r1u64(AlignDownPow2(vaddr, KB(4)), AlignDownPow2(vaddr, KB(4)) + KB(16)); - DASM_Handle dasm_handle = dasm_handle_from_ctrl_process_range(process->ctrl_machine_id, process->ctrl_handle, disasm_vaddr_rng); + DASM_Handle dasm_handle = dasm_handle_from_ctrl_process_range_arch(process->ctrl_machine_id, process->ctrl_handle, disasm_vaddr_rng, process->arch); return dasm_handle; } @@ -2710,11 +2710,9 @@ df_debug_info_path_from_module(Arena *arena, DF_Entity *module) } else { - Temp scratch = scratch_begin(&arena, 1); String8 exe_path = module->name; - String8 dbg_path = ctrl_og_dbg_path_from_exe_path(arena, exe_path); + String8 dbg_path = push_str8f(arena, "%S.pdb", str8_chop_last_dot(exe_path)); result = dbg_path; - scratch_end(scratch); } ProfEnd(); return result; @@ -2830,8 +2828,8 @@ df_trap_net_from_thread__step_over_inst(Arena *arena, DF_Entity *thread) String8 machine_code = {0}; { Rng1U64 rng = r1u64(ip_vaddr, ip_vaddr+max_instruction_size_from_arch(arch)); - machine_code.str = push_array_no_zero(scratch.arena, U8, max_instruction_size_from_arch(arch)); - machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, rng, machine_code.str); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, rng, max_U64); + machine_code = machine_code_slice.data; } // rjf: build traps if machine code was read successfully @@ -2897,8 +2895,8 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) String8 machine_code = {0}; if(good_line_info) { - machine_code.str = push_array_no_zero(scratch.arena, U8, dim_1u64(line_vaddr_rng)); - machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, machine_code.str); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, max_U64); + machine_code = machine_code_slice.data; } // rjf: machine code => ctrl flow analysis @@ -3022,8 +3020,8 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) String8 machine_code = {0}; if(good_line_info) { - machine_code.str = push_array_no_zero(scratch.arena, U8, dim_1u64(line_vaddr_rng)); - machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, machine_code.str); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, max_U64); + machine_code = machine_code_slice.data; } // rjf: machine code => ctrl flow analysis @@ -3581,10 +3579,10 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 //- rjf: read module's TLS index U64 tls_index = 0; { - U64 bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, &tls_index); - if(bytes_read < sizeof(U64)) + CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, max_U64); + if(tls_index_slice.data.size >= addr_size) { - tls_index = 0; + tls_index = *(U64 *)tls_index_slice.data.str; } } @@ -3658,14 +3656,14 @@ internal CTRL_Unwind df_push_unwind_from_thread(Arena *arena, DF_Entity *thread) { DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - CTRL_Unwind unwind = ctrl_unwind_from_process_thread(arena, thread->ctrl_machine_id, process->ctrl_handle, thread->ctrl_handle); + CTRL_Unwind unwind = ctrl_unwind_from_thread(arena, thread->ctrl_machine_id, thread->ctrl_handle, 0); return unwind; } internal U64 df_rip_from_thread(DF_Entity *thread) { - U64 result = ctrl_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); + U64 result = ctrl_query_cached_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); return result; } @@ -3718,7 +3716,10 @@ df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity * internal B32 df_set_thread_rip(DF_Entity *thread, U64 vaddr) { - B32 result = ctrl_thread_write_rip(thread->ctrl_machine_id, thread->ctrl_handle, vaddr); + Temp scratch = scratch_begin(0, 0); + void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, thread->ctrl_machine_id, thread->ctrl_handle, max_U64); + regs_arch_block_write_rip(thread->arch, block, vaddr); + B32 result = ctrl_thread_write_reg_block(thread->ctrl_machine_id, thread->ctrl_handle, block); // rjf: early mutation of unwind cache for immediate frontend effect if(result) @@ -3738,6 +3739,7 @@ df_set_thread_rip(DF_Entity *thread, U64 vaddr) } } + scratch_end(scratch); return result; } @@ -4134,7 +4136,7 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ //- rjf: unpack arguments DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); - U64 tls_root_vaddr = ctrl_tls_root_vaddr_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); + U64 tls_root_vaddr = ctrl_query_cached_tls_root_vaddr_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); DF_Entity *process = thread->parent; U64 unwind_count = ctrl_ctx->unwind_count; CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index a93de0d0..d7fa44bb 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -240,9 +240,9 @@ df_process_info_list_from_query(Arena *arena, String8 query) //- rjf: build list DF_ProcessInfoList list = {0}; { - DEMON_ProcessIter iter = {0}; - demon_proc_iter_begin(&iter); - for(DEMON_ProcessInfo info = {0}; demon_proc_iter_next(scratch.arena, &iter, &info);) + DMN_ProcessIter iter = {0}; + dmn_process_iter_begin(&iter); + for(DMN_ProcessInfo info = {0}; dmn_process_iter_next(scratch.arena, &iter, &info);) { // rjf: skip root-level or otherwise 0-pid processes if(info.pid == 0) @@ -290,7 +290,7 @@ df_process_info_list_from_query(Arena *arena, String8 query) list.count += 1; } } - demon_proc_iter_end(&iter); + dmn_process_iter_end(&iter); } scratch_end(scratch); @@ -7552,8 +7552,9 @@ DF_VIEW_CMD_FUNCTION_DEF(Memory) DF_VIEW_UI_FUNCTION_DEF(Memory) { - Temp scratch = scratch_begin(0, 0); ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + HS_Scope *hs_scope = hs_scope_open(); ////////////////////////////// //- rjf: unpack state @@ -7766,8 +7767,8 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) // rjf: try to read new memory for this range U64 bytes_to_read = dim_1u64(chunk_aligned_range_bytes); U8 *buffer = push_array_no_zero(scratch.arena, U8, bytes_to_read); - U64 half1_bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min, chunk_aligned_range_bytes.min+bytes_to_read/2), buffer+0); - U64 half2_bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min+bytes_to_read/2, chunk_aligned_range_bytes.max), buffer+bytes_to_read/2); + U64 half1_bytes_read = dmn_process_read(process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min, chunk_aligned_range_bytes.min+bytes_to_read/2), buffer+0); + U64 half2_bytes_read = dmn_process_read(process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min+bytes_to_read/2, chunk_aligned_range_bytes.max), buffer+bytes_to_read/2); // rjf: worked? -> clear cache & store if(half1_bytes_read+half2_bytes_read >= bytes_to_read) @@ -8340,6 +8341,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) } } + hs_scope_close(hs_scope); scratch_end(scratch); ProfEnd(); } diff --git a/src/df/gfx/df_views.h b/src/df/gfx/df_views.h index b32c90a0..064609d8 100644 --- a/src/df/gfx/df_views.h +++ b/src/df/gfx/df_views.h @@ -144,7 +144,7 @@ struct DF_EntityListerItemArray typedef struct DF_ProcessInfo DF_ProcessInfo; struct DF_ProcessInfo { - DEMON_ProcessInfo info; + DMN_ProcessInfo info; B32 is_attached; FuzzyMatchRangeList attached_match_ranges; FuzzyMatchRangeList name_match_ranges; diff --git a/src/raddbg/raddbg_main.cpp b/src/raddbg/raddbg_main.cpp index 24565311..827a4c01 100644 --- a/src/raddbg/raddbg_main.cpp +++ b/src/raddbg/raddbg_main.cpp @@ -43,7 +43,7 @@ #include "regs/raddbgi/regs_raddbgi.h" #include "type_graph/type_graph.h" #include "dbgi/dbgi.h" -#include "demon/demon_inc.h" +#include "demon2/demon2_inc.h" #include "eval/eval_inc.h" #include "unwind/unwind.h" #include "ctrl/ctrl_inc.h" @@ -81,7 +81,7 @@ #include "regs/raddbgi/regs_raddbgi.c" #include "type_graph/type_graph.c" #include "dbgi/dbgi.c" -#include "demon/demon_inc.c" +#include "demon2/demon2_inc.c" #include "eval/eval_inc.c" #include "unwind/unwind.c" #include "ctrl/ctrl_inc.c" From d1e88f781e5102654946ef3231cbc52b06e30dab Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 12 Mar 2024 14:20:24 -0700 Subject: [PATCH 04/33] tweak ctrl entity building to be bucketed per 'entity store' - we can now have multiple 'entity stores', one on the frontend thread, one on the ctrl thread, and keep them in sync at specific points via event lists --- src/ctrl/ctrl_core.c | 421 +++++++++++++++++++++++++----------------- src/ctrl/ctrl_core.h | 47 +++-- src/df/core/df_core.c | 4 +- src/df/core/df_core.h | 1 + 4 files changed, 282 insertions(+), 191 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index cd951f07..44f6eaec 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -460,6 +460,233 @@ ctrl_event_from_serialized_string(Arena *arena, String8 string) return event; } +//////////////////////////////// +//~ rjf: Entity Type Functions + +//- rjf: cache creation/destruction + +internal CTRL_EntityStore * +ctrl_entity_store_alloc(void) +{ + Arena *arena = arena_alloc(); + CTRL_EntityStore *store = push_array(arena, CTRL_EntityStore, 1); + store->arena = arena; + return store; +} + +internal void +ctrl_entity_store_release(CTRL_EntityStore *cache) +{ + arena_release(cache->arena); +} + +//- rjf: entity construction/deletion + +internal CTRL_Entity * +ctrl_entity_alloc(CTRL_EntityStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, CTRL_MachineID machine_id, DMN_Handle handle) +{ + CTRL_Entity *entity = &ctrl_entity_nil; + { + // rjf: allocate + entity = store->free; + { + if(entity != 0) + { + SLLStackPop(store->free); + } + else + { + entity = push_array_no_zero(store->arena, CTRL_Entity, 1); + } + MemoryZeroStruct(entity); + } + + // rjf: fill + { + entity->kind = kind; + entity->machine_id = machine_id; + entity->handle = handle; + entity->parent = parent; + entity->next = entity->prev = entity->first = entity->last = &ctrl_entity_nil; + if(parent != &ctrl_entity_nil) + { + DLLPushBack_NPZ(&ctrl_entity_nil, parent->first, parent->last, entity, next, prev); + } + } + + // rjf: insert into hash map + { + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, handle); + U64 slot_idx = hash%store->hash_slots_count; + CTRL_EntityHashSlot *slot = &store->hash_slots[slot_idx]; + CTRL_EntityHashNode *node = 0; + for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) + { + if(n->entity->machine_id == machine_id && dmn_handle_match(n->entity->handle, handle)) + { + node = n; + break; + } + } + if(node == 0) + { + node = store->hash_node_free; + if(node != 0) + { + SLLStackPop(store->hash_node_free); + } + else + { + node = push_array_no_zero(store->arena, CTRL_EntityHashNode, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->entity = entity; + } + } + } + return entity; +} + +internal void +ctrl_entity_release(CTRL_EntityStore *store, CTRL_Entity *entity) +{ + // rjf: unhook root + if(entity->parent != &ctrl_entity_nil) + { + DLLRemove_NPZ(&ctrl_entity_nil, entity->parent->first, entity->parent->last, entity, next, prev); + } + + // rjf: walk every entity in this tree, free each + if(entity != &ctrl_entity_nil) + { + Temp scratch = scratch_begin(0, 0); + typedef struct Task Task; + struct Task + { + Task *next; + CTRL_Entity *e; + }; + Task start_task = {0, entity}; + Task *first_task = &start_task; + Task *last_task = &start_task; + for(Task *t = first_task; t != 0; t = t->next) + { + for(CTRL_Entity *child = entity->first; child != &ctrl_entity_nil; child = child->next) + { + Task *t = push_array(scratch.arena, Task, 1); + t->e = child; + SLLQueuePush(first_task, last_task, t); + } + + // rjf: free entity + SLLStackPush(store->free, t->e); + + // rjf: remove from hash map + { + U64 hash = ctrl_hash_from_machine_id_handle(t->e->machine_id, t->e->handle); + U64 slot_idx = hash%store->hash_slots_count; + CTRL_EntityHashSlot *slot = &store->hash_slots[slot_idx]; + CTRL_EntityHashNode *node = 0; + for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) + { + if(n->entity->machine_id == t->e->machine_id && dmn_handle_match(n->entity->handle, t->e->handle)) + { + DLLRemove(slot->first, slot->last, n); + SLLStackPush(store->hash_node_free, n); + break; + } + } + } + } + scratch_end(scratch); + } +} + +//- rjf: entity store lookups + +internal CTRL_Entity * +ctrl_entity_from_machine_id_handle(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle handle) +{ + CTRL_Entity *entity = &ctrl_entity_nil; + { + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, handle); + U64 slot_idx = hash%store->hash_slots_count; + CTRL_EntityHashSlot *slot = &store->hash_slots[slot_idx]; + CTRL_EntityHashNode *node = 0; + for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) + { + if(n->entity->machine_id == machine_id && dmn_handle_match(n->entity->handle, handle)) + { + entity = n->entity; + break; + } + } + } + return entity; +} + +//- rjf: applying events to entity caches + +internal void +ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) +{ + //- rjf: construct root-level entities + if(!store->root) + { + CTRL_Entity *root = store->root = ctrl_entity_alloc(store, &ctrl_entity_nil, CTRL_EntityKind_Root, 0, dmn_handle_zero()); + CTRL_Entity *local_machine = ctrl_entity_alloc(store, root, CTRL_EntityKind_Machine, CTRL_MachineID_Local, dmn_handle_zero()); + (void)local_machine; + } + + //- rjf: scan events & construct entities + for(CTRL_EventNode *n = list->first; n != 0; n = n->next) + { + CTRL_Event *event = &n->v; + switch(event->kind) + { + //- rjf: processes + case CTRL_EventKind_NewProc: + { + CTRL_Entity *machine = ctrl_entity_from_machine_id_handle(store, event->machine_id, dmn_handle_zero()); + CTRL_Entity *process = ctrl_entity_alloc(store, machine, CTRL_EntityKind_Process, event->machine_id, event->entity); + process->arch = event->arch; + }break; + case CTRL_EventKind_EndProc: + { + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); + ctrl_entity_release(store, process); + }break; + + //- rjf: threads + case CTRL_EventKind_NewThread: + { + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->parent); + CTRL_Entity *thread = ctrl_entity_alloc(store, process, CTRL_EntityKind_Thread, event->machine_id, event->entity); + thread->arch = event->arch; + }break; + case CTRL_EventKind_EndThread: + { + CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); + ctrl_entity_release(store, thread); + }break; + + //- rjf: modules + case CTRL_EventKind_NewModule: + { + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->parent); + CTRL_Entity *module = ctrl_entity_alloc(store, process, CTRL_EntityKind_Module, event->machine_id, event->entity); + module->arch = event->arch; + }break; + case CTRL_EventKind_EndModule: + { + CTRL_Entity *module = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); + ctrl_entity_release(store, module); + }break; + } + } +} + //////////////////////////////// //~ rjf: Main Layer Initialization @@ -504,11 +731,7 @@ ctrl_init(void) ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc(); } - ctrl_state->entity_rw_mutex = os_rw_mutex_alloc(); - ctrl_state->entity_arena = arena_alloc(); - ctrl_state->entity_root = &ctrl_entity_nil; - ctrl_state->entity_hash_slots_count = 4096; - ctrl_state->entity_hash_slots = push_array(arena, CTRL_EntityHashSlot, ctrl_state->entity_hash_slots_count); + ctrl_state->ctrl_thread_entity_store = ctrl_entity_store_alloc(); ctrl_state->u2c_ring_size = KB(64); ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); ctrl_state->u2c_ring_mutex = os_mutex_alloc(); @@ -925,24 +1148,28 @@ ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, internal void * ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us) { + // TODO(rjf) return 0; } internal U64 ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) { + // TODO(rjf) return 0; } internal U64 ctrl_query_cached_rip_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) { + // TODO(rjf) return 0; } internal U64 ctrl_query_cached_rsp_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) { + // TODO(rjf) return 0; } @@ -960,12 +1187,12 @@ ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void * //~ rjf: Unwinding Functions internal CTRL_Unwind -ctrl_unwind_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us) +ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); DBGI_Scope *scope = dbgi_scope_open(); - CTRL_Entity *thread_entity = ctrl_entity_from_machine_id_handle(machine_id, thread); + CTRL_Entity *thread_entity = ctrl_entity_from_machine_id_handle(store, machine_id, thread); CTRL_Entity *process_entity = thread_entity->parent; Architecture arch = thread_entity->arch; U64 arch_reg_block_size = regs_block_size_from_architecture(arch); @@ -1125,29 +1352,6 @@ ctrl_string2alias_from_arch(Architecture arch) return &ctrl_state->arch_string2alias_tables[arch]; } -//- rjf: entity state reading - -internal CTRL_Entity * -ctrl_entity_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle) -{ - CTRL_Entity *entity = &ctrl_entity_nil; - { - U64 hash = ctrl_hash_from_machine_id_handle(machine_id, handle); - U64 slot_idx = hash%ctrl_state->entity_hash_slots_count; - CTRL_EntityHashSlot *slot = &ctrl_state->entity_hash_slots[slot_idx]; - CTRL_EntityHashNode *node = 0; - for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) - { - if(n->entity->machine_id == machine_id && dmn_handle_match(n->entity->handle, handle)) - { - entity = n->entity; - break; - } - } - } - return entity; -} - //////////////////////////////// //~ rjf: Control-Thread Functions @@ -1220,6 +1424,7 @@ ctrl_c2u_push_events(CTRL_EventList *events) { if(events->count != 0) ProfScope("ctrl_c2u_push_events") { + ctrl_entity_store_apply_events(ctrl_state->ctrl_thread_entity_store, events); for(CTRL_EventNode *n = events->first; n != 0; n = n ->next) { Temp scratch = scratch_begin(0, 0); @@ -1281,133 +1486,6 @@ ctrl_c2u_pop_events(Arena *arena) return events; } -//- rjf: entity tree construction - -internal CTRL_Entity * -ctrl_thread__entity_alloc(CTRL_Entity *parent, CTRL_EntityKind kind, CTRL_MachineID machine_id, DMN_Handle handle) -{ - CTRL_Entity *entity = &ctrl_entity_nil; - OS_MutexScopeW(ctrl_state->entity_rw_mutex) - { - // rjf: allocate - entity = ctrl_state->entity_free; - { - if(entity != 0) - { - SLLStackPop(ctrl_state->entity_free); - } - else - { - entity = push_array_no_zero(ctrl_state->entity_arena, CTRL_Entity, 1); - } - MemoryZeroStruct(entity); - } - - // rjf: fill - { - entity->kind = kind; - entity->machine_id = machine_id; - entity->handle = handle; - entity->parent = parent; - entity->next = entity->prev = entity->first = entity->last = &ctrl_entity_nil; - if(parent != &ctrl_entity_nil) - { - DLLPushBack_NPZ(&ctrl_entity_nil, parent->first, parent->last, entity, next, prev); - } - } - - // rjf: insert into hash map - { - U64 hash = ctrl_hash_from_machine_id_handle(machine_id, handle); - U64 slot_idx = hash%ctrl_state->entity_hash_slots_count; - CTRL_EntityHashSlot *slot = &ctrl_state->entity_hash_slots[slot_idx]; - CTRL_EntityHashNode *node = 0; - for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) - { - if(n->entity->machine_id == machine_id && dmn_handle_match(n->entity->handle, handle)) - { - node = n; - break; - } - } - if(node == 0) - { - node = ctrl_state->entity_hash_node_free; - if(node != 0) - { - SLLStackPop(ctrl_state->entity_hash_node_free); - } - else - { - node = push_array_no_zero(ctrl_state->entity_arena, CTRL_EntityHashNode, 1); - } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - node->entity = entity; - } - } - } - return entity; -} - -internal void -ctrl_thread__entity_release(CTRL_Entity *entity) -{ - OS_MutexScopeW(ctrl_state->entity_rw_mutex) - { - // rjf: unhook root - if(entity->parent != &ctrl_entity_nil) - { - DLLRemove_NPZ(&ctrl_entity_nil, entity->parent->first, entity->parent->last, entity, next, prev); - } - - // rjf: walk every entity in this tree, free each - if(entity != &ctrl_entity_nil) - { - Temp scratch = scratch_begin(0, 0); - typedef struct Task Task; - struct Task - { - Task *next; - CTRL_Entity *e; - }; - Task start_task = {0, entity}; - Task *first_task = &start_task; - Task *last_task = &start_task; - for(Task *t = first_task; t != 0; t = t->next) - { - for(CTRL_Entity *child = entity->first; child != &ctrl_entity_nil; child = child->next) - { - Task *t = push_array(scratch.arena, Task, 1); - t->e = child; - SLLQueuePush(first_task, last_task, t); - } - - // rjf: free entity - SLLStackPush(ctrl_state->entity_free, t->e); - - // rjf: remove from hash map - { - U64 hash = ctrl_hash_from_machine_id_handle(t->e->machine_id, t->e->handle); - U64 slot_idx = hash%ctrl_state->entity_hash_slots_count; - CTRL_EntityHashSlot *slot = &ctrl_state->entity_hash_slots[slot_idx]; - CTRL_EntityHashNode *node = 0; - for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) - { - if(n->entity->machine_id == t->e->machine_id && dmn_handle_match(n->entity->handle, t->e->handle)) - { - DLLRemove(slot->first, slot->last, n); - SLLStackPush(ctrl_state->entity_hash_node_free, n); - break; - } - } - } - } - scratch_end(scratch); - } - } -} - //- rjf: entry point internal void @@ -1416,13 +1494,6 @@ ctrl_thread__entry_point(void *p) ThreadNameF("[ctrl] thread"); ProfBeginFunction(); - //- rjf: set up initial entities - { - CTRL_Entity *root = ctrl_thread__entity_alloc(&ctrl_entity_nil, CTRL_EntityKind_Root, 0, dmn_handle_zero()); - CTRL_Entity *local_machine = ctrl_thread__entity_alloc(root, CTRL_EntityKind_Machine, CTRL_MachineID_Local, dmn_handle_zero()); - (void)local_machine; - } - //- rjf: loop Temp scratch = scratch_begin(0, 0); for(;;) @@ -1479,7 +1550,7 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID m { Temp scratch = scratch_begin(&arena, 1); DBGI_Scope *scope = dbgi_scope_open(); - CTRL_Entity *module_entity = ctrl_entity_from_machine_id_handle(machine_id, module); + CTRL_Entity *module_entity = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, machine_id, module); String8 exe_path = module_entity->name; DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); RDI_Parsed *rdi = &dbgi->rdi; @@ -1651,7 +1722,7 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls (spoof == 0 || ev->instruction_pointer != spoof->new_ip_value)) { DBGI_Scope *scope = dbgi_scope_open(); - CTRL_Entity *process = ctrl_entity_from_machine_id_handle(CTRL_MachineID_Local, ev->process); + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, ev->process); CTRL_Entity *module = process->first; if(module != &ctrl_entity_nil) { @@ -1735,7 +1806,7 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls U64 size_of_spoof = 0; if(do_spoof) ProfScope("prep spoof") { - CTRL_Entity *spoof_process = ctrl_entity_from_machine_id_handle(CTRL_MachineID_Local, spoof->process); + CTRL_Entity *spoof_process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, spoof->process); Architecture arch = spoof_process->arch; size_of_spoof = bit_size_from_arch(arch)/8; dmn_process_read(spoof_process->handle, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); @@ -1788,7 +1859,7 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls // simply been sent other debug events first if(spoof != 0) { - CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(CTRL_MachineID_Local, spoof->thread); + CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, spoof->thread); Architecture arch = thread->arch; void *regs_block = push_array(scratch.arena, U8, regs_block_size_from_architecture(arch)); dmn_thread_read_reg_block(spoof->thread, regs_block); @@ -2165,7 +2236,7 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) for(U64 process_idx = 0; process_idx < run_ctrls.run_entity_count; process_idx += 1) { //- rjf: unpack process & first module info - CTRL_Entity *process = ctrl_entity_from_machine_id_handle(CTRL_MachineID_Local, run_ctrls.run_entities[process_idx]); + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, run_ctrls.run_entities[process_idx]); CTRL_Entity *module = process->first; U64 module_base_vaddr = module->vaddr_range.min; String8 exe_path = module->name; @@ -2535,7 +2606,9 @@ ctrl_thread__run(CTRL_Msg *msg) //- rjf: gather all initial breakpoints // DMN_TrapChunkList user_traps = {0}; - for(CTRL_Entity *machine = ctrl_state->entity_root->first; machine != &ctrl_entity_nil; machine = machine->next) + for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; + machine != &ctrl_entity_nil; + machine = machine->next) { if(machine->kind != CTRL_EntityKind_Machine) { continue; } for(CTRL_Entity *process = machine->first; process != &ctrl_entity_nil; process = process->next) @@ -2571,7 +2644,9 @@ ctrl_thread__run(CTRL_Msg *msg) { // rjf: gather stuck threads DMN_HandleList stuck_threads = {0}; - for(CTRL_Entity *machine = ctrl_state->entity_root->first; machine != &ctrl_entity_nil; machine = machine->next) + for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; + machine != &ctrl_entity_nil; + machine = machine->next) { if(machine->kind != CTRL_EntityKind_Machine) { continue; } for(CTRL_Entity *process = machine->first; process != &ctrl_entity_nil; process = process->next) @@ -2783,7 +2858,7 @@ ctrl_thread__run(CTRL_Msg *msg) ////////////////////////// //- rjf: unpack info about thread attached to event // - CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(CTRL_MachineID_Local, event->thread); + CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->thread); Architecture arch = thread->arch; U64 reg_size = regs_block_size_from_architecture(arch); void *thread_regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, CTRL_MachineID_Local, event->thread, max_U64); @@ -2793,7 +2868,7 @@ ctrl_thread__run(CTRL_Msg *msg) U64 module_base_vaddr = 0; U64 thread_rip_voff = 0; { - CTRL_Entity *process = ctrl_entity_from_machine_id_handle(CTRL_MachineID_Local, event->thread); + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->process); for(CTRL_Entity *module = process->first; module != &ctrl_entity_nil; module = module->next) { if(contains_1u64(module->vaddr_range, thread_rip_vaddr)) diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index e4bd7653..9ef1c66a 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -83,6 +83,17 @@ struct CTRL_EntityHashSlot CTRL_EntityHashNode *last; }; +typedef struct CTRL_EntityStore CTRL_EntityStore; +struct CTRL_EntityStore +{ + Arena *arena; + CTRL_Entity *root; + CTRL_Entity *free; + CTRL_EntityHashSlot *hash_slots; + CTRL_EntityHashNode *hash_node_free; + U64 hash_slots_count; +}; + //////////////////////////////// //~ rjf: Unwind Types @@ -473,15 +484,6 @@ struct CTRL_State CTRL_ProcessMemoryCache process_memory_cache; CTRL_ThreadRegCache thread_reg_cache; - // rjf: entity tree - OS_Handle entity_rw_mutex; - Arena *entity_arena; - CTRL_Entity *entity_root; - CTRL_Entity *entity_free; - CTRL_EntityHashSlot *entity_hash_slots; - CTRL_EntityHashNode *entity_hash_node_free; - U64 entity_hash_slots_count; - // rjf: user -> ctrl msg ring buffer U64 u2c_ring_size; U8 *u2c_ring_base; @@ -500,6 +502,7 @@ struct CTRL_State // rjf: ctrl thread state OS_Handle ctrl_thread; + CTRL_EntityStore *ctrl_thread_entity_store; Arena *dmn_event_arena; DMN_EventNode *first_dmn_event_node; DMN_EventNode *last_dmn_event_node; @@ -585,6 +588,23 @@ internal void ctrl_event_list_concat_in_place(CTRL_EventList *dst, CTRL_EventLis internal String8 ctrl_serialized_string_from_event(Arena *arena, CTRL_Event *event); internal CTRL_Event ctrl_event_from_serialized_string(Arena *arena, String8 string); +//////////////////////////////// +//~ rjf: Entity Type Functions + +//- rjf: cache creation/destruction +internal CTRL_EntityStore *ctrl_entity_store_alloc(void); +internal void ctrl_entity_store_release(CTRL_EntityStore *cache); + +//- rjf: entity construction/deletion +internal CTRL_Entity *ctrl_entity_alloc(CTRL_EntityStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, CTRL_MachineID machine_id, DMN_Handle handle); +internal void ctrl_entity_release(CTRL_EntityStore *store, CTRL_Entity *entity); + +//- rjf: entity store lookups +internal CTRL_Entity *ctrl_entity_from_machine_id_handle(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle handle); + +//- rjf: applying events to entity caches +internal void ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list); + //////////////////////////////// //~ rjf: Main Layer Initialization @@ -624,7 +644,7 @@ internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle t //////////////////////////////// //~ rjf: Unwinding Functions -internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us); +internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us); //////////////////////////////// //~ rjf: Halting All Attached Processes @@ -643,9 +663,6 @@ internal U64 ctrl_reggen_idx(void); internal EVAL_String2NumMap *ctrl_string2reg_from_arch(Architecture arch); internal EVAL_String2NumMap *ctrl_string2alias_from_arch(Architecture arch); -//- rjf: entity state reading -internal CTRL_Entity *ctrl_entity_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle); - //////////////////////////////// //~ rjf: Control-Thread Functions @@ -657,10 +674,6 @@ internal CTRL_MsgList ctrl_u2c_pop_msgs(Arena *arena); internal void ctrl_c2u_push_events(CTRL_EventList *events); internal CTRL_EventList ctrl_c2u_pop_events(Arena *arena); -//- rjf: entity tree construction -internal CTRL_Entity *ctrl_thread__entity_alloc(CTRL_Entity *parent, CTRL_EntityKind kind, CTRL_MachineID machine_id, DMN_Handle handle); -internal void ctrl_thread__entity_release(CTRL_Entity *entity); - //- rjf: entry point internal void ctrl_thread__entry_point(void *p); diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 8ef806e3..b73595c3 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -3656,7 +3656,7 @@ internal CTRL_Unwind df_push_unwind_from_thread(Arena *arena, DF_Entity *thread) { DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - CTRL_Unwind unwind = ctrl_unwind_from_thread(arena, thread->ctrl_machine_id, thread->ctrl_handle, 0); + CTRL_Unwind unwind = ctrl_unwind_from_thread(arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); return unwind; } @@ -6398,6 +6398,7 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist) df_state->entities_base = push_array(df_state->entities_arena, DF_Entity, 0); df_state->entities_count = 0; df_state->ctrl_msg_arena = arena_alloc(); + df_state->ctrl_entity_store = ctrl_entity_store_alloc(); df_state->ctrl_stop_arena = arena_alloc(); df_state->entities_root = df_entity_alloc(0, &df_g_nil_entity, DF_EntityKind_Root); df_state->cmd_spec_table_size = 1024; @@ -6549,6 +6550,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) //- rjf: consume & process events CTRL_EventList events = ctrl_c2u_pop_events(scratch.arena); + ctrl_entity_store_apply_events(df_state->ctrl_entity_store, &events); for(CTRL_EventNode *event_n = events.first; event_n != 0; event_n = event_n->next) { CTRL_Event *event = &event_n->v; diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index 5edc70ae..1192d43d 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -1179,6 +1179,7 @@ struct DF_State B32 ctrl_solo_stepping_mode; // rjf: control thread ctrl -> user reading state + CTRL_EntityStore *ctrl_entity_store; Arena *ctrl_stop_arena; CTRL_Event ctrl_last_stop_event; From 8639faabdde8c0a148a936f29864a09e46328405 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 12 Mar 2024 14:56:02 -0700 Subject: [PATCH 05/33] ctrl entity string allocation & tracking, for thread names & module names; fix process memory cache in edge cases --- src/ctrl/ctrl_core.c | 171 ++++++++++++++++++++++----- src/ctrl/ctrl_core.h | 21 +++- src/demon2/demon2_core.h | 1 + src/demon2/win32/demon2_core_win32.c | 7 ++ 4 files changed, 165 insertions(+), 35 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 44f6eaec..75abeeba 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -471,6 +471,8 @@ ctrl_entity_store_alloc(void) Arena *arena = arena_alloc(); CTRL_EntityStore *store = push_array(arena, CTRL_EntityStore, 1); store->arena = arena; + store->hash_slots_count = 1024; + store->hash_slots = push_array(arena, CTRL_EntityHashSlot, store->hash_slots_count); return store; } @@ -480,10 +482,101 @@ ctrl_entity_store_release(CTRL_EntityStore *cache) arena_release(cache->arena); } +internal U64 +ctrl_name_bucket_idx_from_string_size(U64 size) +{ + U64 size_rounded = u64_up_to_pow2(size+1); + size_rounded = ClampBot((1<<4), size_rounded); + U64 bucket_idx = 0; + switch(size_rounded) + { + case 1<<4: {bucket_idx = 0;}break; + case 1<<5: {bucket_idx = 1;}break; + case 1<<6: {bucket_idx = 2;}break; + case 1<<7: {bucket_idx = 3;}break; + case 1<<8: {bucket_idx = 4;}break; + case 1<<9: {bucket_idx = 5;}break; + case 1<<10:{bucket_idx = 6;}break; + default:{bucket_idx = ArrayCount(((CTRL_EntityStore *)0)->free_string_chunks)-1;}break; + } + return bucket_idx; +} + +internal String8 +ctrl_entity_string_alloc(CTRL_EntityStore *store, String8 string) +{ + if(string.size == 0) {return str8_zero();} + U64 bucket_idx = ctrl_name_bucket_idx_from_string_size(string.size); + CTRL_EntityStringChunkNode *node = store->free_string_chunks[bucket_idx]; + + // rjf: pull from bucket free list + if(node != 0) + { + if(bucket_idx == ArrayCount(store->free_string_chunks)-1) + { + node = 0; + CTRL_EntityStringChunkNode *prev = 0; + for(CTRL_EntityStringChunkNode *n = store->free_string_chunks[bucket_idx]; + n != 0; + prev = n, n = n->next) + { + if(n->size >= string.size+1) + { + if(prev == 0) + { + store->free_string_chunks[bucket_idx] = n->next; + } + else + { + prev->next = n->next; + } + node = n; + break; + } + } + } + else + { + SLLStackPop(store->free_string_chunks[bucket_idx]); + } + } + + // rjf: no found node -> allocate new + if(node == 0) + { + U64 chunk_size = 0; + if(bucket_idx < ArrayCount(store->free_string_chunks)-1) + { + chunk_size = 1<<(bucket_idx+4); + } + else + { + chunk_size = u64_up_to_pow2(string.size); + } + U8 *chunk_memory = push_array(store->arena, U8, chunk_size); + node = (CTRL_EntityStringChunkNode *)chunk_memory; + } + + // rjf: fill string & return + String8 allocated_string = str8((U8 *)node, string.size); + MemoryCopy((U8 *)node, string.str, string.size); + return allocated_string; +} + +internal void +ctrl_entity_string_release(CTRL_EntityStore *store, String8 string) +{ + if(string.size == 0) {return;} + U64 bucket_idx = ctrl_name_bucket_idx_from_string_size(string.size); + CTRL_EntityStringChunkNode *node = (CTRL_EntityStringChunkNode *)string.str; + node->size = u64_up_to_pow2(string.size); + SLLStackPush(store->free_string_chunks[bucket_idx], node); +} + //- rjf: entity construction/deletion internal CTRL_Entity * -ctrl_entity_alloc(CTRL_EntityStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, CTRL_MachineID machine_id, DMN_Handle handle) +ctrl_entity_alloc(CTRL_EntityStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, Architecture arch, CTRL_MachineID machine_id, DMN_Handle handle) { CTRL_Entity *entity = &ctrl_entity_nil; { @@ -504,6 +597,7 @@ ctrl_entity_alloc(CTRL_EntityStore *store, CTRL_Entity *parent, CTRL_EntityKind // rjf: fill { entity->kind = kind; + entity->arch = arch; entity->machine_id = machine_id; entity->handle = handle; entity->parent = parent; @@ -603,6 +697,18 @@ ctrl_entity_release(CTRL_EntityStore *store, CTRL_Entity *entity) } } +//- rjf: entity equipment + +internal void +ctrl_entity_equip_string(CTRL_EntityStore *store, CTRL_Entity *entity, String8 string) +{ + if(entity->string.size != 0) + { + ctrl_entity_string_release(store, entity->string); + } + entity->string = ctrl_entity_string_alloc(store, string); +} + //- rjf: entity store lookups internal CTRL_Entity * @@ -634,8 +740,8 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) //- rjf: construct root-level entities if(!store->root) { - CTRL_Entity *root = store->root = ctrl_entity_alloc(store, &ctrl_entity_nil, CTRL_EntityKind_Root, 0, dmn_handle_zero()); - CTRL_Entity *local_machine = ctrl_entity_alloc(store, root, CTRL_EntityKind_Machine, CTRL_MachineID_Local, dmn_handle_zero()); + CTRL_Entity *root = store->root = ctrl_entity_alloc(store, &ctrl_entity_nil, CTRL_EntityKind_Root, Architecture_Null, 0, dmn_handle_zero()); + CTRL_Entity *local_machine = ctrl_entity_alloc(store, root, CTRL_EntityKind_Machine, architecture_from_context(), CTRL_MachineID_Local, dmn_handle_zero()); (void)local_machine; } @@ -649,8 +755,7 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) case CTRL_EventKind_NewProc: { CTRL_Entity *machine = ctrl_entity_from_machine_id_handle(store, event->machine_id, dmn_handle_zero()); - CTRL_Entity *process = ctrl_entity_alloc(store, machine, CTRL_EntityKind_Process, event->machine_id, event->entity); - process->arch = event->arch; + CTRL_Entity *process = ctrl_entity_alloc(store, machine, CTRL_EntityKind_Process, event->arch, event->machine_id, event->entity); }break; case CTRL_EventKind_EndProc: { @@ -662,21 +767,25 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) case CTRL_EventKind_NewThread: { CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->parent); - CTRL_Entity *thread = ctrl_entity_alloc(store, process, CTRL_EntityKind_Thread, event->machine_id, event->entity); - thread->arch = event->arch; + CTRL_Entity *thread = ctrl_entity_alloc(store, process, CTRL_EntityKind_Thread, event->arch, event->machine_id, event->entity); }break; case CTRL_EventKind_EndThread: { CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); ctrl_entity_release(store, thread); }break; + case CTRL_EventKind_ThreadName: + { + CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); + ctrl_entity_equip_string(store, thread, event->string); + }break; //- rjf: modules case CTRL_EventKind_NewModule: { CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->parent); - CTRL_Entity *module = ctrl_entity_alloc(store, process, CTRL_EntityKind_Module, event->machine_id, event->entity); - module->arch = event->arch; + CTRL_Entity *module = ctrl_entity_alloc(store, process, CTRL_EntityKind_Module, event->arch, event->machine_id, event->entity); + ctrl_entity_equip_string(store, module, event->string); }break; case CTRL_EventKind_EndModule: { @@ -811,31 +920,23 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle B32 is_stale = 0; OS_MutexScopeR(process_stripe->rw_mutex) { - for(;;) + for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { - for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) { - if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + U64 range_slot_idx = range_hash%n->range_hash_slots_count; + CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; + for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) { - U64 range_slot_idx = range_hash%n->range_hash_slots_count; - CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; - for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) + if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) { - if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) - { - result = range_n->hash; - is_good = 1; - is_stale = range_n->memgen_idx < ctrl_memgen_idx(); - goto read_cache__break_all; - } + result = range_n->hash; + is_good = 1; + is_stale = (range_n->memgen_idx < ctrl_memgen_idx()); + goto read_cache__break_all; } } } - if(os_now_microseconds() >= endt_us) - { - break; - } - os_condition_variable_wait_rw_r(process_stripe->cv, process_stripe->rw_mutex, endt_us); } read_cache__break_all:; } @@ -918,6 +1019,12 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle { break; } + + //- rjf: done? -> exit + if(is_good && !is_stale) + { + break; + } } return result; } @@ -1245,7 +1352,7 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma if(contains_1u64(m->vaddr_range, rip)) { module = m->handle; - module_name = m->name; + module_name = m->string; module_vaddr_range = m->vaddr_range; break; } @@ -1551,7 +1658,7 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID m Temp scratch = scratch_begin(&arena, 1); DBGI_Scope *scope = dbgi_scope_open(); CTRL_Entity *module_entity = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, machine_id, module); - String8 exe_path = module_entity->name; + String8 exe_path = module_entity->string; DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); RDI_Parsed *rdi = &dbgi->rdi; U64 base_vaddr = module_entity->vaddr_range.min; @@ -1729,7 +1836,7 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls // rjf: determine base address of asan shadow space U64 asan_shadow_base_vaddr = 0; B32 asan_shadow_variable_exists_but_is_zero = 0; - String8 module_path = module->name; + String8 module_path = module->string; DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, module_path, max_U64); RDI_Parsed *rdi = &dbgi->rdi; RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_GlobalVariables); @@ -2239,7 +2346,7 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, run_ctrls.run_entities[process_idx]); CTRL_Entity *module = process->first; U64 module_base_vaddr = module->vaddr_range.min; - String8 exe_path = module->name; + String8 exe_path = module->string; DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); RDI_Parsed *rdi = &dbgi->rdi; RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Procedures); @@ -2873,7 +2980,7 @@ ctrl_thread__run(CTRL_Msg *msg) { if(contains_1u64(module->vaddr_range, thread_rip_vaddr)) { - module_name = module->name; + module_name = module->string; module_base_vaddr = module->vaddr_range.min; thread_rip_voff = thread_rip_vaddr - module->vaddr_range.min; break; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 9ef1c66a..e7ce56e9 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -65,7 +65,7 @@ struct CTRL_Entity CTRL_MachineID machine_id; DMN_Handle handle; Rng1U64 vaddr_range; - String8 name; + String8 string; }; typedef struct CTRL_EntityHashNode CTRL_EntityHashNode; @@ -83,6 +83,13 @@ struct CTRL_EntityHashSlot CTRL_EntityHashNode *last; }; +typedef struct CTRL_EntityStringChunkNode CTRL_EntityStringChunkNode; +struct CTRL_EntityStringChunkNode +{ + CTRL_EntityStringChunkNode *next; + U64 size; +}; + typedef struct CTRL_EntityStore CTRL_EntityStore; struct CTRL_EntityStore { @@ -92,6 +99,7 @@ struct CTRL_EntityStore CTRL_EntityHashSlot *hash_slots; CTRL_EntityHashNode *hash_node_free; U64 hash_slots_count; + CTRL_EntityStringChunkNode *free_string_chunks[8]; }; //////////////////////////////// @@ -593,12 +601,19 @@ internal CTRL_Event ctrl_event_from_serialized_string(Arena *arena, String8 stri //- rjf: cache creation/destruction internal CTRL_EntityStore *ctrl_entity_store_alloc(void); -internal void ctrl_entity_store_release(CTRL_EntityStore *cache); +internal void ctrl_entity_store_release(CTRL_EntityStore *store); + +//- rjf: string allocation/deletion +internal String8 ctrl_entity_string_alloc(CTRL_EntityStore *store, String8 string); +internal void ctrl_entity_string_release(CTRL_EntityStore *store, String8 string); //- rjf: entity construction/deletion -internal CTRL_Entity *ctrl_entity_alloc(CTRL_EntityStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, CTRL_MachineID machine_id, DMN_Handle handle); +internal CTRL_Entity *ctrl_entity_alloc(CTRL_EntityStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, Architecture arch, CTRL_MachineID machine_id, DMN_Handle handle); internal void ctrl_entity_release(CTRL_EntityStore *store, CTRL_Entity *entity); +//- rjf: entity equipment +internal void ctrl_entity_equip_string(CTRL_EntityStore *store, CTRL_Entity *entity, String8 string); + //- rjf: entity store lookups internal CTRL_Entity *ctrl_entity_from_machine_id_handle(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle handle); diff --git a/src/demon2/demon2_core.h b/src/demon2/demon2_core.h index 5cff7a56..cc202c5d 100644 --- a/src/demon2/demon2_core.h +++ b/src/demon2/demon2_core.h @@ -189,6 +189,7 @@ internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src); #define dmn_process_write_struct(process, vaddr, ptr) dmn_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) //- rjf: threads +internal Architecture dmn_arch_from_thread(DMN_Handle handle); internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle); internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle); internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block); diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index afee68fa..c06d2b45 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -2333,6 +2333,13 @@ dmn_process_write(DMN_Handle process, Rng1U64 range, void *src) //- rjf: threads +internal Architecture +dmn_arch_from_thread(DMN_Handle handle) +{ + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle); + return entity->arch; +} + internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle) { From 871419de3907903f2da9eb78cb51596357ee694b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 12 Mar 2024 15:49:36 -0700 Subject: [PATCH 06/33] bugfixes in new demon layer; adjust retry mechanism in process memory cache query; ui fixes --- src/ctrl/ctrl_core.c | 26 ++++++++++++++++++++++++-- src/ctrl/ctrl_core.h | 1 + src/demon2/win32/demon2_core_win32.c | 6 +++--- src/df/core/df_core.c | 12 ++++++------ src/ui/ui_core.c | 3 ++- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 75abeeba..a0444c90 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -970,6 +970,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle } //- rjf: not good -> create range node if necessary + U64 last_time_requested_us = 0; if(!is_good) { OS_MutexScopeW(process_stripe->rw_mutex) @@ -985,6 +986,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle { if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) { + last_time_requested_us = range_n->last_time_requested_us; range_node_exists = 1; break; } @@ -1009,9 +1011,29 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle } //- rjf: not good, or is stale -> submit hash request - if(!is_good || is_stale) + if((!is_good || is_stale) && os_now_microseconds() >= last_time_requested_us+10000) { ctrl_u2ms_enqueue_req(machine_id, process, range, zero_terminated, endt_us); + OS_MutexScopeW(process_stripe->rw_mutex) + { + for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + { + U64 range_slot_idx = range_hash%n->range_hash_slots_count; + CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; + B32 range_node_exists = 0; + for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) + { + if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) + { + range_n->last_time_requested_us = os_now_microseconds(); + break; + } + } + } + } + } } //- rjf: out of time? -> exit @@ -3576,7 +3598,7 @@ ctrl_mem_stream_thread__entry_point(void *p) if(got_task && memgen_idx != preexisting_memgen_idx) { range_size = dim_1u64(vaddr_range_clamped); - U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, KB(64)); + U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, os_page_size()); range_arena = arena_alloc__sized(range_size+ARENA_HEADER_SIZE, range_size+ARENA_HEADER_SIZE); if(range_arena == 0) { diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index e7ce56e9..b33c59d6 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -377,6 +377,7 @@ struct CTRL_ProcessMemoryRangeHashNode Rng1U64 vaddr_range_clamped; U128 hash; U64 memgen_idx; + U64 last_time_requested_us; B32 is_taken; }; diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index c06d2b45..eed84eb6 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -1198,7 +1198,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) { //- rjf: scan all processes for(DMN_W32_Entity *process = dmn_w32_shared->entities_base->first; - process != 0; + process != &dmn_w32_entity_nil; process = process->next) { if(process->kind != DMN_W32_EntityKind_Process) {continue;} @@ -1345,7 +1345,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) DEBUG_EVENT evt = {0}; B32 evt_good = 0; { - B32 resume_good = 0; + B32 resume_good = 1; if(dmn_w32_shared->resume_needed) { dmn_w32_shared->resume_needed = 0; @@ -1987,7 +1987,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) { if(process->kind != DMN_W32_EntityKind_Process) { continue; } for(DMN_W32_Entity *thread = process->first; - thread != 0; + thread != &dmn_w32_entity_nil; thread = thread->next) { if(thread->kind != DMN_W32_EntityKind_Thread) { continue; } diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index b73595c3..61008dee 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -2828,7 +2828,7 @@ df_trap_net_from_thread__step_over_inst(Arena *arena, DF_Entity *thread) String8 machine_code = {0}; { Rng1U64 rng = r1u64(ip_vaddr, ip_vaddr+max_instruction_size_from_arch(arch)); - CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, rng, max_U64); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, rng, os_now_microseconds()+5000); machine_code = machine_code_slice.data; } @@ -2895,7 +2895,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) String8 machine_code = {0}; if(good_line_info) { - CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, max_U64); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, os_now_microseconds()+5000); machine_code = machine_code_slice.data; } @@ -3020,7 +3020,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) String8 machine_code = {0}; if(good_line_info) { - CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, max_U64); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, os_now_microseconds()+5000); machine_code = machine_code_slice.data; } @@ -3579,7 +3579,7 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 //- rjf: read module's TLS index U64 tls_index = 0; { - CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, max_U64); + CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, os_now_microseconds()+5000); if(tls_index_slice.data.size >= addr_size) { tls_index = *(U64 *)tls_index_slice.data.str; @@ -3592,13 +3592,13 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 U64 thread_info_addr = root_vaddr; U64 tls_addr_off = tls_index*addr_size; U64 tls_addr_array = 0; - CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(thread_info_addr, thread_info_addr+addr_size), 0); + CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(thread_info_addr, thread_info_addr+addr_size), os_now_microseconds()+5000); String8 tls_addr_array_data = tls_addr_array_slice.data; if(tls_addr_array_data.size >= 8) { MemoryCopy(&tls_addr_array, tls_addr_array_data.str, sizeof(U64)); } - CTRL_ProcessMemorySlice result_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), 0); + CTRL_ProcessMemorySlice result_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), os_now_microseconds()+5000); String8 result_data = result_slice.data; if(result_data.size >= 8) { diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 863b92a2..714ce9ef 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -2635,7 +2635,8 @@ ui_signal_from_box(UI_Box *box) //- rjf: mouse is over this box's rect, no other hot key? -> set hot key, mark hovering // { - if(contains_2f32(rect, ui_state->mouse) && + if(box->flags & UI_BoxFlag_MouseClickable && + contains_2f32(rect, ui_state->mouse) && !contains_2f32(blacklist_rect, ui_state->mouse) && (ui_key_match(ui_state->hot_box_key, ui_key_zero()) || ui_key_match(ui_state->hot_box_key, box->key)) && (ui_key_match(ui_state->active_box_key[UI_MouseButtonKind_Left], ui_key_zero()) || ui_key_match(ui_state->active_box_key[UI_MouseButtonKind_Left], box->key)) && From ea74f928cd8c9cc8c42c8dee3543cd3f634c5cde Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 12 Mar 2024 15:51:26 -0700 Subject: [PATCH 07/33] fix process memory cache query mechanism when ring buffer is near capacity --- src/ctrl/ctrl_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index a0444c90..5c4b696a 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1013,8 +1013,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle //- rjf: not good, or is stale -> submit hash request if((!is_good || is_stale) && os_now_microseconds() >= last_time_requested_us+10000) { - ctrl_u2ms_enqueue_req(machine_id, process, range, zero_terminated, endt_us); - OS_MutexScopeW(process_stripe->rw_mutex) + if(ctrl_u2ms_enqueue_req(machine_id, process, range, zero_terminated, endt_us)) OS_MutexScopeW(process_stripe->rw_mutex) { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { From c417f15912944d1afb0a548be47553975c588726 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 12 Mar 2024 09:05:00 -0700 Subject: [PATCH 08/33] fix task entry points in breakpad converter --- .../raddbgi_breakpad_from_pdb_main.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c b/src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c index 35312932..491baf79 100644 --- a/src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c +++ b/src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c @@ -61,8 +61,7 @@ struct P2B_BakeUnitVMapOut RDI_U64 vmap_entries_count; }; -internal void * -p2b_bake_unit_vmap_task__entry_point(Arena *arena, void *p) +internal TS_TASK_FUNCTION_DEF(p2b_bake_unit_vmap_task__entry_point) { P2B_BakeUnitVMapIn *in = (P2B_BakeUnitVMapIn *)p; P2B_BakeUnitVMapOut *out = push_array(arena, P2B_BakeUnitVMapOut, 1); @@ -100,8 +99,7 @@ struct P2B_BakeUnitOut RDI_Line *unit_lines; }; -internal void * -p2b_bake_unit_task__entry_point(Arena *arena, void *p) +internal TS_TASK_FUNCTION_DEF(p2b_bake_unit_task__entry_point) { P2B_BakeUnitIn *in = (P2B_BakeUnitIn *)p; P2B_BakeUnitOut *out = push_array(arena, P2B_BakeUnitOut, 1); @@ -138,8 +136,7 @@ struct P2B_DumpProcChunkIn RDIM_SymbolChunkNode *chunk; }; -internal void * -p2b_dump_proc_chunk_task__entry_point(Arena *arena, void *p) +internal TS_TASK_FUNCTION_DEF(p2b_dump_proc_chunk_task__entry_point) { P2B_DumpProcChunkIn *in = (P2B_DumpProcChunkIn *)p; String8List *out = push_array(arena, String8List, 1); From 936c6149e309b2e56731e92d8e0635467a79c632 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 12 Mar 2024 16:35:43 -0700 Subject: [PATCH 09/33] remove timeout on thread register cache accessor --- src/ctrl/ctrl_core.c | 6 +++--- src/ctrl/ctrl_core.h | 2 +- src/df/core/df_core.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 5c4b696a..d6c8df1c 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1274,7 +1274,7 @@ ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, //- rjf: thread register cache reading internal void * -ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us) +ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread) { // TODO(rjf) return 0; @@ -1332,7 +1332,7 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma case Architecture_x64: { // rjf: grab initial register block - void *regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, machine_id, thread, endt_us); + void *regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, machine_id, thread); // rjf: grab initial memory view B32 stack_memview_good = 0; @@ -2989,7 +2989,7 @@ ctrl_thread__run(CTRL_Msg *msg) CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->thread); Architecture arch = thread->arch; U64 reg_size = regs_block_size_from_architecture(arch); - void *thread_regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, CTRL_MachineID_Local, event->thread, max_U64); + void *thread_regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, CTRL_MachineID_Local, event->thread); U64 thread_rip_vaddr = regs_rip_from_arch_block(arch, thread_regs_block); DMN_Handle module = {0}; String8 module_name = {0}; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index b33c59d6..59c72af2 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -649,7 +649,7 @@ internal B32 ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, R //~ rjf: Thread Register Functions //- rjf: thread register cache reading -internal void *ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us); +internal void *ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread); internal U64 ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, DMN_Handle thread); internal U64 ctrl_query_cached_rip_from_thread(CTRL_MachineID machine_id, DMN_Handle thread); internal U64 ctrl_query_cached_rsp_from_thread(CTRL_MachineID machine_id, DMN_Handle thread); diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 61008dee..496fad24 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -3717,7 +3717,7 @@ internal B32 df_set_thread_rip(DF_Entity *thread, U64 vaddr) { Temp scratch = scratch_begin(0, 0); - void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, thread->ctrl_machine_id, thread->ctrl_handle, max_U64); + void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, thread->ctrl_machine_id, thread->ctrl_handle); regs_arch_block_write_rip(thread->arch, block, vaddr); B32 result = ctrl_thread_write_reg_block(thread->ctrl_machine_id, thread->ctrl_handle, block); From aa7c30d85be6db46b800c66fe956e9b3f07421dc Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 14 Mar 2024 21:09:43 -0700 Subject: [PATCH 10/33] ctrl: first pass at new thread registers cache; also checkpoint for progress on moving to new demon layer --- src/ctrl/ctrl_core.c | 114 ++++++++++++++++++++++++--- src/ctrl/ctrl_core.h | 4 +- src/demon2/win32/demon2_core_win32.c | 22 ++++-- src/raddbg/raddbg_main.cpp | 2 +- 4 files changed, 120 insertions(+), 22 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index d6c8df1c..b7eb4b6f 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -666,7 +666,7 @@ ctrl_entity_release(CTRL_EntityStore *store, CTRL_Entity *entity) Task *last_task = &start_task; for(Task *t = first_task; t != 0; t = t->next) { - for(CTRL_Entity *child = entity->first; child != &ctrl_entity_nil; child = child->next) + for(CTRL_Entity *child = t->e->first; child != &ctrl_entity_nil; child = child->next) { Task *t = push_array(scratch.arena, Task, 1); t->e = child; @@ -786,6 +786,7 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->parent); CTRL_Entity *module = ctrl_entity_alloc(store, process, CTRL_EntityKind_Module, event->arch, event->machine_id, event->entity); ctrl_entity_equip_string(store, module, event->string); + module->vaddr_range = event->vaddr_rng; }break; case CTRL_EventKind_EndModule: { @@ -1276,8 +1277,73 @@ ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, internal void * ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread) { - // TODO(rjf) - return 0; + CTRL_ThreadRegCache *cache = &ctrl_state->thread_reg_cache; + Architecture arch = dmn_arch_from_thread(thread); + U64 reg_block_size = regs_block_size_from_architecture(arch); + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, thread); + U64 slot_idx = hash%cache->slots_count; + U64 stripe_idx = slot_idx%cache->stripes_count; + CTRL_ThreadRegCacheSlot *slot = &cache->slots[slot_idx]; + CTRL_ThreadRegCacheStripe *stripe = &cache->stripes[stripe_idx]; + void *result = push_array(arena, U8, reg_block_size); + OS_MutexScopeR(stripe->rw_mutex) + { + // rjf: find existing node + CTRL_ThreadRegCacheNode *node = 0; + for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->thread, thread)) + { + node = n; + break; + } + } + + // rjf: allocate existing node + if(!node) + { + OS_MutexScopeRWPromote(stripe->rw_mutex) + { + for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->thread, thread)) + { + node = n; + break; + } + } + if(!node) + { + node = push_array(stripe->arena, CTRL_ThreadRegCacheNode, 1); + DLLPushBack(slot->first, slot->last, node); + node->machine_id = machine_id; + node->thread = thread; + node->block_size = reg_block_size; + node->block = push_array(stripe->arena, U8, reg_block_size); + } + } + for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->thread, thread)) + { + node = n; + break; + } + } + } + + // rjf: copy from node + if(node) + { + U64 current_reggen_idx = ctrl_reggen_idx(); + if(node->reggen_idx != current_reggen_idx && dmn_thread_read_reg_block(thread, node->block)) + { + node->reggen_idx = current_reggen_idx; + } + MemoryCopy(result, node->block, reg_block_size); + } + } + return result; } internal U64 @@ -1290,15 +1356,23 @@ ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, DMN_Hand internal U64 ctrl_query_cached_rip_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) { - // TODO(rjf) - return 0; + Temp scratch = scratch_begin(0, 0); + Architecture arch = dmn_arch_from_thread(thread); + void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, machine_id, thread); + U64 result = regs_rip_from_arch_block(arch, block); + scratch_end(scratch); + return result; } internal U64 ctrl_query_cached_rsp_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) { - // TODO(rjf) - return 0; + Temp scratch = scratch_begin(0, 0); + Architecture arch = dmn_arch_from_thread(thread); + void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, machine_id, thread); + U64 result = regs_rsp_from_arch_block(arch, block); + scratch_end(scratch); + return result; } //- rjf: thread register writing @@ -1370,7 +1444,7 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma Rng1U64 module_vaddr_range = {0}; for(CTRL_Entity *m = process_entity->first; m != &ctrl_entity_nil; m = m->next) { - if(contains_1u64(m->vaddr_range, rip)) + if(m->kind == CTRL_EntityKind_Module && contains_1u64(m->vaddr_range, rip)) { module = m->handle; module_name = m->string; @@ -1851,7 +1925,15 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls { DBGI_Scope *scope = dbgi_scope_open(); CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, ev->process); - CTRL_Entity *module = process->first; + CTRL_Entity *module = &ctrl_entity_nil; + for(CTRL_Entity *child = process->first; child != &ctrl_entity_nil; child = child->next) + { + if(child->kind == CTRL_EntityKind_Module) + { + module = child; + break; + } + } if(module != &ctrl_entity_nil) { // rjf: determine base address of asan shadow space @@ -2365,7 +2447,15 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) { //- rjf: unpack process & first module info CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, run_ctrls.run_entities[process_idx]); - CTRL_Entity *module = process->first; + CTRL_Entity *module = &ctrl_entity_nil; + for(CTRL_Entity *child = process->first; child != &ctrl_entity_nil; child = child->next) + { + if(child->kind == CTRL_EntityKind_Module) + { + module = child; + break; + } + } U64 module_base_vaddr = module->vaddr_range.min; String8 exe_path = module->string; DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); @@ -2999,7 +3089,7 @@ ctrl_thread__run(CTRL_Msg *msg) CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->process); for(CTRL_Entity *module = process->first; module != &ctrl_entity_nil; module = module->next) { - if(contains_1u64(module->vaddr_range, thread_rip_vaddr)) + if(module->kind == CTRL_EntityKind_Module && contains_1u64(module->vaddr_range, thread_rip_vaddr)) { module_name = module->string; module_base_vaddr = module->vaddr_range.min; @@ -3129,7 +3219,7 @@ ctrl_thread__run(CTRL_Msg *msg) if(bytecode.size != 0) { U64 module_base = module_base_vaddr; - U64 tls_base = 0; // TODO(rjf) + U64 tls_base = ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_MachineID_Local, event->thread); EVAL_Machine machine = {0}; machine.u = &event->process; machine.arch = arch; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 59c72af2..b0b444c2 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -441,7 +441,9 @@ struct CTRL_ThreadRegCacheNode CTRL_ThreadRegCacheNode *prev; CTRL_MachineID machine_id; DMN_Handle thread; - U128 regs_hash; + U64 block_size; + void *block; + U64 reggen_idx; }; typedef struct CTRL_ThreadRegCacheSlot CTRL_ThreadRegCacheSlot; diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index eed84eb6..d944a6d2 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -40,7 +40,7 @@ dmn_w32_entity_from_handle(DMN_Handle handle) { U32 idx = handle.u32[0]; U32 gen = handle.u32[1]; - DMN_W32_Entity *entity = dmn_w32_shared->entities_base; + DMN_W32_Entity *entity = dmn_w32_shared->entities_base + idx; if(entity->gen != gen) { entity = &dmn_w32_entity_nil; @@ -141,7 +141,7 @@ dmn_w32_entity_release(DMN_W32_Entity *entity) Task *last_task = &start_task; for(Task *t = first_task; t != 0; t = t->next) { - for(DMN_W32_Entity *child = entity->first; child != &dmn_w32_entity_nil; child = child->next) + for(DMN_W32_Entity *child = t->e->first; child != &dmn_w32_entity_nil; child = child->next) { Task *t = push_array(scratch.arena, Task, 1); t->e = child; @@ -581,9 +581,10 @@ dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block) //- rjf: unimplemented win32/arch combos // case Architecture_Null: + case Architecture_COUNT: + {}break; case Architecture_arm64: case Architecture_arm32: - case Architecture_COUNT: {NotImplemented;}break; //////////////////////////// @@ -824,9 +825,10 @@ dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block //- rjf: unimplemented win32/arch combos // case Architecture_Null: + case Architecture_COUNT: + {}break; case Architecture_arm64: case Architecture_arm32: - case Architecture_COUNT: {NotImplemented;}break; //////////////////////////// @@ -1148,9 +1150,10 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) { //- rjf: unimplemented win32/arch combos case Architecture_Null: + case Architecture_COUNT: + {}break; case Architecture_arm64: case Architecture_arm32: - case Architecture_COUNT: {NotImplemented;}break; //- rjf: x86/64 @@ -1219,7 +1222,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) //- rjf: scan all threads in this process for(DMN_W32_Entity *thread = process->first; - thread != 0; + thread != &dmn_w32_entity_nil; thread = thread->next) { if(thread->kind != DMN_W32_EntityKind_Thread) {continue;} @@ -1432,6 +1435,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) process->handle = process_handle; process->arch = image_info.arch; thread->handle = thread_handle; + thread->arch = image_info.arch; thread->thread.thread_local_base = tls_base; module->handle = module_handle; module->module.vaddr_range = r1u64(module_base, image_info.size); @@ -2050,9 +2054,10 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) { //- rjf: unimplemented win32/arch combos case Architecture_Null: + case Architecture_COUNT: + {}break; case Architecture_arm64: case Architecture_arm32: - case Architecture_COUNT: {NotImplemented;}break; //- rjf: x86/64 @@ -2353,9 +2358,10 @@ dmn_stack_base_vaddr_from_thread(DMN_Handle handle) switch(thread->arch) { case Architecture_Null: + case Architecture_COUNT: + {}break; case Architecture_arm64: case Architecture_arm32: - case Architecture_COUNT: {NotImplemented;}break; case Architecture_x64: { diff --git a/src/raddbg/raddbg_main.cpp b/src/raddbg/raddbg_main.cpp index 827a4c01..4fc4e296 100644 --- a/src/raddbg/raddbg_main.cpp +++ b/src/raddbg/raddbg_main.cpp @@ -6,7 +6,7 @@ #define BUILD_VERSION_MAJOR 0 #define BUILD_VERSION_MINOR 9 -#define BUILD_VERSION_PATCH 8 +#define BUILD_VERSION_PATCH 9 #define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" #define BUILD_TITLE "The RAD Debugger" #define OS_FEATURE_GRAPHICAL 1 From 8f0e39024fe8c5fff02f18968186d456ae9481ab Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 14 Mar 2024 21:24:12 -0700 Subject: [PATCH 11/33] fix additional demon2 typo --- src/demon2/win32/demon2_core_win32.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index d944a6d2..ba395799 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -2354,7 +2354,6 @@ dmn_stack_base_vaddr_from_thread(DMN_Handle handle) { DMN_W32_Entity *process = thread->parent; U64 tlb = thread->thread.thread_local_base; - U64 result = 0; switch(thread->arch) { case Architecture_Null: From d3cdb97a4e58fb7c280b961946a3bf70b34eca2c Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Sun, 17 Mar 2024 12:16:40 -0700 Subject: [PATCH 12/33] notes --- src/raddbg/raddbg.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index 3d325472..11efef73 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -8,9 +8,11 @@ // using mouse-move events here // [x] CRT asserts - stepping over int 29 should work just like stepping over // an int3 +// [ ] check new callstack caching rules very strongly // [ ] committing needs to happen when navigating focus away for any reason // [ ] better discoverability for view rules - have better help hover tooltip, // info on arguments, and better autocomplete lister +// [ ] freezing thread while running -> soft-halt // // [ ] source view -> floating margin/line-nums // [ ] theme colors -> more explicit about e.g. opaque backgrounds vs. floating From fbf4cce0e750c7d51ac7cd8a4318a375714f7d2b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 13 Mar 2024 15:10:39 -0700 Subject: [PATCH 13/33] make tpi hash parsing gracefully exit on empty input data --- src/pdb/pdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pdb/pdb.c b/src/pdb/pdb.c index f0f2eb2b..c6eed0b4 100644 --- a/src/pdb/pdb.c +++ b/src/pdb/pdb.c @@ -310,7 +310,7 @@ pdb_tpi_hash_from_data(Arena *arena, PDB_Strtbl *strtbl, PDB_TpiParsed *tpi, Str U32 stride = tpi->hash_key_size; U32 bucket_count = tpi->hash_bucket_count; - if (1 <= stride && stride <= 8 && bucket_count > 0){ + if (1 <= stride && stride <= 8 && bucket_count > 0 && data.str != 0){ // allocate buckets PDB_TpiHashBlock **buckets = push_array(arena, PDB_TpiHashBlock*, bucket_count); From 14d3037aec46598bde790d197269e03db09bba1e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 13 Mar 2024 15:25:05 -0700 Subject: [PATCH 14/33] raddbgi_breakpad_from_pdb: add a few missing null checks for edge cases --- src/raddbgi_from_pdb/raddbgi_from_pdb.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.c b/src/raddbgi_from_pdb/raddbgi_from_pdb.c index b285ad3b..19228f85 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb.c +++ b/src/raddbgi_from_pdb/raddbgi_from_pdb.c @@ -1,6 +1,11 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +// TODO(rjf): eliminate redundant null checks, just always allocate +// empty results, and have nulls gracefully fall through +// +// (search for != 0 instances, inserted to prevent prior crashes) + //////////////////////////////// //~ rjf: Basic Helpers @@ -525,6 +530,7 @@ internal TS_TASK_FUNCTION_DEF(p2r_units_convert_task__entry_point) P2R_UnitConvertIn *in = (P2R_UnitConvertIn *)p; P2R_UnitConvertOut *out = push_array(arena, P2R_UnitConvertOut, 1); ProfScope("build units, initial src file map, & collect unit source files") + if(in->comp_units != 0) { U64 units_chunk_cap = in->comp_units->count; P2R_SrcFileMap src_file_map = {0}; @@ -2575,6 +2581,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) // P2R_TPIHashParseIn tpi_hash_in = {0}; TS_Ticket tpi_hash_ticket = {0}; + if(tpi != 0) { tpi_hash_in.strtbl = strtbl; tpi_hash_in.tpi = tpi; @@ -2588,6 +2595,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) // P2R_TPILeafParseIn tpi_leaf_in = {0}; TS_Ticket tpi_leaf_ticket = {0}; + if(tpi != 0) { tpi_leaf_in.leaf_data = pdb_leaf_data_from_tpi(tpi); tpi_leaf_in.itype_first = tpi->itype_first; @@ -2599,6 +2607,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) // P2R_TPIHashParseIn ipi_hash_in = {0}; TS_Ticket ipi_hash_ticket = {0}; + if(ipi != 0) { ipi_hash_in.strtbl = strtbl; ipi_hash_in.tpi = ipi; @@ -2612,6 +2621,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) // P2R_TPILeafParseIn ipi_leaf_in = {0}; TS_Ticket ipi_leaf_ticket = {0}; + if(ipi != 0) { ipi_leaf_in.leaf_data = pdb_leaf_data_from_tpi(ipi); ipi_leaf_in.itype_first = ipi->itype_first; @@ -2681,7 +2691,8 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) //- rjf: calculate EXE's max voff // U64 exe_voff_max = 0; - { + if(coff_sections != 0) + { COFF_SectionHeader *coff_sec_ptr = coff_sections->sections; COFF_SectionHeader *coff_ptr_opl = coff_sec_ptr + coff_section_count; for(;coff_sec_ptr < coff_ptr_opl; coff_sec_ptr += 1) @@ -2743,7 +2754,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) //- rjf: build binary sections list // RDIM_BinarySectionList binary_sections = {0}; - ProfScope("build binary section list") + if(coff_sections != 0) ProfScope("build binary section list") { COFF_SectionHeader *coff_ptr = coff_sections->sections; COFF_SectionHeader *coff_opl = coff_ptr + coff_section_count; @@ -2801,7 +2812,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) P2R_LinkNameMap link_name_map__in_progress = {0}; P2R_LinkNameMapBuildIn link_name_map_build_in = {0}; TS_Ticket link_name_map_ticket = {0}; - ProfScope("kick off link name map build task") + if(sym != 0) ProfScope("kick off link name map build task") { link_name_map__in_progress.buckets_count = symbol_count_prediction; link_name_map__in_progress.buckets = push_array(arena, P2R_LinkNameNode *, link_name_map__in_progress.buckets_count); @@ -3376,8 +3387,8 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) //////////////////////////// //- rjf: kick off all symbol conversion tasks // - U64 global_stream_subdivision_tasks_count = (sym->sym_ranges.count+16383)/16384; - U64 global_stream_syms_per_task = sym->sym_ranges.count/global_stream_subdivision_tasks_count; + U64 global_stream_subdivision_tasks_count = sym ? (sym->sym_ranges.count+16383)/16384 : 0; + U64 global_stream_syms_per_task = sym ? sym->sym_ranges.count/global_stream_subdivision_tasks_count : 0; U64 tasks_count = comp_unit_count + global_stream_subdivision_tasks_count; P2R_SymbolStreamConvertIn *tasks_inputs = push_array(scratch.arena, P2R_SymbolStreamConvertIn, tasks_count); TS_Ticket *tasks_tickets = push_array(scratch.arena, TS_Ticket, tasks_count); From 1269b9358845c86404c00e590d13e36a5b8aac4f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 15 Mar 2024 14:16:30 -0700 Subject: [PATCH 15/33] fix unchecked zero pointers in bake string map joining task, when zero pointers are legal --- src/raddbgi_from_pdb/raddbgi_from_pdb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.c b/src/raddbgi_from_pdb/raddbgi_from_pdb.c index 19228f85..86b9cf99 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb.c +++ b/src/raddbgi_from_pdb/raddbgi_from_pdb.c @@ -3571,11 +3571,13 @@ internal TS_TASK_FUNCTION_DEF(p2r_bake_string_map_join_task__entry_point) { for(U64 slot_idx = in->slot_idx_range.min; slot_idx < in->slot_idx_range.max; slot_idx += 1) { - if(in->dst_map->slots[slot_idx] == 0) + B32 src_slots_good = (in->src_maps[src_map_idx] != 0 && in->src_maps[src_map_idx]->slots != 0); + B32 dst_slot_is_zero = (in->dst_map->slots[slot_idx] == 0); + if(src_slots_good && dst_slot_is_zero) { in->dst_map->slots[slot_idx] = in->src_maps[src_map_idx]->slots[slot_idx]; } - else if(in->src_maps[src_map_idx]->slots[slot_idx] != 0) + else if(src_slots_good && in->src_maps[src_map_idx]->slots[slot_idx] != 0) { rdim_bake_string_chunk_list_concat_in_place(in->dst_map->slots[slot_idx], in->src_maps[src_map_idx]->slots[slot_idx]); } From e0e84c2ee382b9cd0e2f34b48d7f3befdb3c1a8f Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 21 Mar 2024 11:28:47 -0700 Subject: [PATCH 16/33] further progress on integrating new demon layer --- src/ctrl/ctrl_core.c | 62 ++++++++++++++-------------- src/ctrl/ctrl_core.h | 17 ++++---- src/demon2/demon2_core.h | 7 ++++ src/demon2/win32/demon2_core_win32.c | 30 +++++++++++++- src/demon2/win32/demon2_core_win32.h | 5 +++ src/df/core/df_core.c | 35 +++++++++------- src/df/gfx/df_gfx.c | 4 +- src/df/gfx/df_view_rule_hooks.c | 6 +-- src/df/gfx/df_views.c | 2 +- 9 files changed, 105 insertions(+), 63 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index b7eb4b6f..d7b2e0a4 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -933,7 +933,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle { result = range_n->hash; is_good = 1; - is_stale = (range_n->memgen_idx < ctrl_memgen_idx()); + is_stale = (range_n->mem_gen != dmn_mem_gen()); goto read_cache__break_all; } } @@ -1169,6 +1169,20 @@ ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID mac result.data.size = dim_1u64(range); result.byte_bad_flags = byte_bad_flags; result.byte_changed_flags = byte_changed_flags; + if(byte_bad_flags != 0) + { + for(U64 idx = 0; idx < (dim_1u64(range)+63)/64; idx += 1) + { + result.any_byte_bad = result.any_byte_bad || !!result.byte_bad_flags[idx]; + } + } + if(byte_changed_flags != 0) + { + for(U64 idx = 0; idx < (dim_1u64(range)+63)/64; idx += 1) + { + result.any_byte_changed = result.any_byte_changed || !!result.byte_changed_flags[idx]; + } + } hs_scope_close(scope); scratch_end(scratch); @@ -1199,12 +1213,6 @@ ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, ProfBeginFunction(); B32 result = dmn_process_write(process, range, src); - //- rjf: success -> increment memgen - if(result) - { - ins_atomic_u64_inc_eval(&ctrl_state->memgen_idx); - } - //- 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. @@ -1335,10 +1343,10 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, // rjf: copy from node if(node) { - U64 current_reggen_idx = ctrl_reggen_idx(); - if(node->reggen_idx != current_reggen_idx && dmn_thread_read_reg_block(thread, node->block)) + U64 current_reg_gen = dmn_reg_gen(); + if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(thread, node->block)) { - node->reggen_idx = current_reggen_idx; + node->reg_gen = current_reg_gen; } MemoryCopy(result, node->block, reg_block_size); } @@ -1381,7 +1389,6 @@ internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block) { B32 good = dmn_thread_write_reg_block(thread, block); - ins_atomic_u64_inc_eval(&ctrl_state->reggen_idx); return good; } @@ -1421,7 +1428,7 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma { CTRL_ProcessMemorySlice stack_memory_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, machine_id, process_entity->handle, r1u64(stack_top, stack_top+stack_size), endt_us); String8 stack_memory = stack_memory_slice.data; - if(stack_memory.size != 0) + if(stack_memory.size != 0 && !stack_memory_slice.any_byte_bad) { stack_memview_good = 1; stack_memview.data = stack_memory.str; @@ -1517,26 +1524,26 @@ ctrl_halt(void) //////////////////////////////// //~ rjf: Shared Accessor Functions -//- rjf: run indices +//- rjf: run generation counter internal U64 -ctrl_run_idx(void) +ctrl_run_gen(void) { - U64 result = ins_atomic_u64_eval(&ctrl_state->run_idx); + U64 result = dmn_run_gen(); return result; } internal U64 -ctrl_memgen_idx(void) +ctrl_mem_gen(void) { - U64 result = ins_atomic_u64_eval(&ctrl_state->memgen_idx); + U64 result = dmn_mem_gen(); return result; } internal U64 -ctrl_reggen_idx(void) +ctrl_reg_gen(void) { - U64 result = ins_atomic_u64_eval(&ctrl_state->reggen_idx); + U64 result = dmn_reg_gen(); return result; } @@ -2054,13 +2061,6 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls { dmn_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); } - - // rjf: inc generation counters - { - ins_atomic_u64_inc_eval(&ctrl_state->run_idx); - ins_atomic_u64_inc_eval(&ctrl_state->memgen_idx); - ins_atomic_u64_inc_eval(&ctrl_state->reggen_idx); - } } } @@ -3651,7 +3651,7 @@ ctrl_mem_stream_thread__entry_point(void *p) //- rjf: take task B32 got_task = 0; - U64 preexisting_memgen_idx = 0; + U64 preexisting_mem_gen = 0; U128 preexisting_hash = {0}; Rng1U64 vaddr_range_clamped = {0}; OS_MutexScopeW(process_stripe->rw_mutex) @@ -3667,7 +3667,7 @@ ctrl_mem_stream_thread__entry_point(void *p) if(MemoryMatchStruct(&range_n->vaddr_range, &vaddr_range) && range_n->zero_terminated == zero_terminated) { got_task = !ins_atomic_u32_eval_cond_assign(&range_n->is_taken, 1, 0); - preexisting_memgen_idx = range_n->memgen_idx; + preexisting_mem_gen = range_n->mem_gen; preexisting_hash = range_n->hash; vaddr_range_clamped = range_n->vaddr_range_clamped; goto take_task__break_all; @@ -3683,8 +3683,8 @@ ctrl_mem_stream_thread__entry_point(void *p) Arena *range_arena = 0; void *range_base = 0; U64 zero_terminated_size = 0; - U64 memgen_idx = ctrl_memgen_idx(); - if(got_task && memgen_idx != preexisting_memgen_idx) + U64 mem_gen = dmn_mem_gen(); + if(got_task && mem_gen != preexisting_mem_gen) { range_size = dim_1u64(vaddr_range_clamped); U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, os_page_size()); @@ -3746,7 +3746,7 @@ ctrl_mem_stream_thread__entry_point(void *p) if(!u128_match(u128_zero(), hash)) { range_n->hash = hash; - range_n->memgen_idx = memgen_idx; + range_n->mem_gen = mem_gen; } ins_atomic_u32_eval_assign(&range_n->is_taken, 0); goto commit__break_all; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index b0b444c2..b55a3d8a 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -376,7 +376,7 @@ struct CTRL_ProcessMemoryRangeHashNode B32 zero_terminated; Rng1U64 vaddr_range_clamped; U128 hash; - U64 memgen_idx; + U64 mem_gen; U64 last_time_requested_us; B32 is_taken; }; @@ -429,6 +429,8 @@ struct CTRL_ProcessMemorySlice String8 data; U64 *byte_bad_flags; U64 *byte_changed_flags; + B32 any_byte_bad; + B32 any_byte_changed; }; //////////////////////////////// @@ -443,7 +445,7 @@ struct CTRL_ThreadRegCacheNode DMN_Handle thread; U64 block_size; void *block; - U64 reggen_idx; + U64 reg_gen; }; typedef struct CTRL_ThreadRegCacheSlot CTRL_ThreadRegCacheSlot; @@ -483,9 +485,6 @@ struct CTRL_State { Arena *arena; CTRL_WakeupFunctionType *wakeup_hook; - U64 run_idx; - U64 memgen_idx; - U64 reggen_idx; // rjf: name -> register/alias hash tables for eval EVAL_String2NumMap arch_string2reg_tables[Architecture_COUNT]; @@ -672,10 +671,10 @@ internal void ctrl_halt(void); //////////////////////////////// //~ rjf: Shared Accessor Functions -//- rjf: run indices -internal U64 ctrl_run_idx(void); -internal U64 ctrl_memgen_idx(void); -internal U64 ctrl_reggen_idx(void); +//- rjf: generation counters +internal U64 ctrl_run_gen(void); +internal U64 ctrl_mem_gen(void); +internal U64 ctrl_reg_gen(void); //- rjf: name -> register/alias hash tables, for eval internal EVAL_String2NumMap *ctrl_string2reg_from_arch(Architecture arch); diff --git a/src/demon2/demon2_core.h b/src/demon2/demon2_core.h index cc202c5d..dc79b254 100644 --- a/src/demon2/demon2_core.h +++ b/src/demon2/demon2_core.h @@ -165,6 +165,13 @@ internal DMN_Event *dmn_event_list_push(Arena *arena, DMN_EventList *list); internal void dmn_init(void); +//////////////////////////////// +//~ rjf: @dmn_os_hooks Run/Memory/Register Counters + +internal U64 dmn_run_gen(void); +internal U64 dmn_mem_gen(void); +internal U64 dmn_reg_gen(void); + //////////////////////////////// //~ rjf: @dmn_os_hooks Running/Halting (Implemented Per-OS) diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index ba395799..6dc81a1d 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -343,6 +343,7 @@ dmn_w32_process_write(HANDLE process, Rng1U64 range, void *src) ptr += actual_write; cursor += actual_write; } + ins_atomic_u64_inc_eval(&dmn_w32_shared->mem_gen); return result; } @@ -953,6 +954,7 @@ dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block //- rjf: bad context -> abort if(ctx == 0) { + DWORD error = GetLastError(); break; } @@ -1043,6 +1045,7 @@ dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block scratch_end(scratch); }break; } + ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); return result; } @@ -1104,6 +1107,30 @@ dmn_init(void) } } +//////////////////////////////// +//~ rjf: @dmn_os_hooks Run/Memory/Register Counters + +internal U64 +dmn_run_gen(void) +{ + U64 result = ins_atomic_u64_eval(&dmn_w32_shared->run_gen); + return result; +} + +internal U64 +dmn_mem_gen(void) +{ + U64 result = ins_atomic_u64_eval(&dmn_w32_shared->mem_gen); + return result; +} + +internal U64 +dmn_reg_gen(void) +{ + U64 result = ins_atomic_u64_eval(&dmn_w32_shared->reg_gen); + return result; +} + //////////////////////////////// //~ rjf: @dmn_os_hooks Running/Halting (Implemented Per-OS) @@ -1366,6 +1393,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) dmn_w32_shared->resume_pid = evt.dwProcessId; dmn_w32_shared->resume_tid = evt.dwThreadId; } + ins_atomic_u64_inc_eval(&dmn_w32_shared->run_gen); } } @@ -1776,7 +1804,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) { post_trap_rip = regs_rip_from_arch_block(thread->arch, regs_block); regs_arch_block_write_rip(thread->arch, regs_block, instruction_pointer); - dmn_w32_thread_write_reg_block(thread->arch, thread, regs_block); + dmn_w32_thread_write_reg_block(thread->arch, thread->handle, regs_block); } temp_end(temp); } diff --git a/src/demon2/win32/demon2_core_win32.h b/src/demon2/win32/demon2_core_win32.h index 572691c6..d75ee249 100644 --- a/src/demon2/win32/demon2_core_win32.h +++ b/src/demon2/win32/demon2_core_win32.h @@ -194,6 +194,11 @@ struct DMN_W32_Shared Arena *arena; String8List env_strings; + // rjf: run/mem/reg gens + U64 run_gen; + U64 mem_gen; + U64 reg_gen; + // rjf: detaching info Arena *detach_arena; DMN_HandleList detach_processes; diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 496fad24..ccd3e4fa 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -2895,7 +2895,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) String8 machine_code = {0}; if(good_line_info) { - CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, os_now_microseconds()+5000); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, os_now_microseconds()+50000); machine_code = machine_code_slice.data; } @@ -3656,7 +3656,7 @@ internal CTRL_Unwind df_push_unwind_from_thread(Arena *arena, DF_Entity *thread) { DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - CTRL_Unwind unwind = ctrl_unwind_from_thread(arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); + CTRL_Unwind unwind = ctrl_unwind_from_thread(arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, os_now_microseconds()+5000); return unwind; } @@ -6545,8 +6545,8 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) Temp scratch = scratch_begin(&arena, 1); //- rjf: grab next reggen/memgen - U64 new_memgen_idx = ctrl_memgen_idx(); - U64 new_reggen_idx = ctrl_reggen_idx(); + U64 new_mem_gen = ctrl_mem_gen(); + U64 new_reg_gen = ctrl_reg_gen(); //- rjf: consume & process events CTRL_EventList events = ctrl_c2u_pop_events(scratch.arena); @@ -6908,8 +6908,8 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) } //- rjf: refresh unwind cache - if((df_state->unwind_cache_memgen_idx != new_memgen_idx || - df_state->unwind_cache_reggen_idx != new_reggen_idx) && + if((df_state->unwind_cache_memgen_idx != new_mem_gen || + df_state->unwind_cache_reggen_idx != new_reg_gen) && !df_ctrl_targets_running()) ProfScope("per-thread unwind gather") { B32 good = 1; @@ -6935,41 +6935,44 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) break; } } - df_state->unwind_cache_memgen_idx = new_memgen_idx; - df_state->unwind_cache_reggen_idx = new_reggen_idx; + if(good) + { + df_state->unwind_cache_memgen_idx = new_mem_gen; + df_state->unwind_cache_reggen_idx = new_reg_gen; + } } //- rjf: clear tls base cache - if((df_state->tls_base_cache_reggen_idx != new_reggen_idx || - df_state->tls_base_cache_memgen_idx != new_memgen_idx) && + if((df_state->tls_base_cache_reggen_idx != new_reg_gen || + df_state->tls_base_cache_memgen_idx != new_mem_gen) && !df_ctrl_targets_running()) { DF_RunTLSBaseCache *cache = &df_state->tls_base_cache; arena_clear(cache->arena); cache->slots_count = 0; cache->slots = 0; - df_state->tls_base_cache_reggen_idx = new_reggen_idx; - df_state->tls_base_cache_memgen_idx = new_memgen_idx; + df_state->tls_base_cache_reggen_idx = new_reg_gen; + df_state->tls_base_cache_memgen_idx = new_mem_gen; } //- rjf: clear locals cache - if(df_state->locals_cache_reggen_idx != new_reggen_idx && !df_ctrl_targets_running()) + if(df_state->locals_cache_reggen_idx != new_reg_gen && !df_ctrl_targets_running()) { DF_RunLocalsCache *cache = &df_state->locals_cache; arena_clear(cache->arena); cache->table_size = 0; cache->table = 0; - df_state->locals_cache_reggen_idx = new_reggen_idx; + df_state->locals_cache_reggen_idx = new_reg_gen; } //- rjf: clear members cache - if(df_state->member_cache_reggen_idx != new_reggen_idx && !df_ctrl_targets_running()) + if(df_state->member_cache_reggen_idx != new_reg_gen && !df_ctrl_targets_running()) { DF_RunLocalsCache *cache = &df_state->member_cache; arena_clear(cache->arena); cache->table_size = 0; cache->table = 0; - df_state->member_cache_reggen_idx = new_reggen_idx; + df_state->member_cache_reggen_idx = new_reg_gen; } scratch_end(scratch); diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index 3bd9d716..46adcc50 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -3111,8 +3111,8 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D avg_ui_hash_chain_length = chain_length_sum / chain_count; } ui_labelf("Target Hz: %.2f", 1.f/df_dt()); - ui_labelf("Ctrl Run Index: %I64u", ctrl_run_idx()); - ui_labelf("Ctrl Mem Gen Index: %I64u", ctrl_memgen_idx()); + ui_labelf("Ctrl Run Index: %I64u", ctrl_run_gen()); + ui_labelf("Ctrl Mem Gen Index: %I64u", ctrl_mem_gen()); ui_labelf("Window %p", window); ui_set_next_pref_width(ui_children_sum(1)); ui_set_next_pref_height(ui_children_sum(1)); diff --git a/src/df/gfx/df_view_rule_hooks.c b/src/df/gfx/df_view_rule_hooks.c index fd772b5f..5e9d2562 100644 --- a/src/df/gfx/df_view_rule_hooks.c +++ b/src/df/gfx/df_view_rule_hooks.c @@ -565,7 +565,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba) Vec4F32 rgba = {0}; Vec4F32 hsva = {0}; { - if(state->memgen_idx >= ctrl_memgen_idx()) + if(state->memgen_idx >= ctrl_mem_gen()) { hsva = state->hsva; rgba = rgba_from_hsva(hsva); @@ -575,7 +575,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba) DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); rgba = df_view_rule_hooks__rgba_from_eval(value_eval, parse_ctx->type_graph, parse_ctx->rdi, process); state->hsva = hsva = hsva_from_rgba(rgba); - state->memgen_idx = ctrl_memgen_idx(); + state->memgen_idx = ctrl_mem_gen(); } } Vec4F32 initial_hsva = hsva; @@ -624,7 +624,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba) { Vec4F32 rgba = rgba_from_hsva(hsva); df_view_rule_hooks__eval_commit_rgba(eval, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, rgba); - state->memgen_idx = ctrl_memgen_idx(); + state->memgen_idx = ctrl_mem_gen(); } //- rjf: commit possible edited value to state diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index d7fa44bb..ad8e38ff 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -7756,7 +7756,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) U8 *visible_memory = 0; { Rng1U64 chunk_aligned_range_bytes = r1u64(AlignDownPow2(viz_range_bytes.min, KB(4)), AlignPow2(viz_range_bytes.max, KB(4))); - U64 current_memgen_idx = ctrl_memgen_idx(); + U64 current_memgen_idx = ctrl_mem_gen(); B32 range_changed = (chunk_aligned_range_bytes.min != mv->last_viewed_memory_cache_range.min || chunk_aligned_range_bytes.max != mv->last_viewed_memory_cache_range.max); B32 mem_changed = (current_memgen_idx != mv->last_viewed_memory_cache_memgen_idx); From 1466b27385a939ef3be414eea32330264f487c25 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 21 Mar 2024 11:48:48 -0700 Subject: [PATCH 17/33] tweak registers cache lookup rules, to correctly return stale results on failed reads --- project.4coder | 2 +- src/ctrl/ctrl_core.c | 8 ++++++-- src/df/core/df_core.c | 3 +-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/project.4coder b/project.4coder index be4e0ac7..0fb436c2 100644 --- a/project.4coder +++ b/project.4coder @@ -47,7 +47,7 @@ commands = { .rjf_f1 = { - .win = "build raddbg", + .win = "build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index d7b2e0a4..358dd253 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1344,11 +1344,15 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, if(node) { U64 current_reg_gen = dmn_reg_gen(); - if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(thread, node->block)) + if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(thread, result)) { node->reg_gen = current_reg_gen; + MemoryCopy(node->block, result, reg_block_size); + } + else + { + MemoryCopy(result, node->block, reg_block_size); } - MemoryCopy(result, node->block, reg_block_size); } } return result; diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index ccd3e4fa..9572c86d 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -3655,8 +3655,7 @@ df_architecture_from_entity(DF_Entity *entity) internal CTRL_Unwind df_push_unwind_from_thread(Arena *arena, DF_Entity *thread) { - DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - CTRL_Unwind unwind = ctrl_unwind_from_thread(arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, os_now_microseconds()+5000); + CTRL_Unwind unwind = ctrl_unwind_from_thread(arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); return unwind; } From 2c9ff37b2c551323d7f1b2067bf55bcc662a00b0 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 21 Mar 2024 13:53:12 -0700 Subject: [PATCH 18/33] sketch out new unwind cache types --- src/ctrl/ctrl_core.c | 18 ++++++------------ src/ctrl/ctrl_core.h | 29 ++++++++++++++++++++++++++++- src/dasm/dasm.c | 2 +- src/df/core/df_core.c | 1 - 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 358dd253..ce051f0c 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -43,12 +43,6 @@ ctrl_event_cause_from_dmn_event_kind(DMN_EventKind event_kind) return cause; } -internal B32 -ctrl_handle_match(DMN_Handle a, DMN_Handle b) -{ - return MemoryMatchStruct(&a, &b); -} - //////////////////////////////// //~ rjf: Machine/Handle Pair Type Functions @@ -923,7 +917,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { - if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + if(n->machine_id == machine_id && dmn_handle_match(n->process, process)) { U64 range_slot_idx = range_hash%n->range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; @@ -950,7 +944,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle B32 process_node_exists = 0; for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { - if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + if(n->machine_id == machine_id && dmn_handle_match(n->process, process)) { process_node_exists = 1; break; @@ -978,7 +972,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { - if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + if(n->machine_id == machine_id && dmn_handle_match(n->process, process)) { U64 range_slot_idx = range_hash%n->range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; @@ -1018,7 +1012,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { - if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + if(n->machine_id == machine_id && dmn_handle_match(n->process, process)) { U64 range_slot_idx = range_hash%n->range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; @@ -3662,7 +3656,7 @@ ctrl_mem_stream_thread__entry_point(void *p) { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { - if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + if(n->machine_id == machine_id && dmn_handle_match(n->process, process)) { U64 range_slot_idx = range_hash%n->range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; @@ -3739,7 +3733,7 @@ ctrl_mem_stream_thread__entry_point(void *p) { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { - if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + if(n->machine_id == machine_id && dmn_handle_match(n->process, process)) { U64 range_slot_idx = range_hash%n->range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index b55a3d8a..68d8d818 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -471,6 +471,34 @@ struct CTRL_ThreadRegCache CTRL_ThreadRegCacheStripe *stripes; }; +//////////////////////////////// +//~ rjf: Unwind Cache Types + +typedef struct CTRL_UnwindCacheNode CTRL_UnwindCacheNode; +struct CTRL_UnwindCacheNode +{ + CTRL_UnwindCacheNode *next; + CTRL_UnwindCacheNode *prev; + + // rjf: key + CTRL_MachineID machine_id; + DMN_Handle thread; + U64 run_gen; + U64 mem_gen; + U64 reg_gen; + + // rjf: artifacts + CTRL_Unwind unwind; + U64 tls_base_vaddr; +}; + +typedef struct CTRL_UnwindCacheSlot CTRL_UnwindCacheSlot; +struct CTRL_UnwindCacheSlot +{ + CTRL_UnwindCacheNode *first; + CTRL_UnwindCacheNode *last; +}; + //////////////////////////////// //~ rjf: Wakeup Hook Function Types @@ -554,7 +582,6 @@ read_only global CTRL_Entity ctrl_entity_nil = internal U64 ctrl_hash_from_string(String8 string); internal U64 ctrl_hash_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle); internal CTRL_EventCause ctrl_event_cause_from_dmn_event_kind(DMN_EventKind event_kind); -internal B32 ctrl_handle_match(DMN_Handle a, DMN_Handle b); //////////////////////////////// //~ rjf: Machine/Handle Pair Type Functions diff --git a/src/dasm/dasm.c b/src/dasm/dasm.c index 5434c9e9..8eb51f1d 100644 --- a/src/dasm/dasm.c +++ b/src/dasm/dasm.c @@ -195,7 +195,7 @@ dasm_handle_from_ctrl_process_range_arch(CTRL_MachineID machine, DMN_Handle proc for(DASM_Entity *e = slot->first; e != 0; e = e->next) { if(e->machine_id == machine && - ctrl_handle_match(e->process, process) && + dmn_handle_match(e->process, process) && MemoryMatchStruct(&e->vaddr_range, &vaddr_range) && e->arch == arch) { diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 9572c86d..eaebebc1 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -6931,7 +6931,6 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) if(cache_node->unwind.error != 0) { good = 0; - break; } } if(good) From 236214db2548c503b5f6a15e6ca15d4625c22407 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 21 Mar 2024 16:13:01 -0700 Subject: [PATCH 19/33] eliminate unnecessary layers in frontend --- src/ctrl/ctrl_core.h | 28 ------- src/df/core/df_core.c | 178 +++++++++++++++--------------------------- src/df/core/df_core.h | 9 +-- src/df/gfx/df_gfx.c | 2 +- 4 files changed, 66 insertions(+), 151 deletions(-) diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 68d8d818..b9785303 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -471,34 +471,6 @@ struct CTRL_ThreadRegCache CTRL_ThreadRegCacheStripe *stripes; }; -//////////////////////////////// -//~ rjf: Unwind Cache Types - -typedef struct CTRL_UnwindCacheNode CTRL_UnwindCacheNode; -struct CTRL_UnwindCacheNode -{ - CTRL_UnwindCacheNode *next; - CTRL_UnwindCacheNode *prev; - - // rjf: key - CTRL_MachineID machine_id; - DMN_Handle thread; - U64 run_gen; - U64 mem_gen; - U64 reg_gen; - - // rjf: artifacts - CTRL_Unwind unwind; - U64 tls_base_vaddr; -}; - -typedef struct CTRL_UnwindCacheSlot CTRL_UnwindCacheSlot; -struct CTRL_UnwindCacheSlot -{ - CTRL_UnwindCacheNode *first; - CTRL_UnwindCacheNode *last; -}; - //////////////////////////////// //~ rjf: Wakeup Hook Function Types diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index eaebebc1..e008839c 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -2822,7 +2822,7 @@ df_trap_net_from_thread__step_over_inst(Arena *arena, DF_Entity *thread) // rjf: thread => unpacked info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); Architecture arch = df_architecture_from_entity(thread); - U64 ip_vaddr = df_rip_from_thread(thread); + U64 ip_vaddr = ctrl_query_cached_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); // rjf: ip => machine code String8 machine_code = {0}; @@ -2861,7 +2861,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) DF_Entity *module = df_module_from_thread(thread); DF_Entity *binary = df_binary_file_from_module(module); Architecture arch = df_architecture_from_entity(thread); - U64 ip_vaddr = df_rip_from_thread(thread); + U64 ip_vaddr = ctrl_query_cached_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); // rjf: ip => line vaddr range Rng1U64 line_vaddr_rng = {0}; @@ -2986,7 +2986,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) DF_Entity *module = df_module_from_thread(thread); DF_Entity *binary = df_binary_file_from_module(module); Architecture arch = df_architecture_from_entity(thread); - U64 ip_vaddr = df_rip_from_thread(thread); + U64 ip_vaddr = ctrl_query_cached_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); // rjf: ip => line vaddr range Rng1U64 line_vaddr_rng = {0}; @@ -3377,27 +3377,6 @@ df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff) return result; } -internal DF_TextLineDasm2SrcInfoList -df_text_line_dasm2src_info_from_voff(Arena *arena, U64 voff) -{ - Temp scratch = scratch_begin(&arena, 1); - DF_TextLineDasm2SrcInfoList result = {0}; - DF_EntityList binaries = df_push_active_binary_list(scratch.arena); - for(DF_EntityNode *n = binaries.first; n != 0; n = n->next) - { - DF_TextLineDasm2SrcInfo info = df_text_line_dasm2src_info_from_binary_voff(n->entity, voff); - if(!df_entity_is_nil(info.file)) - { - DF_TextLineDasm2SrcInfoNode *dst_n = push_array(arena, DF_TextLineDasm2SrcInfoNode, 1); - dst_n->v = info; - SLLQueuePush(result.first, result.last, dst_n); - result.count += 1; - } - } - scratch_end(scratch); - return result; -} - //- rjf: symbol -> voff lookups internal U64 @@ -3652,42 +3631,6 @@ df_architecture_from_entity(DF_Entity *entity) return entity->arch; } -internal CTRL_Unwind -df_push_unwind_from_thread(Arena *arena, DF_Entity *thread) -{ - CTRL_Unwind unwind = ctrl_unwind_from_thread(arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); - return unwind; -} - -internal U64 -df_rip_from_thread(DF_Entity *thread) -{ - U64 result = ctrl_query_cached_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); - return result; -} - -internal U64 -df_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count) -{ - Temp scratch = scratch_begin(0, 0); - U64 result = df_rip_from_thread(thread); - if(unwind_count != 0) - { - CTRL_Unwind unwind = df_push_unwind_from_thread(scratch.arena, thread); - U64 unwind_idx = 0; - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) - { - if(unwind_count == unwind_idx) - { - result = frame->rip; - break; - } - } - } - scratch_end(scratch); - return result; -} - internal EVAL_String2NumMap * df_push_locals_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff) { @@ -3724,16 +3667,19 @@ df_set_thread_rip(DF_Entity *thread, U64 vaddr) if(result) { DF_RunUnwindCache *unwind_cache = &df_state->unwind_cache; - DF_Handle thread_handle = df_handle_from_entity(thread); - U64 hash = df_hash_from_string(str8_struct(&thread_handle)); - U64 slot_idx = hash % unwind_cache->table_size; - DF_RunUnwindCacheSlot *slot = &unwind_cache->table[slot_idx]; - for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) + if(unwind_cache->slots_count != 0) { - if(df_handle_match(n->thread, thread_handle) && n->unwind.first != 0) + DF_Handle thread_handle = df_handle_from_entity(thread); + U64 hash = df_hash_from_string(str8_struct(&thread_handle)); + U64 slot_idx = hash % unwind_cache->slots_count; + DF_RunUnwindCacheSlot *slot = &unwind_cache->slots[slot_idx]; + for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) { - n->unwind.first->rip = vaddr; - break; + if(df_handle_match(n->thread, thread_handle) && n->unwind.first != 0) + { + n->unwind.first->rip = vaddr; + break; + } } } } @@ -6189,25 +6135,41 @@ df_push_active_target_list(Arena *arena) internal CTRL_Unwind df_query_cached_unwind_from_thread(DF_Entity *thread) { - ProfBeginFunction(); - CTRL_Unwind result = {0}; DF_RunUnwindCache *cache = &df_state->unwind_cache; - if(cache->table_size != 0) + if(cache->slots_count == 0) { - DF_Handle handle = df_handle_from_entity(thread); - U64 hash = df_hash_from_string(str8_struct(&handle)); - U64 slot_idx = hash % cache->table_size; - DF_RunUnwindCacheSlot *slot = &cache->table[slot_idx]; - for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) + cache->slots_count = 1024; + cache->slots = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->slots_count); + } + DF_Handle handle = df_handle_from_entity(thread); + U64 hash = df_hash_from_string(str8_struct(&handle)); + U64 slot_idx = hash % cache->slots_count; + DF_RunUnwindCacheSlot *slot = &cache->slots[slot_idx]; + DF_RunUnwindCacheNode *node = 0; + for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) + { + if(df_handle_match(n->thread, handle)) { - if(df_handle_match(n->thread, handle)) - { - result = n->unwind; - break; - } + node = n; + break; } } - ProfEnd(); + CTRL_Unwind result = {0}; + if(node == 0) + { + result = ctrl_unwind_from_thread(cache->arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); + if(!result.error) + { + node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); + SLLQueuePush_N(slot->first, slot->last, node, hash_next); + node->thread = handle; + node->unwind = result; + } + } + else + { + result = node->unwind; + } return result; } @@ -6227,14 +6189,21 @@ internal U64 df_query_cached_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count) { U64 result = 0; - CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); - U64 unwind_idx = 0; - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) + if(unwind_count == 0) { - if(unwind_idx == unwind_count) + result = ctrl_query_cached_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); + } + else + { + CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); + U64 unwind_idx = 0; + for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) { - result = frame->rip; - break; + if(unwind_idx == unwind_count) + { + result = frame->rip; + break; + } } } return result; @@ -6589,7 +6558,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) // rjf: thread hit user breakpoint -> increment breakpoint hit count if(event->cause == CTRL_EventCause_UserBreakpoint) { - U64 stop_thread_vaddr = df_rip_from_thread(stop_thread); + U64 stop_thread_vaddr = ctrl_query_cached_rip_from_thread(stop_thread->ctrl_machine_id, stop_thread->ctrl_handle); DF_Entity *process = df_entity_ancestor_from_kind(stop_thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, stop_thread_vaddr); DF_Entity *binary = df_binary_file_from_module(module); @@ -6906,38 +6875,17 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) } } - //- rjf: refresh unwind cache + //- rjf: clear unwind cache if((df_state->unwind_cache_memgen_idx != new_mem_gen || df_state->unwind_cache_reggen_idx != new_reg_gen) && !df_ctrl_targets_running()) ProfScope("per-thread unwind gather") { - B32 good = 1; - DF_EntityList all_threads = df_query_cached_entity_list_with_kind(DF_EntityKind_Thread); DF_RunUnwindCache *cache = &df_state->unwind_cache; arena_clear(cache->arena); - cache->table_size = 1024; - cache->table = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->table_size); - for(DF_EntityNode *n = all_threads.first; n != 0; n = n->next) - { - DF_Entity *thread = n->entity; - DF_Handle thread_handle = df_handle_from_entity(thread); - U64 hash = df_hash_from_string(str8_struct(&thread_handle)); - U64 slot_idx = hash % cache->table_size; - DF_RunUnwindCacheSlot *slot = &cache->table[slot_idx]; - DF_RunUnwindCacheNode *cache_node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); - cache_node->thread = thread_handle; - cache_node->unwind = df_push_unwind_from_thread(cache->arena, thread); - SLLQueuePush_NZ(0, slot->first, slot->last, cache_node, hash_next); - if(cache_node->unwind.error != 0) - { - good = 0; - } - } - if(good) - { - df_state->unwind_cache_memgen_idx = new_mem_gen; - df_state->unwind_cache_reggen_idx = new_reg_gen; - } + cache->slots_count = 0; + cache->slots = 0; + df_state->unwind_cache_memgen_idx = new_mem_gen; + df_state->unwind_cache_reggen_idx = new_reg_gen; } //- rjf: clear tls base cache diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index 1192d43d..1a8f907a 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -940,7 +940,6 @@ struct DF_RunUnwindCacheNode DF_RunUnwindCacheNode *hash_next; DF_Handle thread; CTRL_Unwind unwind; - U64 tls_base_vaddr; }; typedef struct DF_RunUnwindCacheSlot DF_RunUnwindCacheSlot; @@ -954,8 +953,8 @@ typedef struct DF_RunUnwindCache DF_RunUnwindCache; struct DF_RunUnwindCache { Arena *arena; - U64 table_size; - DF_RunUnwindCacheSlot *table; + U64 slots_count; + DF_RunUnwindCacheSlot *slots; }; //- rjf: per-run tls-base-vaddr cache @@ -1534,7 +1533,6 @@ internal DF_TextLineSrc2DasmInfoListArray df_text_line_src2dasm_info_list_array_ //- rjf: voff -> src lookups internal DF_TextLineDasm2SrcInfo df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff); -internal DF_TextLineDasm2SrcInfoList df_text_line_dasm2src_info_from_voff(Arena *arena, U64 voff); //- rjf: symbol -> voff lookups internal U64 df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name); @@ -1548,9 +1546,6 @@ internal DF_Entity *df_module_from_process_vaddr(DF_Entity *process, U64 vaddr); internal DF_Entity *df_module_from_thread(DF_Entity *thread); internal U64 df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr); internal Architecture df_architecture_from_entity(DF_Entity *entity); -internal CTRL_Unwind df_push_unwind_from_thread(Arena *arena, DF_Entity *thread); -internal U64 df_rip_from_thread(DF_Entity *thread); -internal U64 df_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count); internal EVAL_String2NumMap *df_push_locals_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff); internal EVAL_String2NumMap *df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff); internal B32 df_set_thread_rip(DF_Entity *thread, U64 vaddr); diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index 46adcc50..47813529 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -2131,7 +2131,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D if(thread->kind == DF_EntityKind_Thread) { // rjf: grab rip - U64 rip_vaddr = (unwind_count == 0 ? df_rip_from_thread(thread) : df_query_cached_rip_from_thread_unwind(thread, unwind_count)); + U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); // rjf: extract thread/rip info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); From 54677e05ece9f388ef214a3b3b9f809cbf299e69 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 21 Mar 2024 16:21:17 -0700 Subject: [PATCH 20/33] fix incorrect metagen pointer comparisons --- src/metagen/metagen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/metagen/metagen.c b/src/metagen/metagen.c index 838328c5..5da28126 100644 --- a/src/metagen/metagen.c +++ b/src/metagen/metagen.c @@ -372,7 +372,7 @@ mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, MD_Node *first, MD_Node //- rjf: consume prefix operators MG_StrExpr *leafmost_op = &mg_str_expr_nil; - for(;it < opl && !md_node_is_nil(it);) + for(;it != opl && !md_node_is_nil(it);) { MG_StrExprOp found_op = MG_StrExprOp_Null; for(MG_StrExprOp op = (MG_StrExprOp)(MG_StrExprOp_Null+1); @@ -431,7 +431,7 @@ mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, MD_Node *first, MD_Node } //- rjf: parse binary operator extensions at this precedence level - for(;it < opl && !md_node_is_nil(it);) + for(;it != opl && !md_node_is_nil(it);) { // rjf: find binary op kind of `it` MG_StrExprOp found_op = MG_StrExprOp_Null; From a694a77eba10490389f2be835c9ffd991ad6c300 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 21 Mar 2024 16:49:34 -0700 Subject: [PATCH 21/33] fix halting, unattached running, and caching generations in demon2 --- src/demon2/win32/demon2_core_win32.c | 34 +++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index 6dc81a1d..aa37f3f3 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -1144,6 +1144,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) // typedef enum DMN_W32_EventGenPath { + DMN_W32_EventGenPath_NotAttached, DMN_W32_EventGenPath_Run, DMN_W32_EventGenPath_DetachProcesses, } @@ -1153,12 +1154,41 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) { event_gen_path = DMN_W32_EventGenPath_DetachProcesses; } + else + { + B32 any_processes_live = dmn_w32_shared->new_process_pending; + if(!any_processes_live) + { + for(DMN_W32_Entity *process = dmn_w32_shared->entities_base->first; process != &dmn_w32_entity_nil; process = process->next) + { + if(process->kind == DMN_W32_EntityKind_Process) + { + any_processes_live = 1; + break; + } + } + } + if(!any_processes_live) + { + event_gen_path = DMN_W32_EventGenPath_NotAttached; + } + } ////////////////////////////// //- rjf: produce debug events // switch(event_gen_path) { + //////////////////////////// + //- rjf: produce not-attached error events + // + case DMN_W32_EventGenPath_NotAttached: + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_Error; + e->error_kind = DMN_ErrorKind_NotAttached; + }break; + //////////////////////////// //- rjf: produce debug events from regular running // @@ -1394,6 +1424,8 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) dmn_w32_shared->resume_tid = evt.dwThreadId; } ins_atomic_u64_inc_eval(&dmn_w32_shared->run_gen); + ins_atomic_u64_inc_eval(&dmn_w32_shared->mem_gen); + ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); } } @@ -2166,7 +2198,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) internal void dmn_halt(U64 code, U64 user_data) { - if(!dmn_handle_match(dmn_handle_zero(), dmn_w32_shared->halter_process)) + if(dmn_handle_match(dmn_handle_zero(), dmn_w32_shared->halter_process)) { DMN_W32_Entity *process = &dmn_w32_entity_nil; for(DMN_W32_Entity *entity = dmn_w32_shared->entities_base->first; From 982f2b6babee7cbf3a519171e5842f2737051d31 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 22 Mar 2024 10:33:20 -0700 Subject: [PATCH 22/33] extend process memory cache queries with output channel for staleness detection - in some cases this is crucial, in other cases you don't care & want to passively accept stale redsults --- src/ctrl/ctrl_core.c | 81 ++++++++++++++++++--------------- src/ctrl/ctrl_core.h | 3 +- src/df/core/df_core.c | 2 +- src/df/gfx/df_view_rule_hooks.c | 8 ++-- 4 files changed, 52 insertions(+), 42 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index ce051f0c..eaa97541 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -896,7 +896,7 @@ ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Hand } internal U128 -ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated, U64 endt_us) +ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated, B32 *out_is_stale, U64 endt_us) { U128 result = {0}; U64 size = dim_1u64(range); @@ -1033,6 +1033,10 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle //- rjf: out of time? -> exit if(os_now_microseconds() >= endt_us) { + if(is_good && is_stale && out_is_stale) + { + out_is_stale[0] = 1; + } break; } @@ -1072,8 +1076,10 @@ ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID mac { U64 page_base_vaddr = page_range.min + page_idx*page_size; U128 page_key = ctrl_hash_store_key_from_process_vaddr_range(machine_id, process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0); - U128 page_hash = ctrl_stored_hash_from_process_vaddr_range(machine_id, process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, endt_us); + B32 page_is_stale = 0; + U128 page_hash = ctrl_stored_hash_from_process_vaddr_range(machine_id, process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, &page_is_stale, endt_us); U128 page_last_hash = hs_hash_from_key(page_key, 1); + result.stale = (result.stale || page_is_stale); page_hashes[page_idx] = page_hash; page_last_hashes[page_idx] = page_last_hash; } @@ -1399,49 +1405,51 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); DBGI_Scope *scope = dbgi_scope_open(); + CTRL_Unwind unwind = {0}; + unwind.error = 1; + + //- rjf: unpack args CTRL_Entity *thread_entity = ctrl_entity_from_machine_id_handle(store, machine_id, thread); CTRL_Entity *process_entity = thread_entity->parent; Architecture arch = thread_entity->arch; U64 arch_reg_block_size = regs_block_size_from_architecture(arch); - CTRL_Unwind unwind = {0}; - unwind.error = 1; - switch(arch) + + //- rjf: grab initial register block + void *regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, machine_id, thread); + + //- rjf: grab initial memory view + B32 stack_memview_good = 0; + UNW_MemView stack_memview = {0}; + { + U64 stack_base_unrounded = dmn_stack_base_vaddr_from_thread(thread); + U64 stack_top_unrounded = regs_rsp_from_arch_block(arch, regs_block); + U64 stack_base = AlignPow2(stack_base_unrounded, KB(4)); + U64 stack_top = AlignDownPow2(stack_top_unrounded, KB(4)); + U64 stack_size = stack_base - stack_top; + if(stack_base >= stack_top) + { + CTRL_ProcessMemorySlice stack_memory_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, machine_id, process_entity->handle, r1u64(stack_top, stack_top+stack_size), endt_us); + String8 stack_memory = stack_memory_slice.data; + if(stack_memory.size != 0 && !stack_memory_slice.any_byte_bad && !stack_memory_slice.stale) + { + stack_memview_good = 1; + stack_memview.data = stack_memory.str; + stack_memview.addr_first = stack_top; + stack_memview.addr_opl = stack_base; + } + } + } + + //- rjf: loop & unwind + UNW_MemView memview = stack_memview; + if(stack_memview_good) switch(arch) { default:{}break; case Architecture_x64: { - // rjf: grab initial register block - void *regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, machine_id, thread); - - // rjf: grab initial memory view - B32 stack_memview_good = 0; - UNW_MemView stack_memview = {0}; + unwind.error = 0; + for(;;) { - U64 stack_base_unrounded = dmn_stack_base_vaddr_from_thread(thread); - U64 stack_top_unrounded = regs_rsp_from_arch_block(arch, regs_block); - U64 stack_base = AlignPow2(stack_base_unrounded, KB(4)); - U64 stack_top = AlignDownPow2(stack_top_unrounded, KB(4)); - U64 stack_size = stack_base - stack_top; - if(stack_base >= stack_top) - { - CTRL_ProcessMemorySlice stack_memory_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, machine_id, process_entity->handle, r1u64(stack_top, stack_top+stack_size), endt_us); - String8 stack_memory = stack_memory_slice.data; - if(stack_memory.size != 0 && !stack_memory_slice.any_byte_bad) - { - stack_memview_good = 1; - stack_memview.data = stack_memory.str; - stack_memview.addr_first = stack_top; - stack_memview.addr_opl = stack_base; - } - } - } - - // rjf: loop & unwind - UNW_MemView memview = stack_memview; - if(stack_memview_good) for(;;) - { - unwind.error = 0; - // rjf: regs -> rip*module U64 rip = regs_rip_from_arch_block(arch, regs_block); DMN_Handle module = {0}; @@ -1504,6 +1512,7 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma } }break; } + dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index b9785303..916f3db4 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -429,6 +429,7 @@ struct CTRL_ProcessMemorySlice String8 data; U64 *byte_bad_flags; U64 *byte_changed_flags; + B32 stale; B32 any_byte_bad; B32 any_byte_changed; }; @@ -636,7 +637,7 @@ internal void ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook); //- rjf: process memory cache interaction internal U128 ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated); -internal U128 ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated, U64 endt_us); +internal U128 ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated, B32 *out_is_stale, U64 endt_us); //- rjf: process memory cache reading helpers internal CTRL_ProcessMemorySlice ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, U64 endt_us); diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index e008839c..2a526015 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -6867,7 +6867,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) } } - // rjf: collect s top info + // rjf: collect stop info arena_clear(df_state->ctrl_stop_arena); MemoryCopyStruct(&df_state->ctrl_last_stop_event, event); df_state->ctrl_last_stop_event.string = push_str8_copy(df_state->ctrl_stop_arena, df_state->ctrl_last_stop_event.string); diff --git a/src/df/gfx/df_view_rule_hooks.c b/src/df/gfx/df_view_rule_hooks.c index 5e9d2562..da3d8842 100644 --- a/src/df/gfx/df_view_rule_hooks.c +++ b/src/df/gfx/df_view_rule_hooks.c @@ -700,7 +700,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(text) } //- rjf: address range -> hash - U128 hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 1, 0); + U128 hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 1, 0, 0); //- rjf: hash -> data String8 data = hs_data_from_hash(hs_scope, hash); @@ -891,7 +891,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap) } //- rjf: address range -> hash - U128 hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 0, 0); + U128 hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 0, 0, 0); //- rjf: hash & topology -> texture TEX_Topology topology = tex_topology_make(v2s32((S32)topology_info.width, (S32)topology_info.height), topology_info.fmt); @@ -1151,8 +1151,8 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(geo) } //- rjf: address range -> hash - U128 index_buffer_hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, index_buffer_vaddr_range, 0, 0); - U128 vertex_buffer_hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vertex_buffer_vaddr_range, 0, 0); + U128 index_buffer_hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, index_buffer_vaddr_range, 0, 0, 0); + U128 vertex_buffer_hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vertex_buffer_vaddr_range, 0, 0, 0); //- rjf: get gpu buffers R_Handle index_buffer = geo_buffer_from_key_hash(geo_scope, index_buffer_key, index_buffer_hash); From 3994adae9235e57704a96e50aa93f427d3370860 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 22 Mar 2024 11:56:28 -0700 Subject: [PATCH 23/33] double-buffer frontend unwind cache --- src/ctrl/ctrl_core.c | 8 ++--- src/df/core/df_core.c | 84 +++++++++++++++++++++++-------------------- src/df/core/df_core.h | 3 +- src/df/gfx/df_views.c | 5 ++- 4 files changed, 56 insertions(+), 44 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index eaa97541..65d42656 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -819,7 +819,7 @@ ctrl_init(void) } ctrl_state->process_memory_cache.slots_count = 256; ctrl_state->process_memory_cache.slots = push_array(arena, CTRL_ProcessMemoryCacheSlot, ctrl_state->process_memory_cache.slots_count); - ctrl_state->process_memory_cache.stripes_count = 8; + ctrl_state->process_memory_cache.stripes_count = os_logical_core_count(); ctrl_state->process_memory_cache.stripes = push_array(arena, CTRL_ProcessMemoryCacheStripe, ctrl_state->process_memory_cache.stripes_count); for(U64 idx = 0; idx < ctrl_state->process_memory_cache.stripes_count; idx += 1) { @@ -828,14 +828,13 @@ ctrl_init(void) } ctrl_state->thread_reg_cache.slots_count = 1024; ctrl_state->thread_reg_cache.slots = push_array(arena, CTRL_ThreadRegCacheSlot, ctrl_state->thread_reg_cache.slots_count); - ctrl_state->thread_reg_cache.stripes_count = 8; + ctrl_state->thread_reg_cache.stripes_count = os_logical_core_count(); ctrl_state->thread_reg_cache.stripes = push_array(arena, CTRL_ThreadRegCacheStripe, ctrl_state->thread_reg_cache.stripes_count); for(U64 idx = 0; idx < ctrl_state->thread_reg_cache.stripes_count; idx += 1) { - ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc(); + ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); } - ctrl_state->ctrl_thread_entity_store = ctrl_entity_store_alloc(); ctrl_state->u2c_ring_size = KB(64); ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); ctrl_state->u2c_ring_mutex = os_mutex_alloc(); @@ -844,6 +843,7 @@ ctrl_init(void) ctrl_state->c2u_ring_base = push_array_no_zero(arena, U8, ctrl_state->c2u_ring_size); ctrl_state->c2u_ring_mutex = os_mutex_alloc(); ctrl_state->c2u_ring_cv = os_condition_variable_alloc(); + ctrl_state->ctrl_thread_entity_store = ctrl_entity_store_alloc(); ctrl_state->dmn_event_arena = arena_alloc(); ctrl_state->user_entry_point_arena = arena_alloc(); for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1)) diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 2a526015..75c2525d 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -3558,7 +3558,7 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 //- rjf: read module's TLS index U64 tls_index = 0; { - CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, os_now_microseconds()+5000); + CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, 0); if(tls_index_slice.data.size >= addr_size) { tls_index = *(U64 *)tls_index_slice.data.str; @@ -3571,13 +3571,13 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 U64 thread_info_addr = root_vaddr; U64 tls_addr_off = tls_index*addr_size; U64 tls_addr_array = 0; - CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(thread_info_addr, thread_info_addr+addr_size), os_now_microseconds()+5000); + CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(thread_info_addr, thread_info_addr+addr_size), 0); String8 tls_addr_array_data = tls_addr_array_slice.data; if(tls_addr_array_data.size >= 8) { MemoryCopy(&tls_addr_array, tls_addr_array_data.str, sizeof(U64)); } - CTRL_ProcessMemorySlice result_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), os_now_microseconds()+5000); + CTRL_ProcessMemorySlice result_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), 0); String8 result_data = result_slice.data; if(result_data.size >= 8) { @@ -3666,7 +3666,7 @@ df_set_thread_rip(DF_Entity *thread, U64 vaddr) // rjf: early mutation of unwind cache for immediate frontend effect if(result) { - DF_RunUnwindCache *unwind_cache = &df_state->unwind_cache; + DF_RunUnwindCache *unwind_cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)]; if(unwind_cache->slots_count != 0) { DF_Handle thread_handle = df_handle_from_entity(thread); @@ -6135,40 +6135,49 @@ df_push_active_target_list(Arena *arena) internal CTRL_Unwind df_query_cached_unwind_from_thread(DF_Entity *thread) { - DF_RunUnwindCache *cache = &df_state->unwind_cache; - if(cache->slots_count == 0) - { - cache->slots_count = 1024; - cache->slots = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->slots_count); - } + CTRL_Unwind result = {0}; DF_Handle handle = df_handle_from_entity(thread); U64 hash = df_hash_from_string(str8_struct(&handle)); - U64 slot_idx = hash % cache->slots_count; - DF_RunUnwindCacheSlot *slot = &cache->slots[slot_idx]; - DF_RunUnwindCacheNode *node = 0; - for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) + for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->unwind_caches); cache_idx += 1) { - if(df_handle_match(n->thread, handle)) + DF_RunUnwindCache *cache = &df_state->unwind_caches[(df_state->unwind_cache_gen+cache_idx)%ArrayCount(df_state->unwind_caches)]; + if(cache_idx == 0 && cache->slots_count == 0) + { + cache->slots_count = 1024; + cache->slots = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->slots_count); + } + else if(cache->slots_count == 0) { - node = n; break; } - } - CTRL_Unwind result = {0}; - if(node == 0) - { - result = ctrl_unwind_from_thread(cache->arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); - if(!result.error) + U64 slot_idx = hash%cache->slots_count; + DF_RunUnwindCacheSlot *slot = &cache->slots[slot_idx]; + DF_RunUnwindCacheNode *node = 0; + for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) { - node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); - SLLQueuePush_N(slot->first, slot->last, node, hash_next); - node->thread = handle; - node->unwind = result; + if(df_handle_match(n->thread, handle)) + { + node = n; + break; + } + } + if(node != 0) + { + result = node->unwind; + break; + } + else + { + result = ctrl_unwind_from_thread(cache->arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); + if(!result.error) + { + node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); + SLLQueuePush_N(slot->first, slot->last, node, hash_next); + node->thread = handle; + node->unwind = result; + break; + } } - } - else - { - result = node->unwind; } return result; } @@ -6176,12 +6185,7 @@ df_query_cached_unwind_from_thread(DF_Entity *thread) internal U64 df_query_cached_rip_from_thread(DF_Entity *thread) { - U64 result = 0; - CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); - if(unwind.first != 0) - { - result = unwind.first->rip; - } + U64 result = df_query_cached_rip_from_thread_unwind(thread, 0); return result; } @@ -6405,7 +6409,10 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist) } // rjf: set up per-run caches - df_state->unwind_cache.arena = arena_alloc(); + for(U64 idx = 0; idx < ArrayCount(df_state->unwind_caches); idx += 1) + { + df_state->unwind_caches[idx].arena = arena_alloc(); + } df_state->tls_base_cache.arena = arena_alloc(); df_state->locals_cache.arena = arena_alloc(); df_state->member_cache.arena = arena_alloc(); @@ -6880,7 +6887,8 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) df_state->unwind_cache_reggen_idx != new_reg_gen) && !df_ctrl_targets_running()) ProfScope("per-thread unwind gather") { - DF_RunUnwindCache *cache = &df_state->unwind_cache; + df_state->unwind_cache_gen += 1; + DF_RunUnwindCache *cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)]; arena_clear(cache->arena); cache->slots_count = 0; cache->slots = 0; diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index 1a8f907a..76c97340 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -1135,7 +1135,8 @@ struct DF_State // rjf: per-run caches U64 unwind_cache_reggen_idx; U64 unwind_cache_memgen_idx; - DF_RunUnwindCache unwind_cache; + DF_RunUnwindCache unwind_caches[2]; + U64 unwind_cache_gen; U64 tls_base_cache_reggen_idx; U64 tls_base_cache_memgen_idx; DF_RunTLSBaseCache tls_base_cache; diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index ad8e38ff..d411c08c 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -6235,6 +6235,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) } // rjf: find live threads mapping to this disassembly + ProfScope("find live threads mapping to this disassembly") { DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx.thread); DF_EntityList threads = df_query_cached_entity_list_with_kind(DF_EntityKind_Thread); @@ -6243,7 +6244,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) DF_Entity *thread = thread_n->entity; U64 unwind_count = (thread == selected_thread) ? ctrl_ctx.unwind_count : 0; U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); - if(contains_1u64(disasm_vaddr_rng, rip_vaddr)) + if(contains_1u64(disasm_vaddr_rng, rip_vaddr)) ProfScope("in-range rip scan") { U64 rip_off = rip_vaddr - disasm_vaddr_rng.min; S64 line_num = dasm_inst_array_idx_from_off__linear_scan(&insts, rip_off)+1; @@ -6257,6 +6258,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) } // rjf: find breakpoints mapping to this disassembly + ProfScope("find breakpoints mapping to this disassembly") { DF_EntityList bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); for(DF_EntityNode *n = bps.first; n != 0; n = n->next) @@ -6277,6 +6279,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) } // rjf: find watch pins mapping to this disassembly + ProfScope("find watch pins mapping to this disassembly") { DF_EntityList pins = df_query_cached_entity_list_with_kind(DF_EntityKind_WatchPin); for(DF_EntityNode *n = pins.first; n != 0; n = n->next) From e9129975e3b6fa3b7a6c982778e8dda6c47c3b1e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 22 Mar 2024 13:32:22 -0700 Subject: [PATCH 24/33] double buffer locals cache & tls base cache; introduce synchronizing mechanism for run vs. non-run ctrl thread states, to only attempt demon reads/queries during non-running times --- src/ctrl/ctrl_core.c | 47 ++++++++++++++++++++---------- src/ctrl/ctrl_core.h | 4 +++ src/demon2/demon2_core.c | 35 +++++++++++++++++++++++ src/demon2/demon2_core.h | 6 ++++ src/df/core/df_core.c | 62 +++++++++++++++++++++++++++++----------- src/df/core/df_core.h | 6 ++-- src/df/gfx/df_views.c | 2 +- 7 files changed, 127 insertions(+), 35 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 65d42656..49f6be97 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -800,6 +800,7 @@ ctrl_init(void) Arena *arena = arena_alloc(); ctrl_state = push_array(arena, CTRL_State, 1); ctrl_state->arena = arena; + ctrl_state->ctrl_run_mutex = os_mutex_alloc(); for(Architecture arch = (Architecture)0; arch < Architecture_COUNT; arch = (Architecture)(arch+1)) { String8 *reg_names = regs_reg_code_string_table_from_architecture(arch); @@ -1344,12 +1345,17 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, if(node) { U64 current_reg_gen = dmn_reg_gen(); - if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(thread, result)) + B32 need_stale = 1; + if(node->reg_gen != current_reg_gen) { - node->reg_gen = current_reg_gen; - MemoryCopy(node->block, result, reg_block_size); + OS_MutexScope(ctrl_state->ctrl_run_mutex) if(ctrl_state->ctrl_run_state == 0 && dmn_thread_read_reg_block(thread, result)) + { + need_stale = 0; + node->reg_gen = current_reg_gen; + MemoryCopy(node->block, result, reg_block_size); + } } - else + if(need_stale) { MemoryCopy(result, node->block, reg_block_size); } @@ -1719,6 +1725,12 @@ ctrl_thread__entry_point(void *p) //- rjf: get next messages CTRL_MsgList msgs = ctrl_u2c_pop_msgs(scratch.arena); + //- rjf: begin run state + OS_MutexScope(ctrl_state->ctrl_run_mutex) + { + ctrl_state->ctrl_run_state = 1; + } + //- rjf: process messages { B32 done = 0; @@ -1753,6 +1765,12 @@ ctrl_thread__entry_point(void *p) } } } + + //- rjf: end run state + OS_MutexScope(ctrl_state->ctrl_run_mutex) + { + ctrl_state->ctrl_run_state = 0; + } } scratch_end(scratch); @@ -2879,7 +2897,7 @@ ctrl_thread__run(CTRL_Msg *msg) if(process->kind != CTRL_EntityKind_Process) { continue; } for(CTRL_Entity *thread = process->first; thread != &ctrl_entity_nil; thread = thread->next) { - U64 rip = ctrl_query_cached_rip_from_thread(thread->machine_id, thread->handle); + U64 rip = dmn_rip_from_thread(thread->handle); // rjf: determine if thread is frozen B32 thread_is_frozen = !msg->freeze_state_is_frozen; @@ -2998,7 +3016,7 @@ ctrl_thread__run(CTRL_Msg *msg) // if(stop_event == 0) { - U64 sp_check_value = ctrl_query_cached_rsp_from_thread(CTRL_MachineID_Local, target_thread); + U64 sp_check_value = dmn_rsp_from_thread(target_thread); B32 spoof_mode = 0; CTRL_Spoof spoof = {0}; for(;;) @@ -3085,9 +3103,7 @@ ctrl_thread__run(CTRL_Msg *msg) // CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->thread); Architecture arch = thread->arch; - U64 reg_size = regs_block_size_from_architecture(arch); - void *thread_regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, CTRL_MachineID_Local, event->thread); - U64 thread_rip_vaddr = regs_rip_from_arch_block(arch, thread_regs_block); + U64 thread_rip_vaddr = dmn_rsp_from_thread(event->thread); DMN_Handle module = {0}; String8 module_name = {0}; U64 module_base_vaddr = 0; @@ -3226,15 +3242,16 @@ ctrl_thread__run(CTRL_Msg *msg) if(bytecode.size != 0) { U64 module_base = module_base_vaddr; - U64 tls_base = ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_MachineID_Local, event->thread); + U64 tls_base = dmn_tls_root_vaddr_from_thread(event->thread); EVAL_Machine machine = {0}; machine.u = &event->process; machine.arch = arch; machine.memory_read = ctrl_eval_memory_read; - machine.reg_data = thread_regs_block; - machine.reg_size = reg_size; + machine.reg_size = regs_block_size_from_architecture(arch); + machine.reg_data = push_array(scratch.arena, U8, machine.reg_size); machine.module_base = &module_base; machine.tls_base = &tls_base; + dmn_thread_read_reg_block(event->thread, machine.reg_data); eval = eval_interpret(&machine, bytecode); } if(eval.code == EVAL_ResultCode_Good && eval.value.u64 == 0) @@ -3335,7 +3352,7 @@ ctrl_thread__run(CTRL_Msg *msg) B32 stack_pointer_matches = 0; if(use_trap_net_logic) { - U64 sp = ctrl_query_cached_rsp_from_thread(CTRL_MachineID_Local, target_thread); + U64 sp = dmn_rsp_from_thread(target_thread); stack_pointer_matches = (sp == sp_check_value); } @@ -3383,7 +3400,7 @@ ctrl_thread__run(CTRL_Msg *msg) { // rjf: setup spoof mode begin_spoof_mode = 1; - U64 spoof_sp = ctrl_query_cached_rsp_from_thread(CTRL_MachineID_Local, target_thread); + U64 spoof_sp = dmn_rsp_from_thread(target_thread); spoof_mode = 1; spoof.process = target_process; spoof.thread = target_thread; @@ -3401,7 +3418,7 @@ ctrl_thread__run(CTRL_Msg *msg) if(stack_pointer_matches) { save_stack_pointer = 1; - sp_check_value = ctrl_query_cached_rsp_from_thread(CTRL_MachineID_Local, target_thread); + sp_check_value = dmn_rsp_from_thread(target_thread); } } } diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 916f3db4..f74f2a83 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -491,6 +491,10 @@ struct CTRL_State EVAL_String2NumMap arch_string2reg_tables[Architecture_COUNT]; EVAL_String2NumMap arch_string2alias_tables[Architecture_COUNT]; + // rjf: access locking mechanism + OS_Handle ctrl_run_mutex; + B32 ctrl_run_state; + // rjf: caches CTRL_ProcessMemoryCache process_memory_cache; CTRL_ThreadRegCache thread_reg_cache; diff --git a/src/demon2/demon2_core.c b/src/demon2/demon2_core.c index ee3b7ed6..86c1c3c6 100644 --- a/src/demon2/demon2_core.c +++ b/src/demon2/demon2_core.c @@ -116,3 +116,38 @@ 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); + { + Architecture arch = dmn_arch_from_thread(thread); + U64 reg_block_size = regs_block_size_from_architecture(arch); + void *reg_block = push_array(scratch.arena, U8, reg_block_size); + dmn_thread_read_reg_block(thread, reg_block); + result = regs_rip_from_arch_block(arch, 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); + { + Architecture arch = dmn_arch_from_thread(thread); + U64 reg_block_size = regs_block_size_from_architecture(arch); + void *reg_block = push_array(scratch.arena, U8, reg_block_size); + dmn_thread_read_reg_block(thread, reg_block); + result = regs_rsp_from_arch_block(arch, reg_block); + } + scratch_end(scratch); + return result; +} diff --git a/src/demon2/demon2_core.h b/src/demon2/demon2_core.h index dc79b254..2ae5efc8 100644 --- a/src/demon2/demon2_core.h +++ b/src/demon2/demon2_core.h @@ -160,6 +160,12 @@ 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: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS) diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 75c2525d..1d7c255c 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -6217,13 +6217,18 @@ internal U64 df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr) { U64 result = 0; + for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->tls_base_caches); cache_idx += 1) { - DF_RunTLSBaseCache *cache = &df_state->tls_base_cache; - if(cache->slots_count == 0) + DF_RunTLSBaseCache *cache = &df_state->tls_base_caches[(df_state->tls_base_cache_gen+cache_idx)%ArrayCount(df_state->tls_base_caches)]; + if(cache_idx == 0 && cache->slots_count == 0) { cache->slots_count = 256; cache->slots = push_array(cache->arena, DF_RunTLSBaseCacheSlot, cache->slots_count); } + else if(cache->slots_count == 0) + { + break; + } DF_Handle handle = df_handle_from_entity(process); U64 hash = df_hash_from_seed_string(df_hash_from_string(str8_struct(&handle)), str8_struct(&rip_vaddr)); U64 slot_idx = hash%cache->slots_count; @@ -6239,14 +6244,22 @@ df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 roo } if(node == 0) { - node = push_array(cache->arena, DF_RunTLSBaseCacheNode, 1); - SLLQueuePush_N(slot->first, slot->last, node, hash_next); - node->process = handle; - node->root_vaddr = root_vaddr; - node->rip_vaddr = rip_vaddr; - node->tls_base_vaddr = df_tls_base_vaddr_from_process_root_rip(process, root_vaddr, rip_vaddr); + U64 tls_base_vaddr = df_tls_base_vaddr_from_process_root_rip(process, root_vaddr, rip_vaddr); + if(tls_base_vaddr != 0) + { + node = push_array(cache->arena, DF_RunTLSBaseCacheNode, 1); + SLLQueuePush_N(slot->first, slot->last, node, hash_next); + node->process = handle; + node->root_vaddr = root_vaddr; + node->rip_vaddr = rip_vaddr; + node->tls_base_vaddr = tls_base_vaddr; + } + } + if(node != 0 && node->tls_base_vaddr != 0) + { + result = node->tls_base_vaddr; + break; } - result = node->tls_base_vaddr; } return result; } @@ -6256,13 +6269,18 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) { ProfBeginFunction(); EVAL_String2NumMap *map = &eval_string2num_map_nil; + for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->locals_caches); cache_idx += 1) { - DF_RunLocalsCache *cache = &df_state->locals_cache; - if(cache->table_size == 0) + DF_RunLocalsCache *cache = &df_state->locals_caches[(df_state->locals_cache_gen+cache_idx)%ArrayCount(df_state->locals_caches)]; + if(cache_idx == 0 && cache->table_size == 0) { cache->table_size = 256; cache->table = push_array(cache->arena, DF_RunLocalsCacheSlot, cache->table_size); } + else if(cache->table_size == 0) + { + break; + } DF_Handle handle = df_handle_from_entity(binary); U64 hash = df_hash_from_string(str8_struct(&handle)); U64 slot_idx = hash % cache->table_size; @@ -6290,9 +6308,10 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) } dbgi_scope_close(scope); } - if(node != 0) + if(node != 0 && node->locals_map->slots_count != 0) { map = node->locals_map; + break; } } ProfEnd(); @@ -6413,8 +6432,14 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist) { df_state->unwind_caches[idx].arena = arena_alloc(); } - df_state->tls_base_cache.arena = arena_alloc(); - df_state->locals_cache.arena = arena_alloc(); + for(U64 idx = 0; idx < ArrayCount(df_state->tls_base_caches); idx += 1) + { + df_state->tls_base_caches[idx].arena = arena_alloc(); + } + for(U64 idx = 0; idx < ArrayCount(df_state->locals_caches); idx += 1) + { + df_state->locals_caches[idx].arena = arena_alloc(); + } df_state->member_cache.arena = arena_alloc(); // rjf: set up eval view cache @@ -6901,7 +6926,8 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) df_state->tls_base_cache_memgen_idx != new_mem_gen) && !df_ctrl_targets_running()) { - DF_RunTLSBaseCache *cache = &df_state->tls_base_cache; + df_state->tls_base_cache_gen += 1; + DF_RunTLSBaseCache *cache = &df_state->tls_base_caches[df_state->tls_base_cache_gen%ArrayCount(df_state->tls_base_caches)]; arena_clear(cache->arena); cache->slots_count = 0; cache->slots = 0; @@ -6910,9 +6936,11 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) } //- rjf: clear locals cache - if(df_state->locals_cache_reggen_idx != new_reg_gen && !df_ctrl_targets_running()) + if(df_state->locals_cache_reggen_idx != new_reg_gen && + !df_ctrl_targets_running()) { - DF_RunLocalsCache *cache = &df_state->locals_cache; + df_state->locals_cache_gen += 1; + DF_RunLocalsCache *cache = &df_state->locals_caches[df_state->locals_cache_gen%ArrayCount(df_state->locals_caches)]; arena_clear(cache->arena); cache->table_size = 0; cache->table = 0; diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index 76c97340..4df932cd 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -1139,9 +1139,11 @@ struct DF_State U64 unwind_cache_gen; U64 tls_base_cache_reggen_idx; U64 tls_base_cache_memgen_idx; - DF_RunTLSBaseCache tls_base_cache; + DF_RunTLSBaseCache tls_base_caches[2]; + U64 tls_base_cache_gen; U64 locals_cache_reggen_idx; - DF_RunLocalsCache locals_cache; + DF_RunLocalsCache locals_caches[2]; + U64 locals_cache_gen; U64 member_cache_reggen_idx; DF_RunLocalsCache member_cache; diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index d411c08c..a6f1eacb 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -6244,7 +6244,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) DF_Entity *thread = thread_n->entity; U64 unwind_count = (thread == selected_thread) ? ctrl_ctx.unwind_count : 0; U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); - if(contains_1u64(disasm_vaddr_rng, rip_vaddr)) ProfScope("in-range rip scan") + if(contains_1u64(disasm_vaddr_rng, rip_vaddr)) { U64 rip_off = rip_vaddr - disasm_vaddr_rng.min; S64 line_num = dasm_inst_array_idx_from_off__linear_scan(&insts, rip_off)+1; From 9de678ec2280f45687baa9d7eb9862f350da1562 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 22 Mar 2024 13:51:26 -0700 Subject: [PATCH 25/33] disable debug heap by default; get unwindg path off caching layers & use demon reads directly --- src/ctrl/ctrl_core.c | 12 +++++++----- src/demon2/win32/demon2_core_win32.c | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 49f6be97..d982e31f 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1421,7 +1421,8 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma U64 arch_reg_block_size = regs_block_size_from_architecture(arch); //- rjf: grab initial register block - void *regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, machine_id, thread); + void *regs_block = push_array(scratch.arena, U8, arch_reg_block_size); + B32 regs_block_good = dmn_thread_read_reg_block(thread, regs_block); //- rjf: grab initial memory view B32 stack_memview_good = 0; @@ -1434,9 +1435,10 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma U64 stack_size = stack_base - stack_top; if(stack_base >= stack_top) { - CTRL_ProcessMemorySlice stack_memory_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, machine_id, process_entity->handle, r1u64(stack_top, stack_top+stack_size), endt_us); - String8 stack_memory = stack_memory_slice.data; - if(stack_memory.size != 0 && !stack_memory_slice.any_byte_bad && !stack_memory_slice.stale) + U8 *stack_memory_base = push_array(scratch.arena, U8, stack_size); + U64 actual_stack_bytes_read = dmn_process_read(process_entity->handle, r1u64(stack_top, stack_top+stack_size), stack_memory_base); + String8 stack_memory = str8(stack_memory_base, actual_stack_bytes_read); + if(stack_memory.size >= stack_size) { stack_memview_good = 1; stack_memview.data = stack_memory.str; @@ -1448,7 +1450,7 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma //- rjf: loop & unwind UNW_MemView memview = stack_memview; - if(stack_memview_good) switch(arch) + if(regs_block_good && stack_memview_good) switch(arch) { default:{}break; case Architecture_x64: diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index aa37f3f3..6035162b 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -2254,6 +2254,7 @@ dmn_launch_process(OS_LaunchOptions *options) if(options->inherit_env != 0) { MemoryZeroStruct(&all_opts); + str8_list_push(scratch.arena, &all_opts, str8_lit("_NO_DEBUG_HEAP=1")); for(String8Node *n = options->env.first; n != 0; n = n->next) { str8_list_push(scratch.arena, &all_opts, n->string); From 14ac7141e763c0163e91e82fe95173edb1327334 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 22 Mar 2024 13:53:14 -0700 Subject: [PATCH 26/33] double buffer member cache --- src/df/core/df_core.c | 20 +++++++++++++++----- src/df/core/df_core.h | 3 ++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 1d7c255c..9321cd09 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -6323,13 +6323,18 @@ df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff) { ProfBeginFunction(); EVAL_String2NumMap *map = &eval_string2num_map_nil; + for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->member_caches); cache_idx += 1) { - DF_RunLocalsCache *cache = &df_state->member_cache; - if(cache->table_size == 0) + DF_RunLocalsCache *cache = &df_state->member_caches[(df_state->member_cache_gen+cache_idx)%ArrayCount(df_state->member_caches)]; + if(cache_idx == 0 && cache->table_size == 0) { cache->table_size = 256; cache->table = push_array(cache->arena, DF_RunLocalsCacheSlot, cache->table_size); } + else if(cache->table_size == 0) + { + break; + } DF_Handle handle = df_handle_from_entity(binary); U64 hash = df_hash_from_string(str8_struct(&handle)); U64 slot_idx = hash % cache->table_size; @@ -6357,9 +6362,10 @@ df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff) } dbgi_scope_close(scope); } - if(node != 0) + if(node != 0 && node->locals_map->slots_count != 0) { map = node->locals_map; + break; } } ProfEnd(); @@ -6440,7 +6446,10 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist) { df_state->locals_caches[idx].arena = arena_alloc(); } - df_state->member_cache.arena = arena_alloc(); + for(U64 idx = 0; idx < ArrayCount(df_state->member_caches); idx += 1) + { + df_state->member_caches[idx].arena = arena_alloc(); + } // rjf: set up eval view cache df_state->eval_view_cache.slots_count = 4096; @@ -6950,7 +6959,8 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) //- rjf: clear members cache if(df_state->member_cache_reggen_idx != new_reg_gen && !df_ctrl_targets_running()) { - DF_RunLocalsCache *cache = &df_state->member_cache; + df_state->member_cache_gen += 1; + DF_RunLocalsCache *cache = &df_state->member_caches[df_state->member_cache_gen%ArrayCount(df_state->member_caches)]; arena_clear(cache->arena); cache->table_size = 0; cache->table = 0; diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index 4df932cd..7ba02bf4 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -1145,7 +1145,8 @@ struct DF_State DF_RunLocalsCache locals_caches[2]; U64 locals_cache_gen; U64 member_cache_reggen_idx; - DF_RunLocalsCache member_cache; + DF_RunLocalsCache member_caches[2]; + U64 member_cache_gen; // rjf: eval view cache DF_EvalViewCache eval_view_cache; From ca01e66ea20255a8e7b8d51750c8df05d063a537 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 22 Mar 2024 14:12:40 -0700 Subject: [PATCH 27/33] plug in tls root vaddr path --- src/ctrl/ctrl_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index d982e31f..936d4d03 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1367,8 +1367,8 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, internal U64 ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) { - // TODO(rjf) - return 0; + U64 result = dmn_tls_root_vaddr_from_thread(thread); + return result; } internal U64 From 07bbf1b43cf9768d37139c50561c8b5530b6ca50 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 22 Mar 2024 15:15:33 -0700 Subject: [PATCH 28/33] organize demon2 by thread api --- src/demon2/demon2_core.h | 32 ++- src/demon2/win32/demon2_core_win32.c | 312 +++++++++++++-------------- 2 files changed, 169 insertions(+), 175 deletions(-) diff --git a/src/demon2/demon2_core.h b/src/demon2/demon2_core.h index 2ae5efc8..adb84bd4 100644 --- a/src/demon2/demon2_core.h +++ b/src/demon2/demon2_core.h @@ -172,28 +172,26 @@ internal U64 dmn_rsp_from_thread(DMN_Handle thread); internal void dmn_init(void); //////////////////////////////// -//~ rjf: @dmn_os_hooks Run/Memory/Register Counters - -internal U64 dmn_run_gen(void); -internal U64 dmn_mem_gen(void); -internal U64 dmn_reg_gen(void); - -//////////////////////////////// -//~ rjf: @dmn_os_hooks Running/Halting (Implemented Per-OS) - -internal DMN_EventList dmn_run(Arena *arena, DMN_RunCtrls *ctrls); -internal void dmn_halt(U64 code, U64 user_data); - -//////////////////////////////// -//~ rjf: @dmn_os_hooks Process Launching/Attaching/Killing/Detaching (Implemented Per-OS) +//~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS) internal U32 dmn_launch_process(OS_LaunchOptions *options); internal B32 dmn_attach_process(U32 pid); internal B32 dmn_kill_process(DMN_Handle process, U32 exit_code); internal B32 dmn_detach_process(DMN_Handle process); +internal DMN_EventList dmn_run(Arena *arena, DMN_RunCtrls *ctrls); //////////////////////////////// -//~ rjf: @dmn_os_hooks Process/Thread Reads/Writes (Implemented Per-OS) +//~ rjf: @dmn_os_hooks Halting (Implemented Per-OS) + +internal void dmn_halt(U64 code, U64 user_data); + +//////////////////////////////// +//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS) + +//- rjf: run/memory/register counters +internal U64 dmn_run_gen(void); +internal U64 dmn_mem_gen(void); +internal U64 dmn_reg_gen(void); //- rjf: processes internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst); @@ -208,9 +206,7 @@ internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle); internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block); internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block); -//////////////////////////////// -//~ rjf: @dmn_os_hooks System Process Listing (Implemented Per-OS) - +//- rjf: system process listing 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); diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index 6035162b..ddf921c9 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -1108,31 +1108,158 @@ dmn_init(void) } //////////////////////////////// -//~ rjf: @dmn_os_hooks Run/Memory/Register Counters +//~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS) -internal U64 -dmn_run_gen(void) +internal U32 +dmn_launch_process(OS_LaunchOptions *options) { - U64 result = ins_atomic_u64_eval(&dmn_w32_shared->run_gen); + Temp scratch = scratch_begin(0, 0); + U32 result = 0; + + //- rjf: produce exe / arguments string + String8 cmd = {0}; + if(options->cmd_line.first != 0) + { + String8List args = {0}; + String8 exe_path = options->cmd_line.first->string; + str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path); + for(String8Node *n = options->cmd_line.first->next; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &args, n->string); + } + StringJoin join_params = {0}; + join_params.sep = str8_lit(" "); + cmd = str8_list_join(scratch.arena, &args, &join_params); + } + + //- rjf: produce environment strings + String8 env = {0}; + { + String8List all_opts = options->env; + if(options->inherit_env != 0) + { + MemoryZeroStruct(&all_opts); + str8_list_push(scratch.arena, &all_opts, str8_lit("_NO_DEBUG_HEAP=1")); + for(String8Node *n = options->env.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + for(String8Node *n = dmn_w32_shared->env_strings.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + } + StringJoin join_params2 = {0}; + join_params2.sep = str8_lit("\0"); + join_params2.post = str8_lit("\0"); + env = str8_list_join(scratch.arena, &all_opts, &join_params2); + } + + //- rjf: produce utf-16 strings + String16 cmd16 = str16_from_8(scratch.arena, cmd); + String16 dir16 = str16_from_8(scratch.arena, options->path); + String16 env16 = str16_from_8(scratch.arena, env); + + //- rjf: launch + DWORD access_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS; + STARTUPINFOW startup_info = {sizeof(startup_info)}; + PROCESS_INFORMATION process_info = {0}; + AllocConsole(); + if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info)) + { + // check if we are 32-bit app, and just close it immediately + BOOL is_wow = 0; + IsWow64Process(process_info.hProcess, &is_wow); + if(is_wow) + { + MessageBox(0, "Sorry, The RAD Debugger only debugs 64-bit applications currently.", "Process error", MB_OK|MB_ICONSTOP); + DebugActiveProcessStop(process_info.dwProcessId); + TerminateProcess(process_info.hProcess,0xffffffff); + } + else + { + result = process_info.dwProcessId; + dmn_w32_shared->new_process_pending = 1; + } + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + } + else + { + MessageBox(0, "Error starting process.", "Process error", MB_OK|MB_ICONSTOP); + } + FreeConsole(); + + //- rjf: eliminate all handles which have stuck around from the AllocConsole + { + SetStdHandle(STD_INPUT_HANDLE, 0); + SetStdHandle(STD_OUTPUT_HANDLE, 0); + SetStdHandle(STD_ERROR_HANDLE, 0); + } + + scratch_end(scratch); return result; } -internal U64 -dmn_mem_gen(void) +internal B32 +dmn_attach_process(U32 pid) { - U64 result = ins_atomic_u64_eval(&dmn_w32_shared->mem_gen); + B32 result = 0; + if(DebugActiveProcess((DWORD)pid)) + { + result = 1; + dmn_w32_shared->new_process_pending = 1; + } return result; } -internal U64 -dmn_reg_gen(void) +internal B32 +dmn_kill_process(DMN_Handle process, U32 exit_code) { - U64 result = ins_atomic_u64_eval(&dmn_w32_shared->reg_gen); + B32 result = 0; + DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); + if(TerminateProcess(process_entity->handle, exit_code)) + { + result = 1; + } return result; } -//////////////////////////////// -//~ rjf: @dmn_os_hooks Running/Halting (Implemented Per-OS) +internal B32 +dmn_detach_process(DMN_Handle process) +{ + B32 result = 0; + DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); + + // rjf: resume threads + for(DMN_W32_Entity *child = process_entity->first; + child != &dmn_w32_entity_nil; + child = child->next) + { + if(child->kind == DMN_W32_EntityKind_Thread) + { + DWORD resume_result = ResumeThread(child->handle); + (void)resume_result; + } + } + + // rjf: detach + { + DWORD pid = (DWORD)process_entity->id; + if(DebugActiveProcessStop(pid)) + { + result = 1; + } + } + + // rjf: push into list of processes to generate events for later + if(result != 0) + { + dmn_handle_list_push(dmn_w32_shared->detach_arena, &dmn_w32_shared->detach_processes, process); + } + + return result; +} internal DMN_EventList dmn_run(Arena *arena, DMN_RunCtrls *ctrls) @@ -2195,6 +2322,9 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) return events; } +//////////////////////////////// +//~ rjf: @dmn_os_hooks Halting (Implemented Per-OS) + internal void dmn_halt(U64 code, U64 user_data) { @@ -2223,162 +2353,31 @@ dmn_halt(U64 code, U64 user_data) } //////////////////////////////// -//~ rjf: @dmn_os_hooks Process Launching/Attaching/Killing/Detaching (Implemented Per-OS) +//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS) -internal U32 -dmn_launch_process(OS_LaunchOptions *options) +//- rjf: run/memory/register counters + +internal U64 +dmn_run_gen(void) { - Temp scratch = scratch_begin(0, 0); - U32 result = 0; - - //- rjf: produce exe / arguments string - String8 cmd = {0}; - if(options->cmd_line.first != 0) - { - String8List args = {0}; - String8 exe_path = options->cmd_line.first->string; - str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path); - for(String8Node *n = options->cmd_line.first->next; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &args, n->string); - } - StringJoin join_params = {0}; - join_params.sep = str8_lit(" "); - cmd = str8_list_join(scratch.arena, &args, &join_params); - } - - //- rjf: produce environment strings - String8 env = {0}; - { - String8List all_opts = options->env; - if(options->inherit_env != 0) - { - MemoryZeroStruct(&all_opts); - str8_list_push(scratch.arena, &all_opts, str8_lit("_NO_DEBUG_HEAP=1")); - for(String8Node *n = options->env.first; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &all_opts, n->string); - } - for(String8Node *n = dmn_w32_shared->env_strings.first; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &all_opts, n->string); - } - } - StringJoin join_params2 = {0}; - join_params2.sep = str8_lit("\0"); - join_params2.post = str8_lit("\0"); - env = str8_list_join(scratch.arena, &all_opts, &join_params2); - } - - //- rjf: produce utf-16 strings - String16 cmd16 = str16_from_8(scratch.arena, cmd); - String16 dir16 = str16_from_8(scratch.arena, options->path); - String16 env16 = str16_from_8(scratch.arena, env); - - //- rjf: launch - DWORD access_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS; - STARTUPINFOW startup_info = {sizeof(startup_info)}; - PROCESS_INFORMATION process_info = {0}; - AllocConsole(); - if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info)) - { - // check if we are 32-bit app, and just close it immediately - BOOL is_wow = 0; - IsWow64Process(process_info.hProcess, &is_wow); - if(is_wow) - { - MessageBox(0, "Sorry, The RAD Debugger only debugs 64-bit applications currently.", "Process error", MB_OK|MB_ICONSTOP); - DebugActiveProcessStop(process_info.dwProcessId); - TerminateProcess(process_info.hProcess,0xffffffff); - } - else - { - result = process_info.dwProcessId; - dmn_w32_shared->new_process_pending = 1; - } - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); - } - else - { - MessageBox(0, "Error starting process.", "Process error", MB_OK|MB_ICONSTOP); - } - FreeConsole(); - - //- rjf: eliminate all handles which have stuck around from the AllocConsole - { - SetStdHandle(STD_INPUT_HANDLE, 0); - SetStdHandle(STD_OUTPUT_HANDLE, 0); - SetStdHandle(STD_ERROR_HANDLE, 0); - } - - scratch_end(scratch); + U64 result = ins_atomic_u64_eval(&dmn_w32_shared->run_gen); return result; } -internal B32 -dmn_attach_process(U32 pid) +internal U64 +dmn_mem_gen(void) { - B32 result = 0; - if(DebugActiveProcess((DWORD)pid)) - { - result = 1; - dmn_w32_shared->new_process_pending = 1; - } + U64 result = ins_atomic_u64_eval(&dmn_w32_shared->mem_gen); return result; } -internal B32 -dmn_kill_process(DMN_Handle process, U32 exit_code) +internal U64 +dmn_reg_gen(void) { - B32 result = 0; - DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); - if(TerminateProcess(process_entity->handle, exit_code)) - { - result = 1; - } + U64 result = ins_atomic_u64_eval(&dmn_w32_shared->reg_gen); return result; } -internal B32 -dmn_detach_process(DMN_Handle process) -{ - B32 result = 0; - DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); - - // rjf: resume threads - for(DMN_W32_Entity *child = process_entity->first; - child != &dmn_w32_entity_nil; - child = child->next) - { - if(child->kind == DMN_W32_EntityKind_Thread) - { - DWORD resume_result = ResumeThread(child->handle); - (void)resume_result; - } - } - - // rjf: detach - { - DWORD pid = (DWORD)process_entity->id; - if(DebugActiveProcessStop(pid)) - { - result = 1; - } - } - - // rjf: push into list of processes to generate events for later - if(result != 0) - { - dmn_handle_list_push(dmn_w32_shared->detach_arena, &dmn_w32_shared->detach_processes, process); - } - - return result; -} - -//////////////////////////////// -//~ rjf: @dmn_os_hooks Process/Thread Reads/Writes (Implemented Per-OS) - //- rjf: processes internal U64 @@ -2466,8 +2465,7 @@ dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block) return result; } -//////////////////////////////// -//~ rjf: @dmn_os_hooks System Process Listing (Implemented Per-OS) +//- rjf: system process listing internal void dmn_process_iter_begin(DMN_ProcessIter *iter) From c636e1ad2ee7300810b1fa209a75367ad076c928 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 22 Mar 2024 15:53:04 -0700 Subject: [PATCH 29/33] extend demon2 with explicit separation between blocking ctrl mechanisms & passive access/introspection/writing mechanisms; extend demon2 api with access mechanism --- src/ctrl/ctrl_core.c | 69 +++--- src/ctrl/ctrl_core.h | 20 +- src/demon2/demon2_core.h | 30 ++- src/demon2/win32/demon2_core_win32.c | 347 ++++++++++++++++----------- src/demon2/win32/demon2_core_win32.h | 5 + src/raddbg/raddbg.h | 17 +- 6 files changed, 293 insertions(+), 195 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 936d4d03..1987676d 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1717,6 +1717,7 @@ ctrl_thread__entry_point(void *p) { ThreadNameF("[ctrl] thread"); ProfBeginFunction(); + DMN_CtrlCtx *ctrl_ctx = dmn_ctrl_begin(); //- rjf: loop Temp scratch = scratch_begin(0, 0); @@ -1746,13 +1747,13 @@ ctrl_thread__entry_point(void *p) case CTRL_MsgKind_COUNT:{}break; //- rjf: target operations - case CTRL_MsgKind_LaunchAndHandshake:{ctrl_thread__launch_and_handshake(msg);}break; - case CTRL_MsgKind_LaunchAndInit: {ctrl_thread__launch_and_init (msg);}break; - case CTRL_MsgKind_Attach: {ctrl_thread__attach (msg);}break; - case CTRL_MsgKind_Kill: {ctrl_thread__kill (msg);}break; - case CTRL_MsgKind_Detach: {ctrl_thread__detach (msg);}break; - case CTRL_MsgKind_Run: {ctrl_thread__run (msg); done = 1;}break; - case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (msg); done = 1;}break; + case CTRL_MsgKind_LaunchAndHandshake:{ctrl_thread__launch_and_handshake(ctrl_ctx, msg);}break; + case CTRL_MsgKind_LaunchAndInit: {ctrl_thread__launch_and_init (ctrl_ctx, msg);}break; + case CTRL_MsgKind_Attach: {ctrl_thread__attach (ctrl_ctx, msg);}break; + case CTRL_MsgKind_Kill: {ctrl_thread__kill (ctrl_ctx, msg);}break; + case CTRL_MsgKind_Detach: {ctrl_thread__detach (ctrl_ctx, msg);}break; + case CTRL_MsgKind_Run: {ctrl_thread__run (ctrl_ctx, msg); done = 1;}break; + case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (ctrl_ctx, msg); done = 1;}break; //- rjf: configuration case CTRL_MsgKind_SetUserEntryPoints: @@ -1899,7 +1900,7 @@ ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID //- rjf: attached process running/event gathering internal DMN_Event * -ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof) +ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof) { ProfBeginFunction(); DMN_Event *event = push_array(arena, DMN_Event, 1); @@ -2042,8 +2043,8 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls } } - //- rjf: no event -> dmn_run for a new one - if(got_event == 0) ProfScope("no event -> dmn_run for a new one") + //- rjf: no event -> dmn_ctrl_run for a new one + if(got_event == 0) ProfScope("no event -> dmn_ctrl_run for a new one") { // rjf: prep spoof B32 do_spoof = (spoof != 0 && dmn_handle_match(run_ctrls->single_step_thread, dmn_handle_zero())); @@ -2065,7 +2066,7 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls // rjf: run for new events ProfScope("run for new events") { - DMN_EventList events = dmn_run(scratch.arena, run_ctrls); + DMN_EventList events = dmn_ctrl_run(scratch.arena, ctrl_ctx, run_ctrls); for(DMN_EventNode *src_n = events.first; src_n != 0; src_n = src_n->next) { DMN_EventNode *dst_n = ctrl_state->free_dmn_event_node; @@ -2255,7 +2256,7 @@ ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size) //- rjf: msg kind implementations internal void -ctrl_thread__launch_and_handshake(CTRL_Msg *msg) +ctrl_thread__launch_and_handshake(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -2269,7 +2270,7 @@ ctrl_thread__launch_and_handshake(CTRL_Msg *msg) opts.env = msg->env_string_list; opts.inherit_env = msg->env_inherit; } - U32 id = dmn_launch_process(&opts); + U32 id = dmn_ctrl_launch(ctrl_ctx, &opts); //- rjf: record start { @@ -2296,7 +2297,7 @@ ctrl_thread__launch_and_handshake(CTRL_Msg *msg) // rjf: run until handshake-signifying events for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; @@ -2363,7 +2364,7 @@ ctrl_thread__launch_and_handshake(CTRL_Msg *msg) } internal void -ctrl_thread__launch_and_init(CTRL_Msg *msg) +ctrl_thread__launch_and_init(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -2378,7 +2379,7 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) opts.env = msg->env_string_list; opts.inherit_env = msg->env_inherit; } - U32 id = dmn_launch_process(&opts); + U32 id = dmn_ctrl_launch(ctrl_ctx, &opts); ////////////////////////////// //- rjf: record start @@ -2402,7 +2403,7 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) run_ctrls.run_entities_are_processes = 1; for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; @@ -2686,14 +2687,14 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) } internal void -ctrl_thread__attach(CTRL_Msg *msg) +ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); DBGI_Scope *scope = dbgi_scope_open(); //- rjf: attach - B32 attach_successful = dmn_attach_process(msg->entity_id); + B32 attach_successful = dmn_ctrl_attach(ctrl_ctx, msg->entity_id); //- rjf: run to handshake if(attach_successful) @@ -2704,7 +2705,7 @@ ctrl_thread__attach(CTRL_Msg *msg) run_ctrls.run_entities_are_processes = 1; for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; @@ -2739,7 +2740,7 @@ ctrl_thread__attach(CTRL_Msg *msg) } internal void -ctrl_thread__kill(CTRL_Msg *msg) +ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -2748,7 +2749,7 @@ ctrl_thread__kill(CTRL_Msg *msg) U32 exit_code = msg->exit_code; //- rjf: send kill - B32 kill_worked = dmn_kill_process(process, exit_code); + B32 kill_worked = dmn_ctrl_kill(ctrl_ctx, process, exit_code); //- rjf: wait for process to be dead if(kill_worked) @@ -2760,7 +2761,7 @@ ctrl_thread__kill(CTRL_Msg *msg) run_ctrls.run_entity_count = 1; for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process)) { done = 1; @@ -2788,7 +2789,7 @@ ctrl_thread__kill(CTRL_Msg *msg) } internal void -ctrl_thread__detach(CTRL_Msg *msg) +ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -2796,7 +2797,7 @@ ctrl_thread__detach(CTRL_Msg *msg) DMN_Handle process = msg->entity; //- rjf: detach - B32 detach_worked = dmn_detach_process(process); + B32 detach_worked = dmn_ctrl_detach(ctrl_ctx, process); //- rjf: wait for process to be dead if(detach_worked) @@ -2808,7 +2809,7 @@ ctrl_thread__detach(CTRL_Msg *msg) run_ctrls.run_entity_count = 1; for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process)) { done = 1; @@ -2836,7 +2837,7 @@ ctrl_thread__detach(CTRL_Msg *msg) } internal void -ctrl_thread__run(CTRL_Msg *msg) +ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -2959,7 +2960,7 @@ ctrl_thread__run(CTRL_Msg *msg) run_ctrls.single_step_thread = node->v; for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; @@ -3062,7 +3063,7 @@ ctrl_thread__run(CTRL_Msg *msg) ////////////////////////// //- rjf: get next event // - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, run_spoof); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, run_spoof); ////////////////////////// //- rjf: determine event handling @@ -3298,7 +3299,7 @@ ctrl_thread__run(CTRL_Msg *msg) single_step_ctrls.single_step_thread = event->thread; for(B32 single_step_done = 0; single_step_done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &single_step_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &single_step_ctrls, 0); switch(event->kind) { default:{}break; @@ -3369,7 +3370,7 @@ ctrl_thread__run(CTRL_Msg *msg) single_step_ctrls.single_step_thread = target_thread; for(B32 single_step_done = 0; single_step_done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &single_step_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &single_step_ctrls, 0); switch(event->kind) { default:{}break; @@ -3454,7 +3455,7 @@ ctrl_thread__run(CTRL_Msg *msg) single_step_ctrls.single_step_thread = event->thread; for(B32 single_step_done = 0; single_step_done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &single_step_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &single_step_ctrls, 0); switch(event->kind) { default:{}break; @@ -3539,7 +3540,7 @@ ctrl_thread__run(CTRL_Msg *msg) } internal void -ctrl_thread__single_step(CTRL_Msg *msg) +ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -3561,7 +3562,7 @@ ctrl_thread__single_step(CTRL_Msg *msg) run_ctrls.single_step_thread = msg->entity; for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index f74f2a83..2ac62d9b 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -699,23 +699,23 @@ internal CTRL_EventList ctrl_c2u_pop_events(Arena *arena); internal void ctrl_thread__entry_point(void *p); //- rjf: breakpoint resolution -internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); -internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_MachineID machine_id, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); //- rjf: attached process running/event gathering -internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof); +internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof); //- rjf: eval helpers internal B32 ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size); //- rjf: msg kind implementations -internal void ctrl_thread__launch_and_handshake(CTRL_Msg *msg); -internal void ctrl_thread__launch_and_init(CTRL_Msg *msg); -internal void ctrl_thread__attach(CTRL_Msg *msg); -internal void ctrl_thread__kill(CTRL_Msg *msg); -internal void ctrl_thread__detach(CTRL_Msg *msg); -internal void ctrl_thread__run(CTRL_Msg *msg); -internal void ctrl_thread__single_step(CTRL_Msg *msg); +internal void ctrl_thread__launch_and_handshake(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__launch_and_init(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); //////////////////////////////// //~ rjf: Memory-Stream Thread Functions diff --git a/src/demon2/demon2_core.h b/src/demon2/demon2_core.h index adb84bd4..6ff8e2d3 100644 --- a/src/demon2/demon2_core.h +++ b/src/demon2/demon2_core.h @@ -4,6 +4,20 @@ #ifndef DEMON2_CORE_H #define DEMON2_CORE_H +//////////////////////////////// +//~ rjf: Control-Thread-Only Context +// +// An instance of this struct must ONLY be returned by dmn_ctrl_begin, and only +// used by the thread which called it. All APIs which can ONLY run on the +// control thread, which blocks to control & receive events, will take this +// parameter. All other APIs can be called from any thread. + +typedef struct DMN_CtrlCtx DMN_CtrlCtx; +struct DMN_CtrlCtx +{ + U64 u64 [1]; +}; + //////////////////////////////// //~ rjf: Handle Types @@ -174,11 +188,12 @@ internal void dmn_init(void); //////////////////////////////// //~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS) -internal U32 dmn_launch_process(OS_LaunchOptions *options); -internal B32 dmn_attach_process(U32 pid); -internal B32 dmn_kill_process(DMN_Handle process, U32 exit_code); -internal B32 dmn_detach_process(DMN_Handle process); -internal DMN_EventList dmn_run(Arena *arena, DMN_RunCtrls *ctrls); +internal DMN_CtrlCtx *dmn_ctrl_begin(void); +internal U32 dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options); +internal B32 dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid); +internal B32 dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code); +internal B32 dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process); +internal DMN_EventList dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls); //////////////////////////////// //~ rjf: @dmn_os_hooks Halting (Implemented Per-OS) @@ -193,6 +208,11 @@ internal U64 dmn_run_gen(void); internal U64 dmn_mem_gen(void); internal U64 dmn_reg_gen(void); +//- rjf: non-blocking-control-thread access barriers +internal B32 dmn_access_open(void); +internal void dmn_access_close(void); +#define DMN_AccessScope DeferLoopChecked(dmn_access_open(), dmn_access_close()) + //- rjf: processes internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst); internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src); diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index ddf921c9..6a86c4e5 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -1073,6 +1073,7 @@ dmn_init(void) Arena *arena = arena_alloc(); dmn_w32_shared = push_array(arena, DMN_W32_Shared, 1); dmn_w32_shared->arena = arena; + dmn_w32_shared->access_mutex = os_mutex_alloc(); dmn_w32_shared->detach_arena = arena_alloc(); dmn_w32_shared->entities_arena = arena_alloc__sized(GB(8), KB(64)); dmn_w32_shared->entities_base = dmn_w32_entity_alloc(&dmn_w32_entity_nil, DMN_W32_EntityKind_Root, 0); @@ -1110,102 +1111,111 @@ dmn_init(void) //////////////////////////////// //~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS) +internal DMN_CtrlCtx * +dmn_ctrl_begin(void) +{ + DMN_CtrlCtx *ctx = (DMN_CtrlCtx *)1; + dmn_w32_ctrl_thread = 1; + return ctx; +} + internal U32 -dmn_launch_process(OS_LaunchOptions *options) +dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options) { Temp scratch = scratch_begin(0, 0); U32 result = 0; - - //- rjf: produce exe / arguments string - String8 cmd = {0}; - if(options->cmd_line.first != 0) + DMN_AccessScope { - String8List args = {0}; - String8 exe_path = options->cmd_line.first->string; - str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path); - for(String8Node *n = options->cmd_line.first->next; n != 0; n = n->next) + //- rjf: produce exe / arguments string + String8 cmd = {0}; + if(options->cmd_line.first != 0) { - str8_list_push(scratch.arena, &args, n->string); - } - StringJoin join_params = {0}; - join_params.sep = str8_lit(" "); - cmd = str8_list_join(scratch.arena, &args, &join_params); - } - - //- rjf: produce environment strings - String8 env = {0}; - { - String8List all_opts = options->env; - if(options->inherit_env != 0) - { - MemoryZeroStruct(&all_opts); - str8_list_push(scratch.arena, &all_opts, str8_lit("_NO_DEBUG_HEAP=1")); - for(String8Node *n = options->env.first; n != 0; n = n->next) + String8List args = {0}; + String8 exe_path = options->cmd_line.first->string; + str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path); + for(String8Node *n = options->cmd_line.first->next; n != 0; n = n->next) { - str8_list_push(scratch.arena, &all_opts, n->string); - } - for(String8Node *n = dmn_w32_shared->env_strings.first; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &all_opts, n->string); + str8_list_push(scratch.arena, &args, n->string); } + StringJoin join_params = {0}; + join_params.sep = str8_lit(" "); + cmd = str8_list_join(scratch.arena, &args, &join_params); } - StringJoin join_params2 = {0}; - join_params2.sep = str8_lit("\0"); - join_params2.post = str8_lit("\0"); - env = str8_list_join(scratch.arena, &all_opts, &join_params2); - } - - //- rjf: produce utf-16 strings - String16 cmd16 = str16_from_8(scratch.arena, cmd); - String16 dir16 = str16_from_8(scratch.arena, options->path); - String16 env16 = str16_from_8(scratch.arena, env); - - //- rjf: launch - DWORD access_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS; - STARTUPINFOW startup_info = {sizeof(startup_info)}; - PROCESS_INFORMATION process_info = {0}; - AllocConsole(); - if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info)) - { - // check if we are 32-bit app, and just close it immediately - BOOL is_wow = 0; - IsWow64Process(process_info.hProcess, &is_wow); - if(is_wow) + + //- rjf: produce environment strings + String8 env = {0}; { - MessageBox(0, "Sorry, The RAD Debugger only debugs 64-bit applications currently.", "Process error", MB_OK|MB_ICONSTOP); - DebugActiveProcessStop(process_info.dwProcessId); - TerminateProcess(process_info.hProcess,0xffffffff); + String8List all_opts = options->env; + if(options->inherit_env != 0) + { + MemoryZeroStruct(&all_opts); + str8_list_push(scratch.arena, &all_opts, str8_lit("_NO_DEBUG_HEAP=1")); + for(String8Node *n = options->env.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + for(String8Node *n = dmn_w32_shared->env_strings.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + } + StringJoin join_params2 = {0}; + join_params2.sep = str8_lit("\0"); + join_params2.post = str8_lit("\0"); + env = str8_list_join(scratch.arena, &all_opts, &join_params2); + } + + //- rjf: produce utf-16 strings + String16 cmd16 = str16_from_8(scratch.arena, cmd); + String16 dir16 = str16_from_8(scratch.arena, options->path); + String16 env16 = str16_from_8(scratch.arena, env); + + //- rjf: launch + DWORD access_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS; + STARTUPINFOW startup_info = {sizeof(startup_info)}; + PROCESS_INFORMATION process_info = {0}; + AllocConsole(); + if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info)) + { + // check if we are 32-bit app, and just close it immediately + BOOL is_wow = 0; + IsWow64Process(process_info.hProcess, &is_wow); + if(is_wow) + { + MessageBox(0, "Sorry, The RAD Debugger only debugs 64-bit applications currently.", "Process error", MB_OK|MB_ICONSTOP); + DebugActiveProcessStop(process_info.dwProcessId); + TerminateProcess(process_info.hProcess,0xffffffff); + } + else + { + result = process_info.dwProcessId; + dmn_w32_shared->new_process_pending = 1; + } + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); } else { - result = process_info.dwProcessId; - dmn_w32_shared->new_process_pending = 1; + MessageBox(0, "Error starting process.", "Process error", MB_OK|MB_ICONSTOP); + } + FreeConsole(); + + //- rjf: eliminate all handles which have stuck around from the AllocConsole + { + SetStdHandle(STD_INPUT_HANDLE, 0); + SetStdHandle(STD_OUTPUT_HANDLE, 0); + SetStdHandle(STD_ERROR_HANDLE, 0); } - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); } - else - { - MessageBox(0, "Error starting process.", "Process error", MB_OK|MB_ICONSTOP); - } - FreeConsole(); - - //- rjf: eliminate all handles which have stuck around from the AllocConsole - { - SetStdHandle(STD_INPUT_HANDLE, 0); - SetStdHandle(STD_OUTPUT_HANDLE, 0); - SetStdHandle(STD_ERROR_HANDLE, 0); - } - scratch_end(scratch); return result; } internal B32 -dmn_attach_process(U32 pid) +dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid) { B32 result = 0; - if(DebugActiveProcess((DWORD)pid)) + DMN_AccessScope if(DebugActiveProcess((DWORD)pid)) { result = 1; dmn_w32_shared->new_process_pending = 1; @@ -1214,57 +1224,63 @@ dmn_attach_process(U32 pid) } internal B32 -dmn_kill_process(DMN_Handle process, U32 exit_code) +dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code) { B32 result = 0; - DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); - if(TerminateProcess(process_entity->handle, exit_code)) + DMN_AccessScope { - result = 1; + DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); + if(TerminateProcess(process_entity->handle, exit_code)) + { + result = 1; + } } return result; } internal B32 -dmn_detach_process(DMN_Handle process) +dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process) { B32 result = 0; - DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); - - // rjf: resume threads - for(DMN_W32_Entity *child = process_entity->first; - child != &dmn_w32_entity_nil; - child = child->next) + DMN_AccessScope { - if(child->kind == DMN_W32_EntityKind_Thread) + DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); + + // rjf: resume threads + for(DMN_W32_Entity *child = process_entity->first; + child != &dmn_w32_entity_nil; + child = child->next) { - DWORD resume_result = ResumeThread(child->handle); - (void)resume_result; + if(child->kind == DMN_W32_EntityKind_Thread) + { + DWORD resume_result = ResumeThread(child->handle); + (void)resume_result; + } + } + + // rjf: detach + { + DWORD pid = (DWORD)process_entity->id; + if(DebugActiveProcessStop(pid)) + { + result = 1; + } + } + + // rjf: push into list of processes to generate events for later + if(result != 0) + { + dmn_handle_list_push(dmn_w32_shared->detach_arena, &dmn_w32_shared->detach_processes, process); } } - - // rjf: detach - { - DWORD pid = (DWORD)process_entity->id; - if(DebugActiveProcessStop(pid)) - { - result = 1; - } - } - - // rjf: push into list of processes to generate events for later - if(result != 0) - { - dmn_handle_list_push(dmn_w32_shared->detach_arena, &dmn_w32_shared->detach_processes, process); - } - return result; } internal DMN_EventList -dmn_run(Arena *arena, DMN_RunCtrls *ctrls) +dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) { DMN_EventList events = {0}; + dmn_access_open(); ////////////////////////////// //- rjf: determine event generation path @@ -2319,6 +2335,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) }break; } + dmn_access_close(); return events; } @@ -2378,21 +2395,56 @@ dmn_reg_gen(void) return result; } +//- rjf: non-blocking-control-thread access barriers + +internal B32 +dmn_access_open(void) +{ + B32 result = 0; + if(dmn_w32_ctrl_thread) + { + result = 1; + } + else + { + os_mutex_take(dmn_w32_shared->access_mutex); + result = !dmn_w32_shared->access_run_state; + } + return result; +} + +internal void +dmn_access_close(void) +{ + if(!dmn_w32_ctrl_thread) + { + os_mutex_drop(dmn_w32_shared->access_mutex); + } +} + //- rjf: processes internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst) { - DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process); - U64 result = dmn_w32_process_read(entity->handle, range, dst); + U64 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process); + result = dmn_w32_process_read(entity->handle, range, dst); + } return result; } internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src) { - DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process); - B32 result = dmn_w32_process_write(entity->handle, range, src); + B32 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process); + result = dmn_w32_process_write(entity->handle, range, src); + } return result; } @@ -2401,37 +2453,45 @@ dmn_process_write(DMN_Handle process, Rng1U64 range, void *src) internal Architecture dmn_arch_from_thread(DMN_Handle handle) { - DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle); - return entity->arch; + Architecture arch = Architecture_Null; + DMN_AccessScope + { + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle); + arch = entity->arch; + } + return arch; } internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle) { U64 result = 0; - DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); - if(thread->kind == DMN_W32_EntityKind_Thread) + DMN_AccessScope { - DMN_W32_Entity *process = thread->parent; - U64 tlb = thread->thread.thread_local_base; - switch(thread->arch) + DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); + if(thread->kind == DMN_W32_EntityKind_Thread) { - case Architecture_Null: - case Architecture_COUNT: - {}break; - case Architecture_arm64: - case Architecture_arm32: - {NotImplemented;}break; - case Architecture_x64: + DMN_W32_Entity *process = thread->parent; + U64 tlb = thread->thread.thread_local_base; + switch(thread->arch) { - U64 stack_base_addr = tlb + 0x8; - dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+8), &result); - }break; - case Architecture_x86: - { - U64 stack_base_addr = tlb + 0x4; - dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+4), &result); - }break; + case Architecture_Null: + case Architecture_COUNT: + {}break; + case Architecture_arm64: + case Architecture_arm32: + {NotImplemented;}break; + case Architecture_x64: + { + U64 stack_base_addr = tlb + 0x8; + dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+8), &result); + }break; + case Architecture_x86: + { + U64 stack_base_addr = tlb + 0x4; + dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+4), &result); + }break; + } } } return result; @@ -2441,10 +2501,13 @@ internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle) { U64 result = 0; - DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle); - if(entity->kind == DMN_W32_EntityKind_Thread) + DMN_AccessScope { - result = entity->thread.thread_local_base; + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle); + if(entity->kind == DMN_W32_EntityKind_Thread) + { + result = entity->thread.thread_local_base; + } } return result; } @@ -2452,16 +2515,24 @@ dmn_tls_root_vaddr_from_thread(DMN_Handle handle) internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block) { - DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); - B32 result = dmn_w32_thread_read_reg_block(thread->arch, thread->handle, reg_block); + B32 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); + result = dmn_w32_thread_read_reg_block(thread->arch, thread->handle, reg_block); + } return result; } internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block) { - DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); - B32 result = dmn_w32_thread_write_reg_block(thread->arch, thread->handle, reg_block); + B32 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); + result = dmn_w32_thread_write_reg_block(thread->arch, thread->handle, reg_block); + } return result; } diff --git a/src/demon2/win32/demon2_core_win32.h b/src/demon2/win32/demon2_core_win32.h index d75ee249..15e2e3ac 100644 --- a/src/demon2/win32/demon2_core_win32.h +++ b/src/demon2/win32/demon2_core_win32.h @@ -194,6 +194,10 @@ struct DMN_W32_Shared Arena *arena; String8List env_strings; + // rjf: access locking mechanism + OS_Handle access_mutex; + B32 access_run_state; + // rjf: run/mem/reg gens U64 run_gen; U64 mem_gen; @@ -232,6 +236,7 @@ struct DMN_W32_Shared global DMN_W32_Shared *dmn_w32_shared = 0; global DMN_W32_Entity dmn_w32_entity_nil = {&dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil}; global DMN_W32_GetThreadDescriptionFunctionType *dmn_w32_GetThreadDescription = 0; +thread_static B32 dmn_w32_ctrl_thread = 0; //////////////////////////////// //~ rjf: Basic Helpers diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index 11efef73..c28a1950 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -1,18 +1,21 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Demon2 Pass Tasks +// +// [ ] solidify synchronization mechanisms for usage of demon2 layer +// [ ] TLS eval correctness +// [ ] TLS eval -> in-process-memory EXE info +// [ ] unwinding -> in-process-memory EXE info +// [ ] freezing thread while running -> soft-halt + //////////////////////////////// //~ rjf: Frontend/UI Pass Tasks // -// [x] hover-eval when window is not focused - maybe just start directly -// using mouse-move events here -// [x] CRT asserts - stepping over int 29 should work just like stepping over -// an int3 -// [ ] check new callstack caching rules very strongly // [ ] committing needs to happen when navigating focus away for any reason // [ ] better discoverability for view rules - have better help hover tooltip, // info on arguments, and better autocomplete lister -// [ ] freezing thread while running -> soft-halt // // [ ] source view -> floating margin/line-nums // [ ] theme colors -> more explicit about e.g. opaque backgrounds vs. floating @@ -81,8 +84,6 @@ // [ ] disasm animation & go-to-address // // [ ] visualize remapped files (via path map) -// -// [x] DBGI layer is case-sensitive even on case-insensitive systems //////////////////////////////// //~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup) From 2c8c9a497ca53f0a01885c815cc5e2dbb2320404 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 22 Mar 2024 16:15:20 -0700 Subject: [PATCH 30/33] parameterize ctrl thread registers cache with entity store, rather than relying on implicit demon-api-provided cache --- src/ctrl/ctrl_core.c | 50 ++++++++-------------------- src/ctrl/ctrl_core.h | 11 ++---- src/demon2/demon2_core.h | 3 ++ src/demon2/win32/demon2_core_win32.c | 18 ++++++++++ src/df/core/df_core.c | 14 ++++---- src/regs/generated/regs.meta.c | 2 +- src/regs/regs.mdesk | 2 +- 7 files changed, 46 insertions(+), 54 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 1987676d..fa06d999 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -800,7 +800,6 @@ ctrl_init(void) Arena *arena = arena_alloc(); ctrl_state = push_array(arena, CTRL_State, 1); ctrl_state->arena = arena; - ctrl_state->ctrl_run_mutex = os_mutex_alloc(); for(Architecture arch = (Architecture)0; arch < Architecture_COUNT; arch = (Architecture)(arch+1)) { String8 *reg_names = regs_reg_code_string_table_from_architecture(arch); @@ -1284,10 +1283,11 @@ ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, //- rjf: thread register cache reading internal void * -ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread) +ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread) { CTRL_ThreadRegCache *cache = &ctrl_state->thread_reg_cache; - Architecture arch = dmn_arch_from_thread(thread); + CTRL_Entity *thread_entity = ctrl_entity_from_machine_id_handle(store, machine_id, thread); + Architecture arch = thread_entity->arch; U64 reg_block_size = regs_block_size_from_architecture(arch); U64 hash = ctrl_hash_from_machine_id_handle(machine_id, thread); U64 slot_idx = hash%cache->slots_count; @@ -1346,14 +1346,11 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, { U64 current_reg_gen = dmn_reg_gen(); B32 need_stale = 1; - if(node->reg_gen != current_reg_gen) + if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(thread, result)) { - OS_MutexScope(ctrl_state->ctrl_run_mutex) if(ctrl_state->ctrl_run_state == 0 && dmn_thread_read_reg_block(thread, result)) - { - need_stale = 0; - node->reg_gen = current_reg_gen; - MemoryCopy(node->block, result, reg_block_size); - } + need_stale = 0; + node->reg_gen = current_reg_gen; + MemoryCopy(node->block, result, reg_block_size); } if(need_stale) { @@ -1365,34 +1362,24 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, } internal U64 -ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) +ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread) { U64 result = dmn_tls_root_vaddr_from_thread(thread); return result; } internal U64 -ctrl_query_cached_rip_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) +ctrl_query_cached_rip_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread) { Temp scratch = scratch_begin(0, 0); - Architecture arch = dmn_arch_from_thread(thread); - void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, machine_id, thread); + CTRL_Entity *thread_entity = ctrl_entity_from_machine_id_handle(store, machine_id, thread); + Architecture arch = thread_entity->arch; + void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, store, machine_id, thread); U64 result = regs_rip_from_arch_block(arch, block); scratch_end(scratch); return result; } -internal U64 -ctrl_query_cached_rsp_from_thread(CTRL_MachineID machine_id, DMN_Handle thread) -{ - Temp scratch = scratch_begin(0, 0); - Architecture arch = dmn_arch_from_thread(thread); - void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, machine_id, thread); - U64 result = regs_rsp_from_arch_block(arch, block); - scratch_end(scratch); - return result; -} - //- rjf: thread register writing internal B32 @@ -1728,13 +1715,8 @@ ctrl_thread__entry_point(void *p) //- rjf: get next messages CTRL_MsgList msgs = ctrl_u2c_pop_msgs(scratch.arena); - //- rjf: begin run state - OS_MutexScope(ctrl_state->ctrl_run_mutex) - { - ctrl_state->ctrl_run_state = 1; - } - //- rjf: process messages + DMN_CtrlExclusiveAccessScope { B32 done = 0; for(CTRL_MsgNode *msg_n = msgs.first; msg_n != 0 && done == 0; msg_n = msg_n->next) @@ -1768,12 +1750,6 @@ ctrl_thread__entry_point(void *p) } } } - - //- rjf: end run state - OS_MutexScope(ctrl_state->ctrl_run_mutex) - { - ctrl_state->ctrl_run_state = 0; - } } scratch_end(scratch); diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 2ac62d9b..02ca8006 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -491,10 +491,6 @@ struct CTRL_State EVAL_String2NumMap arch_string2reg_tables[Architecture_COUNT]; EVAL_String2NumMap arch_string2alias_tables[Architecture_COUNT]; - // rjf: access locking mechanism - OS_Handle ctrl_run_mutex; - B32 ctrl_run_state; - // rjf: caches CTRL_ProcessMemoryCache process_memory_cache; CTRL_ThreadRegCache thread_reg_cache; @@ -654,10 +650,9 @@ internal B32 ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, R //~ rjf: Thread Register Functions //- rjf: thread register cache reading -internal void *ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id, DMN_Handle thread); -internal U64 ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, DMN_Handle thread); -internal U64 ctrl_query_cached_rip_from_thread(CTRL_MachineID machine_id, DMN_Handle thread); -internal U64 ctrl_query_cached_rsp_from_thread(CTRL_MachineID machine_id, DMN_Handle thread); +internal void *ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread); +internal U64 ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread); +internal U64 ctrl_query_cached_rip_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread); //- rjf: thread register writing internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block); diff --git a/src/demon2/demon2_core.h b/src/demon2/demon2_core.h index 6ff8e2d3..e0e3860e 100644 --- a/src/demon2/demon2_core.h +++ b/src/demon2/demon2_core.h @@ -189,6 +189,9 @@ internal void dmn_init(void); //~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS) internal DMN_CtrlCtx *dmn_ctrl_begin(void); +internal void dmn_ctrl_exclusive_access_begin(void); +internal void dmn_ctrl_exclusive_access_end(void); +#define DMN_CtrlExclusiveAccessScope DeferLoop(dmn_ctrl_exclusive_access_begin(), dmn_ctrl_exclusive_access_end()) internal U32 dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options); internal B32 dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid); internal B32 dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code); diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index 6a86c4e5..39b41e6a 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -1119,6 +1119,24 @@ dmn_ctrl_begin(void) return ctx; } +internal void +dmn_ctrl_exclusive_access_begin(void) +{ + OS_MutexScope(dmn_w32_shared->access_mutex) + { + dmn_w32_shared->access_run_state = 1; + } +} + +internal void +dmn_ctrl_exclusive_access_end(void) +{ + OS_MutexScope(dmn_w32_shared->access_mutex) + { + dmn_w32_shared->access_run_state = 0; + } +} + internal U32 dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options) { diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 9321cd09..0d3fbf74 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -2822,7 +2822,7 @@ df_trap_net_from_thread__step_over_inst(Arena *arena, DF_Entity *thread) // rjf: thread => unpacked info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); Architecture arch = df_architecture_from_entity(thread); - U64 ip_vaddr = ctrl_query_cached_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); + U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); // rjf: ip => machine code String8 machine_code = {0}; @@ -2861,7 +2861,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) DF_Entity *module = df_module_from_thread(thread); DF_Entity *binary = df_binary_file_from_module(module); Architecture arch = df_architecture_from_entity(thread); - U64 ip_vaddr = ctrl_query_cached_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); + U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); // rjf: ip => line vaddr range Rng1U64 line_vaddr_rng = {0}; @@ -2986,7 +2986,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) DF_Entity *module = df_module_from_thread(thread); DF_Entity *binary = df_binary_file_from_module(module); Architecture arch = df_architecture_from_entity(thread); - U64 ip_vaddr = ctrl_query_cached_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); + U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); // rjf: ip => line vaddr range Rng1U64 line_vaddr_rng = {0}; @@ -3659,7 +3659,7 @@ internal B32 df_set_thread_rip(DF_Entity *thread, U64 vaddr) { Temp scratch = scratch_begin(0, 0); - void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, thread->ctrl_machine_id, thread->ctrl_handle); + void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); regs_arch_block_write_rip(thread->arch, block, vaddr); B32 result = ctrl_thread_write_reg_block(thread->ctrl_machine_id, thread->ctrl_handle, block); @@ -4081,7 +4081,7 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ //- rjf: unpack arguments DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); - U64 tls_root_vaddr = ctrl_query_cached_tls_root_vaddr_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); + U64 tls_root_vaddr = ctrl_query_cached_tls_root_vaddr_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); DF_Entity *process = thread->parent; U64 unwind_count = ctrl_ctx->unwind_count; CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); @@ -6195,7 +6195,7 @@ df_query_cached_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count) U64 result = 0; if(unwind_count == 0) { - result = ctrl_query_cached_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); + result = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); } else { @@ -6599,7 +6599,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) // rjf: thread hit user breakpoint -> increment breakpoint hit count if(event->cause == CTRL_EventCause_UserBreakpoint) { - U64 stop_thread_vaddr = ctrl_query_cached_rip_from_thread(stop_thread->ctrl_machine_id, stop_thread->ctrl_handle); + U64 stop_thread_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, stop_thread->ctrl_machine_id, stop_thread->ctrl_handle); DF_Entity *process = df_entity_ancestor_from_kind(stop_thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, stop_thread_vaddr); DF_Entity *binary = df_binary_file_from_module(module); diff --git a/src/regs/generated/regs.meta.c b/src/regs/generated/regs.meta.c index 6e8d2707..213acb9b 100644 --- a/src/regs/generated/regs.meta.c +++ b/src/regs/generated/regs.meta.c @@ -5,7 +5,7 @@ internal U64 regs_block_size_from_architecture(Architecture arch) { -U64 result = 0; +U64 result = 8; switch(arch) { default:{}break; diff --git a/src/regs/regs.mdesk b/src/regs/regs.mdesk index 6370a1d4..cfebf067 100644 --- a/src/regs/regs.mdesk +++ b/src/regs/regs.mdesk @@ -421,7 +421,7 @@ regs_g_reg_code_x86_usage_kind_table: { `internal U64 regs_block_size_from_architecture(Architecture arch)`; `{`; - `U64 result = 0;`; + `U64 result = 8;`; `switch(arch)`; `{`; `default:{}break;`; From 7cd524d39d7a0c6094e3ff48ae907e591c14b0f3 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 22 Mar 2024 16:19:35 -0700 Subject: [PATCH 31/33] fix tls base calculation in demon2 --- src/demon2/win32/demon2_core_win32.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index 39b41e6a..ab320c3d 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -2525,6 +2525,23 @@ dmn_tls_root_vaddr_from_thread(DMN_Handle handle) if(entity->kind == DMN_W32_EntityKind_Thread) { result = entity->thread.thread_local_base; + switch(entity->arch) + { + case Architecture_Null: + case Architecture_COUNT: + {}break; + case Architecture_arm64: + case Architecture_arm32: + {NotImplemented;}break; + case Architecture_x64: + { + result += 88; + }break; + case Architecture_x86: + { + result += 44; + }break; + } } } return result; From 928532f386c2f0144dc7243576a6f4bf9668b49b Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 22 Mar 2024 16:29:50 -0700 Subject: [PATCH 32/33] do not attempt to refresh tls base calculation cache, if targets running --- src/df/core/df_core.c | 143 +++++++++++++++++++++--------------------- src/raddbg/raddbg.h | 4 +- 2 files changed, 75 insertions(+), 72 deletions(-) diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 0d3fbf74..df6ae29f 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -2520,11 +2520,13 @@ df_set_thread_freeze_state(DF_Entity *thread, B32 frozen) } node->handle = thread_handle; df_handle_list_push_node(&df_state->frozen_threads, node); + df_state->entities_mut_soft_halt = 1; } // rjf: frozen => not frozen if(is_frozen && !should_be_frozen) { + df_state->entities_mut_soft_halt = 1; df_handle_list_remove(&df_state->frozen_threads, already_frozen_node); SLLStackPush(df_state->free_handle_node, already_frozen_node); } @@ -3542,83 +3544,84 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 U64 base_vaddr = 0; Temp scratch = scratch_begin(0, 0); DBGI_Scope *scope = dbgi_scope_open(); - - //- rjf: unpack thread info - DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); - String8 bin_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); - PE_BinInfo *bin = &dbgi->pe; - B32 bin_is_pe = 1; // TODO(rjf): this path needs to change for ELF - U64 addr_size = bit_size_from_arch(bin->arch)/8; - - //- rjf: grab tls range - Rng1U64 tls_vaddr_range = pe_tls_rng_from_bin_base_vaddr(bin_data, bin, df_base_vaddr_from_module(module)); - - //- rjf: read module's TLS index - U64 tls_index = 0; + if(!df_ctrl_targets_running()) { - CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, 0); - if(tls_index_slice.data.size >= addr_size) - { - tls_index = *(U64 *)tls_index_slice.data.str; - } - } - - //- rjf: PE path - if(bin_is_pe) - { - U64 thread_info_addr = root_vaddr; - U64 tls_addr_off = tls_index*addr_size; - U64 tls_addr_array = 0; - CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(thread_info_addr, thread_info_addr+addr_size), 0); - String8 tls_addr_array_data = tls_addr_array_slice.data; - if(tls_addr_array_data.size >= 8) - { - MemoryCopy(&tls_addr_array, tls_addr_array_data.str, sizeof(U64)); - } - CTRL_ProcessMemorySlice result_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), 0); - String8 result_data = result_slice.data; - if(result_data.size >= 8) - { - MemoryCopy(&base_vaddr, result_data.str, sizeof(U64)); - } - } - - //- rjf: non-PE path (not implemented) - if(!bin_is_pe) - { - // TODO(rjf): not supported. old code from the prototype that Nick had sketched out: -#if 0 - // TODO(nick): This code works only if the linked c runtime library is glibc. - // Implement CRT detection here. + //- rjf: unpack thread info + DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); + String8 bin_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); + PE_BinInfo *bin = &dbgi->pe; + B32 bin_is_pe = 1; // TODO(rjf): this path needs to change for ELF + U64 addr_size = bit_size_from_arch(bin->arch)/8; - U64 dtv_addr = UINT64_MAX; - demon_read_memory(process->demon_handle, &dtv_addr, thread_info_addr, addr_size); + //- rjf: grab tls range + Rng1U64 tls_vaddr_range = pe_tls_rng_from_bin_base_vaddr(bin_data, bin, df_base_vaddr_from_module(module)); - /* - union delta_thread_vector + //- rjf: read module's TLS index + U64 tls_index = 0; + { + CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, 0); + if(tls_index_slice.data.size >= addr_size) { - size_t counter; - struct - { - void *value; - void *to_free; - } pointer; - }; - */ - - U64 dtv_size = 16; - U64 dtv_count = 0; - demon_read_memory(process->demon_handle, &dtv_count, dtv_addr - dtv_size, addr_size); - - if (tls_index > 0 && tls_index < dtv_count) - { - demon_read_memory(process->demon_handle, &result, dtv_addr + dtv_size*tls_index, addr_size); + tls_index = *(U64 *)tls_index_slice.data.str; + } } + + //- rjf: PE path + if(bin_is_pe) + { + U64 thread_info_addr = root_vaddr; + U64 tls_addr_off = tls_index*addr_size; + U64 tls_addr_array = 0; + CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(thread_info_addr, thread_info_addr+addr_size), 0); + String8 tls_addr_array_data = tls_addr_array_slice.data; + if(tls_addr_array_data.size >= 8) + { + MemoryCopy(&tls_addr_array, tls_addr_array_data.str, sizeof(U64)); + } + CTRL_ProcessMemorySlice result_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), 0); + String8 result_data = result_slice.data; + if(result_data.size >= 8) + { + MemoryCopy(&base_vaddr, result_data.str, sizeof(U64)); + } + } + + //- rjf: non-PE path (not implemented) + if(!bin_is_pe) + { + // TODO(rjf): not supported. old code from the prototype that Nick had sketched out: +#if 0 + // TODO(nick): This code works only if the linked c runtime library is glibc. + // Implement CRT detection here. + + U64 dtv_addr = UINT64_MAX; + demon_read_memory(process->demon_handle, &dtv_addr, thread_info_addr, addr_size); + + /* + union delta_thread_vector + { + size_t counter; + struct + { + void *value; + void *to_free; + } pointer; + }; + */ + + U64 dtv_size = 16; + U64 dtv_count = 0; + demon_read_memory(process->demon_handle, &dtv_count, dtv_addr - dtv_size, addr_size); + + if (tls_index > 0 && tls_index < dtv_count) + { + demon_read_memory(process->demon_handle, &result, dtv_addr + dtv_size*tls_index, addr_size); + } #endif + } } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index c28a1950..d6f39ba9 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -4,8 +4,8 @@ //////////////////////////////// //~ rjf: Demon2 Pass Tasks // -// [ ] solidify synchronization mechanisms for usage of demon2 layer -// [ ] TLS eval correctness +// [x] solidify synchronization mechanisms for usage of demon2 layer +// [x] TLS eval correctness // [ ] TLS eval -> in-process-memory EXE info // [ ] unwinding -> in-process-memory EXE info // [ ] freezing thread while running -> soft-halt From 71f3d18bf7417dffc53251f640279a34c244030a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 22 Mar 2024 16:30:04 -0700 Subject: [PATCH 33/33] notes --- src/raddbg/raddbg.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index d6f39ba9..eb035e73 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -4,11 +4,11 @@ //////////////////////////////// //~ rjf: Demon2 Pass Tasks // -// [x] solidify synchronization mechanisms for usage of demon2 layer -// [x] TLS eval correctness // [ ] TLS eval -> in-process-memory EXE info // [ ] unwinding -> in-process-memory EXE info -// [ ] freezing thread while running -> soft-halt +// [x] solidify synchronization mechanisms for usage of demon2 layer +// [x] TLS eval correctness +// [x] freezing thread while running -> soft-halt //////////////////////////////// //~ rjf: Frontend/UI Pass Tasks