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