diff --git a/project.4coder b/project.4coder index f39bd033..0fb436c2 100644 --- a/project.4coder +++ b/project.4coder @@ -47,7 +47,7 @@ commands = { .rjf_f1 = { - .win = "build ryan_scratch", + .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 90f77226..fa06d999 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -6,80 +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->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->demon_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 @@ -94,44 +20,29 @@ 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) -{ - 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 @@ -205,120 +116,6 @@ ctrl_user_breakpoint_list_copy(Arena *arena, CTRL_UserBreakpointList *src) return dst; } -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) -{ - Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); - String8 exe_path = demon_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); - 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; - DEMON_Trap trap = {process, vaddr, (U64)bp}; - demon_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; - DEMON_Trap trap = {process, proc_vaddr + voff, (U64)bp}; - demon_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, DEMON_Handle process, CTRL_UserBreakpointList *user_bps, DEMON_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); - } - } -} - //////////////////////////////// //~ rjf: Message Type Functions @@ -658,187 +455,433 @@ ctrl_event_from_serialized_string(Arena *arena, String8 string) } //////////////////////////////// -//~ rjf: Shared Functions +//~ rjf: Entity Type Functions -//- rjf: run index +//- rjf: cache creation/destruction -internal U64 -ctrl_run_idx(void) +internal CTRL_EntityStore * +ctrl_entity_store_alloc(void) { - U64 result = ins_atomic_u64_eval(&ctrl_state->run_idx); - return result; + 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; } -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 - internal void -ctrl_halt(void) +ctrl_entity_store_release(CTRL_EntityStore *cache) { - demon_halt(0, 0); + arena_release(cache->arena); } -//- 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}; - { - // 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, CTRL_Handle handle) -{ - return demon_arch_from_object(ctrl_demon_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_name_bucket_idx_from_string_size(U64 size) { - U64 actual_bytes_read = demon_read_memory(ctrl_demon_handle_from_ctrl(process), dst, range.min, dim_1u64(range)); - return actual_bytes_read; + 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 B32 -ctrl_process_write(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *src) +internal String8 +ctrl_entity_string_alloc(CTRL_EntityStore *store, String8 string) { - ProfBeginFunction(); - U64 size = dim_1u64(range); - B32 result = demon_write_memory(ctrl_demon_handle_from_ctrl(process), range.min, src, size); + 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: success -> increment memgen - if(result) + // rjf: pull from bucket free list + if(node != 0) { - ins_atomic_u64_inc_eval(&ctrl_state->memgen_idx); + 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: 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) + // 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, Architecture arch, 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->arch = arch; + 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); - 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; - CTRL_Handle process; - Rng1U64 range; + CTRL_Entity *e; }; - 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) + 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 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_Entity *child = t->e->first; child != &ctrl_entity_nil; child = child->next) { - for(CTRL_ProcessMemoryCacheNode *proc_n = slot->first; proc_n != 0; proc_n = proc_n->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) { - for(U64 range_hash_idx = 0; range_hash_idx < proc_n->range_hash_slots_count; range_hash_idx += 1) + if(n->entity->machine_id == t->e->machine_id && dmn_handle_match(n->entity->handle, t->e->handle)) { - 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); - } - } + DLLRemove(slot->first, slot->last, n); + SLLStackPush(store->hash_node_free, n); + break; } } } } - - //- 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: 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 * +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, 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; + } + + //- 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->arch, event->machine_id, event->entity); + }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->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->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: + { + 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 + +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 = 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) + { + 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 = 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].arena = arena_alloc(); + ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = os_rw_mutex_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(); + 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->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)) + { + 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 -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 +896,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, B32 *out_is_stale, U64 endt_us) { U128 result = {0}; U64 size = dim_1u64(range); @@ -872,31 +915,23 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_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 && dmn_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->mem_gen != dmn_mem_gen()); + 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:; } @@ -909,7 +944,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_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; @@ -930,13 +965,14 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle } //- rjf: not good -> create range node if necessary + U64 last_time_requested_us = 0; if(!is_good) { 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)) + 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]; @@ -945,6 +981,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_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; } @@ -969,13 +1006,42 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_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); + 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) + { + 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]; + 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 if(os_now_microseconds() >= endt_us) + { + if(is_good && is_stale && out_is_stale) + { + out_is_stale[0] = 1; + } + break; + } + + //- rjf: done? -> exit + if(is_good && !is_stale) { break; } @@ -986,7 +1052,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 && @@ -1010,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; } @@ -1101,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); @@ -1109,7 +1191,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) @@ -1123,147 +1205,261 @@ ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CT return result; } -//- rjf: register reading/writing - -internal void * -ctrl_reg_block_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread) -{ - void *regs = demon_read_regs(ctrl_demon_handle_from_ctrl(thread)); - return regs; -} +//- rjf: process memory writing internal B32 -ctrl_thread_write_reg_block(CTRL_MachineID machine_id, CTRL_Handle thread, void *block) +ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *src) { - B32 good = demon_write_regs(ctrl_demon_handle_from_ctrl(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) -{ - 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)); - 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) -{ - 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)); - 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, CTRL_Handle thread) -{ - U64 result = 0; - DEMON_Handle demon_handle = ctrl_demon_handle_from_ctrl(thread); - result = demon_tls_root_vaddr_from_thread(demon_handle); - return result; -} - -//- rjf: process * vaddr -> module - -internal CTRL_Handle -ctrl_module_from_process_vaddr(CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr) -{ - CTRL_Handle handle = {0}; + ProfBeginFunction(); + B32 result = dmn_process_write(process, range, src); + + //- 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); - DEMON_HandleArray modules = demon_modules_from_process(scratch.arena, ctrl_demon_handle_from_ctrl(process)); - for(U64 idx = 0; idx < modules.count; idx += 1) + U64 endt_us = os_now_microseconds()+5000; + + //- rjf: gather tasks for all affected cached regions + typedef struct Task Task; + struct Task { - DEMON_Handle m = modules.handles[idx]; - Rng1U64 m_vaddr_rng = demon_vaddr_range_from_module(m); - if(contains_1u64(m_vaddr_rng, vaddr)) + 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) { - handle = ctrl_handle_from_demon(m); + 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_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread) +{ + CTRL_ThreadRegCache *cache = &ctrl_state->thread_reg_cache; + 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; + 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; } } - scratch_end(scratch); + + // 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_reg_gen = dmn_reg_gen(); + B32 need_stale = 1; + if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(thread, result)) + { + need_stale = 0; + node->reg_gen = current_reg_gen; + MemoryCopy(node->block, result, reg_block_size); + } + if(need_stale) + { + MemoryCopy(result, node->block, reg_block_size); + } + } } - return handle; + return result; } -//- rjf: unwinding +internal U64 +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_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread) +{ + Temp scratch = scratch_begin(0, 0); + 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; +} + +//- rjf: thread register writing + +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); + return good; +} + +//////////////////////////////// +//~ rjf: Unwinding Functions internal CTRL_Unwind -ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, CTRL_Handle thread) +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(); - Architecture arch = demon_arch_from_object(ctrl_demon_handle_from_ctrl(thread)); - U64 arch_reg_block_size = regs_block_size_from_architecture(arch); CTRL_Unwind unwind = {0}; unwind.error = 1; - switch(arch) + + //- 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); + + //- rjf: grab initial register block + 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; + 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) + { + 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; + stack_memview.addr_first = stack_top; + stack_memview.addr_opl = stack_base; + } + } + } + + //- rjf: loop & unwind + UNW_MemView memview = stack_memview; + if(regs_block_good && stack_memview_good) switch(arch) { default:{}break; 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; + unwind.error = 0; + for(;;) { - void *regs_raw = ctrl_reg_block_from_thread(machine_id, thread); - if(regs_raw != 0) + // rjf: regs -> rip*module + U64 rip = regs_rip_from_arch_block(arch, regs_block); + 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) { - MemoryCopy(regs_block, regs_raw, arch_reg_block_size); - regs_block_good = 1; - } - } - - // rjf: grab initial memory view - B32 stack_memview_good = 0; - 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_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) - { - 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); - if(stack_memory.size != 0) + if(m->kind == CTRL_EntityKind_Module && contains_1u64(m->vaddr_range, rip)) { - stack_memview_good = 1; - stack_memview.data = stack_memory.str; - stack_memview.addr_first = stack_top; - stack_memview.addr_opl = stack_base; + module = m->handle; + module_name = m->string; + module_vaddr_range = m->vaddr_range; + break; } } - } - - // rjf: loop & unwind - UNW_MemView memview = stack_memview; - if(stack_memview_good) for(;;) - { - unwind.error = 0; - - // 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); // rjf: cancel on 0 rip if(rip == 0) @@ -1271,8 +1467,8 @@ ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Ha break; } - // rjf: binary -> all the binary info - String8 binary_full_path = demon_full_path_from_module(scratch.arena, ctrl_demon_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); @@ -1292,7 +1488,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, module_vaddr_range.min, &memview, (UNW_X64_Regs *)regs_block); // rjf: cancel on bad step if(unwind_step.dead != 0) @@ -1311,12 +1507,48 @@ ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Ha } }break; } + dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); return unwind; } +//////////////////////////////// +//~ rjf: Halting All Attached Processes + +internal void +ctrl_halt(void) +{ + dmn_halt(0, 0); +} + +//////////////////////////////// +//~ rjf: Shared Accessor Functions + +//- rjf: run generation counter + +internal U64 +ctrl_run_gen(void) +{ + U64 result = dmn_run_gen(); + return result; +} + +internal U64 +ctrl_mem_gen(void) +{ + U64 result = dmn_mem_gen(); + return result; +} + +internal U64 +ctrl_reg_gen(void) +{ + U64 result = dmn_reg_gen(); + return result; +} + //- rjf: name -> register/alias hash tables, for eval internal EVAL_String2NumMap * @@ -1332,7 +1564,9 @@ 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) @@ -1394,14 +1628,14 @@ 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) { 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); @@ -1463,55 +1697,6 @@ ctrl_c2u_pop_events(Arena *arena) return events; } -//////////////////////////////// -//~ 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) -{ - 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, CTRL_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: entry point internal void @@ -1519,7 +1704,9 @@ ctrl_thread__entry_point(void *p) { ThreadNameF("[ctrl] thread"); ProfBeginFunction(); - demon_primary_thread_begin(); + DMN_CtrlCtx *ctrl_ctx = dmn_ctrl_begin(); + + //- rjf: loop Temp scratch = scratch_begin(0, 0); for(;;) { @@ -1529,8 +1716,8 @@ ctrl_thread__entry_point(void *p) CTRL_MsgList msgs = ctrl_u2c_pop_msgs(scratch.arena); //- rjf: process messages + DMN_CtrlExclusiveAccessScope { - demon_exclusive_mode_begin(); B32 done = 0; for(CTRL_MsgNode *msg_n = msgs.first; msg_n != 0 && done == 0; msg_n = msg_n->next) { @@ -1542,13 +1729,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: @@ -1562,20 +1749,137 @@ ctrl_thread__entry_point(void *p) }break; } } - demon_exclusive_mode_end(); } } + scratch_end(scratch); 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(ctrl_state->ctrl_thread_entity_store, machine_id, module); + 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; + 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 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, DMN_CtrlCtx *ctrl_ctx, 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 +1890,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 +1935,22 @@ 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); - if(modules.count != 0) + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, ev->process); + 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 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)); + 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); @@ -1656,10 +1968,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 + module->vaddr_range.min; + Architecture arch = process->arch; 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); + 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); } } @@ -1693,7 +2005,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,62 +2014,56 @@ 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_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 && 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)); + 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); } // 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_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof->new_ip_value); } // 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_ctrl_run(scratch.arena, ctrl_ctx, 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); - } - - // 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); + dmn_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); } } } @@ -1767,10 +2073,15 @@ 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)); + 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); + U64 spoof_thread_rip = regs_rip_from_arch_block(arch, regs_block); if(spoof_thread_rip == spoof->new_ip_value) { - demon_write_ip(ctrl_demon_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); } } @@ -1779,95 +2090,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 = event->arch; 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 = event->arch; 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 = event->arch; 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 = event->address; 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 +2186,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 +2207,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 +2223,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; } @@ -1921,7 +2232,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); @@ -1935,7 +2246,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_ctrl_launch(ctrl_ctx, &opts); //- rjf: record start { @@ -1946,12 +2257,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 +2273,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, ctrl_ctx, 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 +2312,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 +2328,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); @@ -2029,7 +2340,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); @@ -2044,7 +2355,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_ctrl_launch(ctrl_ctx, &opts); ////////////////////////////// //- rjf: record start @@ -2059,22 +2370,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, ctrl_ctx, 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 +2394,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 +2412,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,19 +2442,26 @@ 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(); //- 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 - DEMON_HandleArray modules = demon_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); + //- 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 = &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); RDI_Parsed *rdi = &dbgi->rdi; RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Procedures); @@ -2171,8 +2489,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 +2514,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 +2548,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 +2560,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 +2592,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 +2634,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 +2652,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); @@ -2345,35 +2663,35 @@ 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 = demon_attach_process(msg->entity_id); + B32 attach_successful = dmn_ctrl_attach(ctrl_ctx, 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, ctrl_ctx, 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 +2704,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); @@ -2398,29 +2716,29 @@ 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); 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_ctrl_kill(ctrl_ctx, process, exit_code); //- rjf: wait for process to be dead - if(demon_object_exists(process) && kill_worked) + if(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, ctrl_ctx, msg, &run_ctrls, 0); + if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process)) { done = 1; } @@ -2432,7 +2750,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) { @@ -2447,28 +2765,28 @@ 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); 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_ctrl_detach(ctrl_ctx, process); //- rjf: wait for process to be dead - if(demon_object_exists(process) && detach_worked) + if(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, ctrl_ctx, msg, &run_ctrls, 0); + if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process)) { done = 1; } @@ -2480,7 +2798,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) { @@ -2495,43 +2813,39 @@ 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); 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); - ////////////////////////////// //- rjf: gather all initial breakpoints // - DEMON_TrapChunkList user_traps = {0}; + DMN_TrapChunkList user_traps = {0}; + for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->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) { - DEMON_Handle process = processes.handles[process_idx]; - DEMON_HandleArray modules = demon_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) { - DEMON_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); } } @@ -2551,58 +2865,62 @@ ctrl_thread__run(CTRL_Msg *msg) if(stop_event == 0) { // rjf: gather stuck threads - DEMON_HandleList stuck_threads = {0}; - for(U64 i = 0; i < processes.count; i += 1) + DMN_HandleList stuck_threads = {0}; + for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; + machine != &ctrl_entity_nil; + machine = machine->next) { - DEMON_Handle process = processes.handles[i]; - DEMON_HandleArray threads = demon_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) { - DEMON_Handle thread = threads.handles[j]; - U64 rip = demon_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(ctrl_demon_handle_from_ctrl(n->v.handle) == thread) + U64 rip = dmn_rip_from_thread(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(DEMON_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(DEMON_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(trap_ptr->process == process && trap_ptr->address == 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 || thread != target_thread)) - { - demon_handle_list_push(scratch.arena, &stuck_threads, thread); - } - - if(is_on_user_bp && is_on_net_trap && thread == target_thread) - { - target_thread_is_on_user_bp_and_trap_net_trap = 1; } } } @@ -2610,28 +2928,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, ctrl_ctx, 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 +2961,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 +2995,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_rsp_from_thread(target_thread); B32 spoof_mode = 0; CTRL_Spoof spoof = {0}; for(;;) @@ -2685,7 +3003,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 +3021,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,70 +3039,66 @@ 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, ctrl_ctx, 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}; - 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_TrapChunkList new_traps = {0}; + 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 DEMON_EventKind_LoadModule: + case DMN_EventKind_LoadModule: { - DEMON_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_TrapChunkList new_traps = {0}; + 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; } ////////////////////////// //- rjf: unpack info about thread attached to event // - Architecture arch = demon_arch_from_object(event->thread); - U64 reg_size = regs_block_size_from_architecture(arch); - void *thread_regs_block = demon_read_regs(event->thread); - U64 thread_rip_vaddr = regs_rip_from_arch_block(arch, thread_regs_block); - DEMON_Handle module = 0; + 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 thread_rip_vaddr = dmn_rsp_from_thread(event->thread); + DMN_Handle module = {0}; + String8 module_name = {0}; + U64 module_base_vaddr = 0; U64 thread_rip_voff = 0; { - Temp temp = temp_begin(scratch.arena); - DEMON_HandleArray modules = demon_modules_from_process(temp.arena, event->process); - if(modules.count != 0) + 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) { - for(U64 idx = 0; idx < modules.count; idx += 1) + if(module->kind == CTRL_EntityKind_Module && contains_1u64(module->vaddr_range, thread_rip_vaddr)) { - Rng1U64 vaddr_range = demon_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->string; + module_base_vaddr = module->vaddr_range.min; + thread_rip_voff = thread_rip_vaddr - module->vaddr_range.min; + break; } } - temp_end(temp); } ////////////////////////// @@ -2799,12 +3113,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 +3151,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 +3180,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 = 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) @@ -2906,16 +3220,17 @@ ctrl_thread__run(CTRL_Msg *msg) EVAL_Result eval = {0}; if(bytecode.size != 0) { - U64 module_base = demon_base_vaddr_from_module(module); - U64 tls_base = 0; // TODO(rjf) + U64 module_base = module_base_vaddr; + U64 tls_base = dmn_tls_root_vaddr_from_thread(event->thread); 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; - 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) @@ -2933,7 +3248,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 +3271,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, ctrl_ctx, 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 +3310,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 +3321,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 +3331,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_rsp_from_thread(target_thread); stack_pointer_matches = (sp == sp_check_value); } @@ -3027,29 +3342,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, ctrl_ctx, 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 +3379,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_rsp_from_thread(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 +3397,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_rsp_from_thread(target_thread); } } } @@ -3112,27 +3427,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, ctrl_ctx, 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 +3501,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; @@ -3201,7 +3516,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); @@ -3216,23 +3531,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, ctrl_ctx, 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 +3564,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; @@ -3266,6 +3581,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 @@ -3276,7 +3636,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); @@ -3294,14 +3654,14 @@ 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) { 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]; @@ -3310,7 +3670,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; @@ -3326,11 +3686,11 @@ 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, 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) { @@ -3339,7 +3699,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); @@ -3378,7 +3738,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]; @@ -3389,7 +3749,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 f507548d..02ca8006 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,71 @@ 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 string; +}; + +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; +}; + +typedef struct CTRL_EntityStringChunkNode CTRL_EntityStringChunkNode; +struct CTRL_EntityStringChunkNode +{ + CTRL_EntityStringChunkNode *next; + U64 size; +}; + +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; + CTRL_EntityStringChunkNode *free_string_chunks[8]; +}; + //////////////////////////////// //~ rjf: Unwind Types @@ -105,8 +161,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 +233,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 +337,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; @@ -320,7 +376,8 @@ 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; }; @@ -338,7 +395,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; }; @@ -372,6 +429,47 @@ struct CTRL_ProcessMemorySlice String8 data; U64 *byte_bad_flags; U64 *byte_changed_flags; + B32 stale; + B32 any_byte_bad; + B32 any_byte_changed; +}; + +//////////////////////////////// +//~ 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; + U64 block_size; + void *block; + U64 reg_gen; +}; + +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; }; //////////////////////////////// @@ -388,16 +486,14 @@ 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]; 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 +513,11 @@ 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; + CTRL_EntityStore *ctrl_thread_entity_store; + 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 +540,21 @@ 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); //////////////////////////////// //~ rjf: Machine/Handle Pair Type Functions @@ -484,8 +573,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, 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); //////////////////////////////// //~ rjf: Message Type Functions @@ -512,97 +599,127 @@ 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: Entity Type Functions -//- rjf: run index -internal U64 ctrl_run_idx(void); -internal U64 ctrl_memgen_idx(void); -internal U64 ctrl_reggen_idx(void); +//- rjf: cache creation/destruction +internal CTRL_EntityStore *ctrl_entity_store_alloc(void); +internal void ctrl_entity_store_release(CTRL_EntityStore *store); -//- rjf: halt everything -internal void ctrl_halt(void); +//- 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: 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: entity construction/deletion +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: handle -> arch -internal Architecture ctrl_arch_from_handle(CTRL_MachineID machine, CTRL_Handle handle); +//- rjf: entity equipment +internal void ctrl_entity_equip_string(CTRL_EntityStore *store, CTRL_Entity *entity, String8 string); -//- 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: 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 + +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, 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); +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, 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, 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); +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: 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 memory writing +internal B32 ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *src); -//- rjf: process * vaddr -> module -internal CTRL_Handle ctrl_module_from_process_vaddr(CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr); +//////////////////////////////// +//~ rjf: Thread Register Functions -//- rjf: unwinding -internal CTRL_Unwind ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, CTRL_Handle thread); +//- rjf: thread register cache reading +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); + +//////////////////////////////// +//~ rjf: Unwinding Functions + +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 + +internal void ctrl_halt(void); + +//////////////////////////////// +//~ rjf: Shared Accessor Functions + +//- 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); 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: 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, 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 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, 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-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/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 734b35f5..8eb51f1d 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_arch(CTRL_MachineID machine, DMN_Handle process, Rng1U64 vaddr_range, Architecture arch) { DASM_Handle result = {0}; if(machine != 0 && process.u64[0] != 0) @@ -195,8 +195,9 @@ dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, for(DASM_Entity *e = slot->first; e != 0; e = e->next) { if(e->machine_id == machine && - ctrl_handle_match(e->process, process) && - MemoryMatchStruct(&e->vaddr_range, &vaddr_range)) + dmn_handle_match(e->process, process) && + 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, CTRL_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)); @@ -389,7 +391,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; @@ -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 a49412e0..6bf4450c 100644 --- a/src/dasm/dasm.h +++ b/src/dasm/dasm.h @@ -77,8 +77,9 @@ struct DASM_Entity // rjf: key info CTRL_MachineID machine_id; - CTRL_Handle process; + DMN_Handle process; Rng1U64 vaddr_range; + Architecture arch; U64 id; // rjf: top-level info @@ -114,7 +115,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 +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, CTRL_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/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 0beedca4..e0e3860e 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 @@ -54,6 +68,7 @@ struct DMN_Event DMN_Handle process; DMN_Handle thread; DMN_Handle module; + Architecture arch; U64 address; U64 size; String8 string; @@ -159,43 +174,62 @@ 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) internal void dmn_init(void); //////////////////////////////// -//~ rjf: @dmn_os_hooks Running/Halting (Implemented Per-OS) +//~ 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); +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) -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 Introspection Functions (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); +//- rjf: 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 Process/Thread Reads/Writes (Implemented Per-OS) +//- 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); +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); - -//////////////////////////////// -//~ rjf: @dmn_os_hooks System Process Listing (Implemented Per-OS) +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); +internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block); +//- 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 2f42d85f..ab320c3d 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; @@ -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; } @@ -581,9 +582,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 +826,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; //////////////////////////// @@ -951,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; } @@ -1041,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; } @@ -1068,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); @@ -1103,18 +1109,203 @@ dmn_init(void) } //////////////////////////////// -//~ rjf: @dmn_os_hooks Running/Halting (Implemented Per-OS) +//~ 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 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) +{ + Temp scratch = scratch_begin(0, 0); + U32 result = 0; + DMN_AccessScope + { + //- 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 B32 +dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid) +{ + B32 result = 0; + DMN_AccessScope if(DebugActiveProcess((DWORD)pid)) + { + result = 1; + dmn_w32_shared->new_process_pending = 1; + } + return result; +} + +internal B32 +dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code) +{ + B32 result = 0; + DMN_AccessScope + { + 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_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process) +{ + B32 result = 0; + DMN_AccessScope + { + 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) +dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) { DMN_EventList events = {0}; + dmn_access_open(); ////////////////////////////// //- rjf: determine event generation path // typedef enum DMN_W32_EventGenPath { + DMN_W32_EventGenPath_NotAttached, DMN_W32_EventGenPath_Run, DMN_W32_EventGenPath_DetachProcesses, } @@ -1124,12 +1315,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 // @@ -1148,9 +1368,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 @@ -1198,7 +1419,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;} @@ -1219,7 +1440,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;} @@ -1345,7 +1566,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; @@ -1363,6 +1584,9 @@ 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); + ins_atomic_u64_inc_eval(&dmn_w32_shared->mem_gen); + ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); } } @@ -1432,6 +1656,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); @@ -1462,6 +1687,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 +1697,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 +1707,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 +1771,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 +1802,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 +1857,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 +1869,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); @@ -1765,7 +1997,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); } @@ -1980,7 +2212,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; } @@ -2043,9 +2275,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 @@ -2120,13 +2353,17 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) }break; } + dmn_access_close(); return events; } +//////////////////////////////// +//~ rjf: @dmn_os_hooks Halting (Implemented Per-OS) + 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; @@ -2151,206 +2388,128 @@ 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) + 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: non-blocking-control-thread access barriers + +internal B32 +dmn_access_open(void) +{ + B32 result = 0; + if(dmn_w32_ctrl_thread) { - 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); - 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); + result = 1; } 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) -{ - B32 result = 0; - if(DebugActiveProcess((DWORD)pid)) - { - result = 1; - dmn_w32_shared->new_process_pending = 1; + os_mutex_take(dmn_w32_shared->access_mutex); + result = !dmn_w32_shared->access_run_state; } return result; } -internal B32 -dmn_kill_process(DMN_Handle process, U32 exit_code) +internal void +dmn_access_close(void) { - B32 result = 0; - DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); - if(TerminateProcess(process_entity->handle, exit_code)) + if(!dmn_w32_ctrl_thread) { - result = 1; - } - 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); + os_mutex_drop(dmn_w32_shared->access_mutex); } } -//////////////////////////////// -//~ 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) { - 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; } //- rjf: threads +internal Architecture +dmn_arch_from_thread(DMN_Handle handle) +{ + 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; - U64 result = 0; - 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_arm64: - case Architecture_arm32: - case Architecture_COUNT: - {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; @@ -2360,10 +2519,30 @@ 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; + 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; } @@ -2371,21 +2550,28 @@ 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; } -//////////////////////////////// -//~ rjf: @dmn_os_hooks System Process Listing (Implemented Per-OS) +//- rjf: system process listing internal void dmn_process_iter_begin(DMN_ProcessIter *iter) diff --git a/src/demon2/win32/demon2_core_win32.h b/src/demon2/win32/demon2_core_win32.h index 572691c6..15e2e3ac 100644 --- a/src/demon2/win32/demon2_core_win32.h +++ b/src/demon2/win32/demon2_core_win32.h @@ -194,6 +194,15 @@ 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; + U64 reg_gen; + // rjf: detaching info Arena *detach_arena; DMN_HandleList detach_processes; @@ -227,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/df/core/df_core.c b/src/df/core/df_core.c index a7ff9ff9..df6ae29f 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; } @@ -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) @@ -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); } @@ -2710,11 +2712,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; @@ -2824,14 +2824,14 @@ 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(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); // rjf: ip => machine code 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, os_now_microseconds()+5000); + machine_code = machine_code_slice.data; } // rjf: build traps if machine code was read successfully @@ -2863,7 +2863,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(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); // rjf: ip => line vaddr range Rng1U64 line_vaddr_rng = {0}; @@ -2897,8 +2897,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, os_now_microseconds()+50000); + machine_code = machine_code_slice.data; } // rjf: machine code => ctrl flow analysis @@ -2988,7 +2988,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(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); // rjf: ip => line vaddr range Rng1U64 line_vaddr_rng = {0}; @@ -3022,8 +3022,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, os_now_microseconds()+5000); + machine_code = machine_code_slice.data; } // rjf: machine code => ctrl flow analysis @@ -3379,27 +3379,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 @@ -3565,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()) { - U64 bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, &tls_index); - if(bytes_read < sizeof(U64)) - { - tls_index = 0; - } - } - - //- 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(); @@ -3654,43 +3634,6 @@ df_architecture_from_entity(DF_Entity *entity) return entity->arch; } -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); - return unwind; -} - -internal U64 -df_rip_from_thread(DF_Entity *thread) -{ - U64 result = ctrl_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) { @@ -3718,26 +3661,33 @@ 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, 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); // rjf: early mutation of unwind cache for immediate frontend effect 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) + DF_RunUnwindCache *unwind_cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)]; + 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; + } } } } + scratch_end(scratch); return result; } @@ -4134,7 +4084,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(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); @@ -6188,37 +6138,57 @@ 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) + DF_Handle handle = df_handle_from_entity(thread); + U64 hash = df_hash_from_string(str8_struct(&handle)); + for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->unwind_caches); cache_idx += 1) { - 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]; + 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) + { + break; + } + 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)) { - result = n->unwind; + 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; } } } - ProfEnd(); return result; } 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; } @@ -6226,14 +6196,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(df_state->ctrl_entity_store, 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; @@ -6243,13 +6220,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; @@ -6265,14 +6247,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; } @@ -6282,13 +6272,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; @@ -6316,9 +6311,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(); @@ -6330,13 +6326,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; @@ -6364,9 +6365,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(); @@ -6396,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; @@ -6417,7 +6420,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")); } @@ -6434,10 +6437,22 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist) } // rjf: set up per-run caches - df_state->unwind_cache.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(); + for(U64 idx = 0; idx < ArrayCount(df_state->unwind_caches); idx += 1) + { + df_state->unwind_caches[idx].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(); + } + 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; @@ -6542,11 +6557,12 @@ 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); + 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; @@ -6586,7 +6602,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(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); @@ -6895,7 +6911,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); @@ -6903,72 +6919,55 @@ 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) && + //- 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; - break; - } - } - if(good) - { - df_state->unwind_cache_memgen_idx = new_memgen_idx; - df_state->unwind_cache_reggen_idx = new_reggen_idx; - } - } - - //- 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) && - !df_ctrl_targets_running()) - { - DF_RunTLSBaseCache *cache = &df_state->tls_base_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; - df_state->tls_base_cache_reggen_idx = new_reggen_idx; - df_state->tls_base_cache_memgen_idx = new_memgen_idx; + 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_reg_gen || + df_state->tls_base_cache_memgen_idx != new_mem_gen) && + !df_ctrl_targets_running()) + { + 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; + 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; + 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; - 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; + 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; - df_state->member_cache_reggen_idx = new_reggen_idx; + df_state->member_cache_reggen_idx = new_reg_gen; } scratch_end(scratch); @@ -7515,7 +7514,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); @@ -7523,7 +7522,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..7ba02bf4 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; @@ -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 @@ -1136,14 +1135,18 @@ 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; + 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; + DF_RunLocalsCache member_caches[2]; + U64 member_cache_gen; // rjf: eval view cache DF_EvalViewCache eval_view_cache; @@ -1179,6 +1182,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; @@ -1447,7 +1451,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 +1472,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); @@ -1533,7 +1537,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); @@ -1547,9 +1550,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 3bd9d716..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); @@ -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..da3d8842 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 @@ -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); diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index a93de0d0..a6f1eacb 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); @@ -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); @@ -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) @@ -7552,8 +7555,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 @@ -7755,7 +7759,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); @@ -7766,8 +7770,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 +8344,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/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; diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index 3d325472..eb035e73 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -1,13 +1,18 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Demon2 Pass Tasks +// +// [ ] TLS eval -> in-process-memory EXE info +// [ ] unwinding -> in-process-memory EXE info +// [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 // -// [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 // [ ] 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 @@ -79,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) diff --git a/src/raddbg/raddbg_main.cpp b/src/raddbg/raddbg_main.cpp index 24565311..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 @@ -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" 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;`; 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 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)) &&