further tightening up of win32 demon run path; take a few fastpaths on x64; speeds up conditional breakpoints

This commit is contained in:
Ryan Fleury
2024-06-14 09:50:33 -07:00
parent fb9824dc24
commit 723c7c5d4d
4 changed files with 130 additions and 35 deletions
+103 -19
View File
@@ -580,6 +580,7 @@ internal B32
dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block)
{
B32 result = 0;
ProfBeginFunction();
switch(arch)
{
////////////////////////////
@@ -817,6 +818,7 @@ dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block)
scratch_end(scratch);
}break;
}
ProfEnd();
return result;
}
@@ -824,6 +826,7 @@ internal B32
dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block)
{
B32 result = 0;
ProfBeginFunction();
switch(arch)
{
////////////////////////////
@@ -1050,6 +1053,7 @@ dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block
}break;
}
ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen);
ProfEnd();
return result;
}
@@ -1381,6 +1385,34 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
{
Temp scratch = scratch_begin(&arena, 1);
//////////////////////////
//- rjf: get single step thread's context (x64 single-step-set fast path)
//
CONTEXT *single_step_thread_ctx = 0;
if(!dmn_handle_match(ctrls->single_step_thread, dmn_handle_zero()))
{
DMN_W32_Entity *thread = dmn_w32_entity_from_handle(ctrls->single_step_thread);
Architecture arch = thread->arch;
switch(arch)
{
default:{}break;
case Architecture_x64:
{
U32 ctx_flags = DMN_W32_CTX_X64|DMN_W32_CTX_INTEL_CONTROL;
DWORD size = 0;
InitializeContext(0, ctx_flags, 0, &size);
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
void *ctx_memory = push_array(scratch.arena, U8, size);
if(!InitializeContext(ctx_memory, ctx_flags, &single_step_thread_ctx, &size))
{
single_step_thread_ctx = 0;
}
}
}break;
}
}
//////////////////////////
//- rjf: set single step bit
//
@@ -1398,7 +1430,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
case Architecture_arm32:
{NotImplemented;}break;
//- rjf: x86/64
//- rjf: x86
case Architecture_x86:
{
REGS_RegBlockX86 regs = {0};
@@ -1406,12 +1438,22 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
regs.eflags.u32 |= 0x100;
dmn_thread_write_reg_block(ctrls->single_step_thread, &regs);
}break;
//- rjf: x64
case Architecture_x64:
{
REGS_RegBlockX64 regs = {0};
dmn_thread_read_reg_block(ctrls->single_step_thread, &regs);
regs.rflags.u64 |= 0x100;
dmn_thread_write_reg_block(ctrls->single_step_thread, &regs);
if(!GetThreadContext(thread->handle, single_step_thread_ctx))
{
single_step_thread_ctx = 0;
}
if(single_step_thread_ctx != 0)
{
U64 rflags = single_step_thread_ctx->EFlags|0x2;
U64 new_rflags = rflags |= 0x100;
single_step_thread_ctx->EFlags = new_rflags;
SetThreadContext(thread->handle, single_step_thread_ctx);
ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen);
}
}break;
}
}
@@ -1983,19 +2025,53 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
B32 should_do_rollback = (hit_user_trap || (is_trap && !hit_explicit_trap));
//- rjf: roll back thread's instruction pointer
U64 post_trap_rip = 0;
if(should_do_rollback)
if(should_do_rollback) ProfScope("roll back thread's instruction pointer")
{
Temp temp = temp_begin(scratch.arena);
U64 regs_block_size = regs_block_size_from_architecture(thread->arch);
void *regs_block = push_array(scratch.arena, U8, regs_block_size);
if(dmn_w32_thread_read_reg_block(thread->arch, thread->handle, regs_block))
switch(thread->arch)
{
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->handle, regs_block);
//- rjf: default, general path
default:
{
Temp temp = temp_begin(scratch.arena);
U64 regs_block_size = regs_block_size_from_architecture(thread->arch);
void *regs_block = push_array(scratch.arena, U8, regs_block_size);
if(dmn_w32_thread_read_reg_block(thread->arch, thread->handle, regs_block))
{
regs_arch_block_write_rip(thread->arch, regs_block, instruction_pointer);
dmn_w32_thread_write_reg_block(thread->arch, thread->handle, regs_block);
}
temp_end(temp);
}break;
//- rjf: x64 (fastpath)
case Architecture_x64:
{
CONTEXT *ctx = 0;
U32 ctx_flags = DMN_W32_CTX_X64|DMN_W32_CTX_INTEL_CONTROL;
DWORD size = 0;
InitializeContext(0, ctx_flags, 0, &size);
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
void *ctx_memory = push_array(scratch.arena, U8, size);
if(!InitializeContext(ctx_memory, ctx_flags, &ctx, &size))
{
ctx = 0;
}
}
if(!GetThreadContext(thread->handle, ctx))
{
ctx = 0;
}
if(ctx != 0)
{
U64 rip = ctx->Rip;
U64 new_rip = instruction_pointer;
ctx->Rip = new_rip;
SetThreadContext(thread->handle, ctx);
ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen);
}
}break;
}
temp_end(temp);
}
//- rjf: not a user trap, not an explicit trap, then it's a trap that
@@ -2347,10 +2423,18 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
}break;
case Architecture_x64:
{
REGS_RegBlockX64 regs = {0};
dmn_thread_read_reg_block(ctrls->single_step_thread, &regs);
regs.rflags.u64 &= ~0x100;
dmn_thread_write_reg_block(ctrls->single_step_thread, &regs);
if(!GetThreadContext(thread->handle, single_step_thread_ctx))
{
single_step_thread_ctx = 0;
}
if(ctx != 0)
{
U64 rflags = single_step_thread_ctx->EFlags|0x2;
U64 new_rflags = rflags &= ~0x100;
single_step_thread_ctx->EFlags = new_rflags;
SetThreadContext(thread->handle, single_step_thread_ctx);
ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen);
}
}break;
}
}
+5 -5
View File
@@ -61,11 +61,11 @@
#define DMN_W32_CTX_X86 0x00010000
#define DMN_W32_CTX_X64 0x00100000
#define DMN_W32_CTX_INTEL_CONTROL 0x0001
#define DMN_W32_CTX_INTEL_INTEGER 0x0002
#define DMN_W32_CTX_INTEL_SEGMENTS 0x0004
#define DMN_W32_CTX_INTEL_FLOATS 0x0008
#define DMN_W32_CTX_INTEL_DEBUG 0x0010
#define DMN_W32_CTX_INTEL_CONTROL 0x0001 // segss, rsp, segcs, rip, and rflags
#define DMN_W32_CTX_INTEL_INTEGER 0x0002 // rax, rcx, rdx, rbx, rbp, rsi, rdi, and r8-r15
#define DMN_W32_CTX_INTEL_SEGMENTS 0x0004 // segds, seges, segfs, and seggs
#define DMN_W32_CTX_INTEL_FLOATS 0x0008 // xmm0-xmm15
#define DMN_W32_CTX_INTEL_DEBUG 0x0010 // dr0-dr3 and dr6-dr7
#define DMN_W32_CTX_INTEL_EXTENDED 0x0020
#define DMN_W32_CTX_INTEL_XSTATE 0x0040