double buffer locals cache & tls base cache; introduce synchronizing mechanism for run vs. non-run ctrl thread states, to only attempt demon reads/queries during non-running times

This commit is contained in:
Ryan Fleury
2024-03-22 13:32:22 -07:00
parent 3994adae92
commit e9129975e3
7 changed files with 127 additions and 35 deletions
+32 -15
View File
@@ -800,6 +800,7 @@ ctrl_init(void)
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
ctrl_state = push_array(arena, CTRL_State, 1); ctrl_state = push_array(arena, CTRL_State, 1);
ctrl_state->arena = arena; ctrl_state->arena = arena;
ctrl_state->ctrl_run_mutex = os_mutex_alloc();
for(Architecture arch = (Architecture)0; arch < Architecture_COUNT; arch = (Architecture)(arch+1)) for(Architecture arch = (Architecture)0; arch < Architecture_COUNT; arch = (Architecture)(arch+1))
{ {
String8 *reg_names = regs_reg_code_string_table_from_architecture(arch); String8 *reg_names = regs_reg_code_string_table_from_architecture(arch);
@@ -1344,12 +1345,17 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_MachineID machine_id,
if(node) if(node)
{ {
U64 current_reg_gen = dmn_reg_gen(); U64 current_reg_gen = dmn_reg_gen();
if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(thread, result)) B32 need_stale = 1;
if(node->reg_gen != current_reg_gen)
{ {
node->reg_gen = current_reg_gen; OS_MutexScope(ctrl_state->ctrl_run_mutex) if(ctrl_state->ctrl_run_state == 0 && dmn_thread_read_reg_block(thread, result))
MemoryCopy(node->block, result, reg_block_size); {
need_stale = 0;
node->reg_gen = current_reg_gen;
MemoryCopy(node->block, result, reg_block_size);
}
} }
else if(need_stale)
{ {
MemoryCopy(result, node->block, reg_block_size); MemoryCopy(result, node->block, reg_block_size);
} }
@@ -1719,6 +1725,12 @@ ctrl_thread__entry_point(void *p)
//- rjf: get next messages //- rjf: get next messages
CTRL_MsgList msgs = ctrl_u2c_pop_msgs(scratch.arena); CTRL_MsgList msgs = ctrl_u2c_pop_msgs(scratch.arena);
//- rjf: begin run state
OS_MutexScope(ctrl_state->ctrl_run_mutex)
{
ctrl_state->ctrl_run_state = 1;
}
//- rjf: process messages //- rjf: process messages
{ {
B32 done = 0; B32 done = 0;
@@ -1753,6 +1765,12 @@ ctrl_thread__entry_point(void *p)
} }
} }
} }
//- rjf: end run state
OS_MutexScope(ctrl_state->ctrl_run_mutex)
{
ctrl_state->ctrl_run_state = 0;
}
} }
scratch_end(scratch); scratch_end(scratch);
@@ -2879,7 +2897,7 @@ ctrl_thread__run(CTRL_Msg *msg)
if(process->kind != CTRL_EntityKind_Process) { continue; } if(process->kind != CTRL_EntityKind_Process) { continue; }
for(CTRL_Entity *thread = process->first; thread != &ctrl_entity_nil; thread = thread->next) for(CTRL_Entity *thread = process->first; thread != &ctrl_entity_nil; thread = thread->next)
{ {
U64 rip = ctrl_query_cached_rip_from_thread(thread->machine_id, thread->handle); U64 rip = dmn_rip_from_thread(thread->handle);
// rjf: determine if thread is frozen // rjf: determine if thread is frozen
B32 thread_is_frozen = !msg->freeze_state_is_frozen; B32 thread_is_frozen = !msg->freeze_state_is_frozen;
@@ -2998,7 +3016,7 @@ ctrl_thread__run(CTRL_Msg *msg)
// //
if(stop_event == 0) if(stop_event == 0)
{ {
U64 sp_check_value = ctrl_query_cached_rsp_from_thread(CTRL_MachineID_Local, target_thread); U64 sp_check_value = dmn_rsp_from_thread(target_thread);
B32 spoof_mode = 0; B32 spoof_mode = 0;
CTRL_Spoof spoof = {0}; CTRL_Spoof spoof = {0};
for(;;) for(;;)
@@ -3085,9 +3103,7 @@ ctrl_thread__run(CTRL_Msg *msg)
// //
CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->thread); CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->thread);
Architecture arch = thread->arch; Architecture arch = thread->arch;
U64 reg_size = regs_block_size_from_architecture(arch); U64 thread_rip_vaddr = dmn_rsp_from_thread(event->thread);
void *thread_regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, CTRL_MachineID_Local, event->thread);
U64 thread_rip_vaddr = regs_rip_from_arch_block(arch, thread_regs_block);
DMN_Handle module = {0}; DMN_Handle module = {0};
String8 module_name = {0}; String8 module_name = {0};
U64 module_base_vaddr = 0; U64 module_base_vaddr = 0;
@@ -3226,15 +3242,16 @@ ctrl_thread__run(CTRL_Msg *msg)
if(bytecode.size != 0) if(bytecode.size != 0)
{ {
U64 module_base = module_base_vaddr; U64 module_base = module_base_vaddr;
U64 tls_base = ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_MachineID_Local, event->thread); U64 tls_base = dmn_tls_root_vaddr_from_thread(event->thread);
EVAL_Machine machine = {0}; EVAL_Machine machine = {0};
machine.u = &event->process; machine.u = &event->process;
machine.arch = arch; machine.arch = arch;
machine.memory_read = ctrl_eval_memory_read; machine.memory_read = ctrl_eval_memory_read;
machine.reg_data = thread_regs_block; machine.reg_size = regs_block_size_from_architecture(arch);
machine.reg_size = reg_size; machine.reg_data = push_array(scratch.arena, U8, machine.reg_size);
machine.module_base = &module_base; machine.module_base = &module_base;
machine.tls_base = &tls_base; machine.tls_base = &tls_base;
dmn_thread_read_reg_block(event->thread, machine.reg_data);
eval = eval_interpret(&machine, bytecode); eval = eval_interpret(&machine, bytecode);
} }
if(eval.code == EVAL_ResultCode_Good && eval.value.u64 == 0) if(eval.code == EVAL_ResultCode_Good && eval.value.u64 == 0)
@@ -3335,7 +3352,7 @@ ctrl_thread__run(CTRL_Msg *msg)
B32 stack_pointer_matches = 0; B32 stack_pointer_matches = 0;
if(use_trap_net_logic) if(use_trap_net_logic)
{ {
U64 sp = ctrl_query_cached_rsp_from_thread(CTRL_MachineID_Local, target_thread); U64 sp = dmn_rsp_from_thread(target_thread);
stack_pointer_matches = (sp == sp_check_value); stack_pointer_matches = (sp == sp_check_value);
} }
@@ -3383,7 +3400,7 @@ ctrl_thread__run(CTRL_Msg *msg)
{ {
// rjf: setup spoof mode // rjf: setup spoof mode
begin_spoof_mode = 1; begin_spoof_mode = 1;
U64 spoof_sp = ctrl_query_cached_rsp_from_thread(CTRL_MachineID_Local, target_thread); U64 spoof_sp = dmn_rsp_from_thread(target_thread);
spoof_mode = 1; spoof_mode = 1;
spoof.process = target_process; spoof.process = target_process;
spoof.thread = target_thread; spoof.thread = target_thread;
@@ -3401,7 +3418,7 @@ ctrl_thread__run(CTRL_Msg *msg)
if(stack_pointer_matches) if(stack_pointer_matches)
{ {
save_stack_pointer = 1; save_stack_pointer = 1;
sp_check_value = ctrl_query_cached_rsp_from_thread(CTRL_MachineID_Local, target_thread); sp_check_value = dmn_rsp_from_thread(target_thread);
} }
} }
} }
+4
View File
@@ -491,6 +491,10 @@ struct CTRL_State
EVAL_String2NumMap arch_string2reg_tables[Architecture_COUNT]; EVAL_String2NumMap arch_string2reg_tables[Architecture_COUNT];
EVAL_String2NumMap arch_string2alias_tables[Architecture_COUNT]; EVAL_String2NumMap arch_string2alias_tables[Architecture_COUNT];
// rjf: access locking mechanism
OS_Handle ctrl_run_mutex;
B32 ctrl_run_state;
// rjf: caches // rjf: caches
CTRL_ProcessMemoryCache process_memory_cache; CTRL_ProcessMemoryCache process_memory_cache;
CTRL_ThreadRegCache thread_reg_cache; CTRL_ThreadRegCache thread_reg_cache;
+35
View File
@@ -116,3 +116,38 @@ dmn_event_list_push(Arena *arena, DMN_EventList *list)
DMN_Event *result = &n->v; DMN_Event *result = &n->v;
return result; 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;
}
+6
View File
@@ -160,6 +160,12 @@ internal DMN_HandleArray dmn_handle_array_copy(Arena *arena, DMN_HandleArray *sr
//- rjf: event list building //- rjf: event list building
internal DMN_Event *dmn_event_list_push(Arena *arena, DMN_EventList *list); 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) //~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS)
+45 -17
View File
@@ -6217,13 +6217,18 @@ internal U64
df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr) df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr)
{ {
U64 result = 0; 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; DF_RunTLSBaseCache *cache = &df_state->tls_base_caches[(df_state->tls_base_cache_gen+cache_idx)%ArrayCount(df_state->tls_base_caches)];
if(cache->slots_count == 0) if(cache_idx == 0 && cache->slots_count == 0)
{ {
cache->slots_count = 256; cache->slots_count = 256;
cache->slots = push_array(cache->arena, DF_RunTLSBaseCacheSlot, cache->slots_count); 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); 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 hash = df_hash_from_seed_string(df_hash_from_string(str8_struct(&handle)), str8_struct(&rip_vaddr));
U64 slot_idx = hash%cache->slots_count; U64 slot_idx = hash%cache->slots_count;
@@ -6239,14 +6244,22 @@ df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 roo
} }
if(node == 0) if(node == 0)
{ {
node = push_array(cache->arena, DF_RunTLSBaseCacheNode, 1); U64 tls_base_vaddr = df_tls_base_vaddr_from_process_root_rip(process, root_vaddr, rip_vaddr);
SLLQueuePush_N(slot->first, slot->last, node, hash_next); if(tls_base_vaddr != 0)
node->process = handle; {
node->root_vaddr = root_vaddr; node = push_array(cache->arena, DF_RunTLSBaseCacheNode, 1);
node->rip_vaddr = rip_vaddr; SLLQueuePush_N(slot->first, slot->last, node, hash_next);
node->tls_base_vaddr = df_tls_base_vaddr_from_process_root_rip(process, root_vaddr, rip_vaddr); 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; return result;
} }
@@ -6256,13 +6269,18 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff)
{ {
ProfBeginFunction(); ProfBeginFunction();
EVAL_String2NumMap *map = &eval_string2num_map_nil; 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; DF_RunLocalsCache *cache = &df_state->locals_caches[(df_state->locals_cache_gen+cache_idx)%ArrayCount(df_state->locals_caches)];
if(cache->table_size == 0) if(cache_idx == 0 && cache->table_size == 0)
{ {
cache->table_size = 256; cache->table_size = 256;
cache->table = push_array(cache->arena, DF_RunLocalsCacheSlot, cache->table_size); 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); DF_Handle handle = df_handle_from_entity(binary);
U64 hash = df_hash_from_string(str8_struct(&handle)); U64 hash = df_hash_from_string(str8_struct(&handle));
U64 slot_idx = hash % cache->table_size; U64 slot_idx = hash % cache->table_size;
@@ -6290,9 +6308,10 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff)
} }
dbgi_scope_close(scope); dbgi_scope_close(scope);
} }
if(node != 0) if(node != 0 && node->locals_map->slots_count != 0)
{ {
map = node->locals_map; map = node->locals_map;
break;
} }
} }
ProfEnd(); ProfEnd();
@@ -6413,8 +6432,14 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist)
{ {
df_state->unwind_caches[idx].arena = arena_alloc(); df_state->unwind_caches[idx].arena = arena_alloc();
} }
df_state->tls_base_cache.arena = arena_alloc(); for(U64 idx = 0; idx < ArrayCount(df_state->tls_base_caches); idx += 1)
df_state->locals_cache.arena = arena_alloc(); {
df_state->tls_base_caches[idx].arena = arena_alloc();
}
for(U64 idx = 0; idx < ArrayCount(df_state->locals_caches); idx += 1)
{
df_state->locals_caches[idx].arena = arena_alloc();
}
df_state->member_cache.arena = arena_alloc(); df_state->member_cache.arena = arena_alloc();
// rjf: set up eval view cache // rjf: set up eval view cache
@@ -6901,7 +6926,8 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
df_state->tls_base_cache_memgen_idx != new_mem_gen) && df_state->tls_base_cache_memgen_idx != new_mem_gen) &&
!df_ctrl_targets_running()) !df_ctrl_targets_running())
{ {
DF_RunTLSBaseCache *cache = &df_state->tls_base_cache; df_state->tls_base_cache_gen += 1;
DF_RunTLSBaseCache *cache = &df_state->tls_base_caches[df_state->tls_base_cache_gen%ArrayCount(df_state->tls_base_caches)];
arena_clear(cache->arena); arena_clear(cache->arena);
cache->slots_count = 0; cache->slots_count = 0;
cache->slots = 0; cache->slots = 0;
@@ -6910,9 +6936,11 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
} }
//- rjf: clear locals cache //- rjf: clear locals cache
if(df_state->locals_cache_reggen_idx != new_reg_gen && !df_ctrl_targets_running()) if(df_state->locals_cache_reggen_idx != new_reg_gen &&
!df_ctrl_targets_running())
{ {
DF_RunLocalsCache *cache = &df_state->locals_cache; df_state->locals_cache_gen += 1;
DF_RunLocalsCache *cache = &df_state->locals_caches[df_state->locals_cache_gen%ArrayCount(df_state->locals_caches)];
arena_clear(cache->arena); arena_clear(cache->arena);
cache->table_size = 0; cache->table_size = 0;
cache->table = 0; cache->table = 0;
+4 -2
View File
@@ -1139,9 +1139,11 @@ struct DF_State
U64 unwind_cache_gen; U64 unwind_cache_gen;
U64 tls_base_cache_reggen_idx; U64 tls_base_cache_reggen_idx;
U64 tls_base_cache_memgen_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; U64 locals_cache_reggen_idx;
DF_RunLocalsCache locals_cache; DF_RunLocalsCache locals_caches[2];
U64 locals_cache_gen;
U64 member_cache_reggen_idx; U64 member_cache_reggen_idx;
DF_RunLocalsCache member_cache; DF_RunLocalsCache member_cache;
+1 -1
View File
@@ -6244,7 +6244,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly)
DF_Entity *thread = thread_n->entity; DF_Entity *thread = thread_n->entity;
U64 unwind_count = (thread == selected_thread) ? ctrl_ctx.unwind_count : 0; U64 unwind_count = (thread == selected_thread) ? ctrl_ctx.unwind_count : 0;
U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count);
if(contains_1u64(disasm_vaddr_rng, rip_vaddr)) ProfScope("in-range rip scan") if(contains_1u64(disasm_vaddr_rng, rip_vaddr))
{ {
U64 rip_off = rip_vaddr - disasm_vaddr_rng.min; U64 rip_off = rip_vaddr - disasm_vaddr_rng.min;
S64 line_num = dasm_inst_array_idx_from_off__linear_scan(&insts, rip_off)+1; S64 line_num = dasm_inst_array_idx_from_off__linear_scan(&insts, rip_off)+1;