diff --git a/src/demon/test/demon_attach.cpp b/src/demon/test/demon_attach.cpp deleted file mode 100644 index ca9fb1ea..00000000 --- a/src/demon/test/demon_attach.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -// exe // - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "demon/demon_inc.h" -#include "syms_helpers/syms_internal_overrides.h" -#include "syms/syms_inc.h" -#include "syms_helpers/syms_helpers.h" - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "demon/demon_inc.c" -#include "syms_helpers/syms_internal_overrides.c" -#include "syms/syms_inc.c" -#include "syms_helpers/syms_helpers.c" - -int -main(int argument_count, char **arguments) -{ - os_init(argument_count, arguments); - Arena *arena = arena_alloc(); - demon_init(); - - //- rjf: find PID of mule_loop.exe - String8 attach_process_name = str8_lit("mule_loop.exe"); - U32 pid = 0; - { - DEMON_ProcessIter it = {0}; - demon_proc_iter_begin(&it); - for(DEMON_ProcessInfo info = {0}; demon_proc_iter_next(arena, &it, &info);) - { - if(str8_match(info.name, attach_process_name, 0)) - { - pid = info.pid; - break; - } - } - demon_proc_iter_end(&it); - } - - //- rjf: attach - B32 attach_good = demon_attach_process(pid); - - //- rjf: get events - DEMON_RunCtrls ctrls = {0}; - DEMON_EventList events = demon_run(arena, ctrls); - for(DEMON_Event *event = events.first; event != 0; event = event->next) - { - int x = 0; - } - -#if 0 - //- rjf: try to break in the loop - DEMON_RunCtrls ctrls = {0}; - DEMON_Trap trap = {0}; - { - U64 loop_bp = 0x0000000140001074; - ctrls.trap_count = 1; - ctrls.traps = &trap; - } -#endif -} diff --git a/src/demon/test/demon_regs_test.cpp b/src/demon/test/demon_regs_test.cpp deleted file mode 100644 index c5ef06b5..00000000 --- a/src/demon/test/demon_regs_test.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "demon/demon_inc.h" -#include "syms_helpers/syms_internal_overrides.h" -#include "syms/syms_inc.h" -#include "syms_helpers/syms_helpers.h" - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "demon/demon_inc.c" -#include "syms_helpers/syms_internal_overrides.c" -#include "syms/syms_inc.c" -#include "syms_helpers/syms_helpers.c" - -internal SYMS_String8 -file_load_func_for_syms(void *user, SYMS_Arena *arena, SYMS_String8 file_name){ - String8 data = os_read_file(arena, str8_from_syms(file_name)); - SYMS_String8 result = syms_from_str8(data); - return(result); -} - -int -main(int argument_count, char **arguments) -{ - os_init(argument_count, arguments); - Temp scratch = scratch_begin(0, 0); - - // setup - demon_init(); - - // parse arguments - String8 executable_file_name = {0}; - U64 bp_address = 0; - - { - String8List command_line_arguments = os_get_command_line_arguments(); - CmdLine cmd_line = cmd_line_from_string_list(scratch.arena, command_line_arguments); - if (cmd_line.inputs.first != 0){ - executable_file_name = cmd_line.inputs.first->string; - } - String8 bp_string = cmd_line_string(cmd_line, str8_lit("bp")); - try_u64_from_str8_c_rules(bp_string, &bp_address); - } - - // check parameters - if (bp_address == 0 || executable_file_name.size == 0){ - printf("bad parameters\n"); - exit(0); - } - - // demon launch - OS_LaunchOptions launch_opts = {0}; - str8_list_push(scratch.arena, &launch_opts.cmd_line, executable_file_name); - launch_opts.path = os_get_path(scratch.arena, OS_SystemPath_Current); - U32 process_id = demon_launch_process(&launch_opts); - if (process_id == 0){ - printf("could not launch: '%.*s'\n", str8_varg(executable_file_name)); - exit(0); - } - - // demon loop - { - DEMON_Handle process = 0; - DEMON_Handle thread = 0; - - B32 hit_bp = false; - U64 single_step_counter = 0; - - U64 counter = 0; - for (;;){ - Temp temp = temp_begin(scratch.arena); - - DEMON_RunCtrls run_controls = {0}; - DEMON_Trap traps[1]; - - if (!hit_bp){ - if (process != 0){ - run_controls.trap_count = 1; - run_controls.traps = traps; - run_controls.traps[0].process = process; - run_controls.traps[0].address = bp_address; - } - } - else{ - run_controls.single_step_thread = thread; - } - - DEMON_EventList events = demon_run(temp.arena, run_controls); - - for (DEMON_Event *event = events.first; - event != 0; - event = event->next, counter += 1){ - // update tracking state - switch (event->kind){ - case DEMON_EventKind_CreateProcess: - { - process = event->process; - }break; - - case DEMON_EventKind_ExitProcess: - { - if (event->process == process){ - process = 0; - } - }break; - - case DEMON_EventKind_CreateThread: - { - thread = event->thread; - }break; - - case DEMON_EventKind_Breakpoint: - { - hit_bp = true; - }break; - - case DEMON_EventKind_SingleStep: - { - single_step_counter += 1; - - SYMS_RegX64 regs1 = {0}; - demon_read_x64_regs(thread, ®s1); - demon_write_x64_regs(thread, ®s1); - SYMS_RegX64 regs2 = {0}; - demon_read_x64_regs(thread, ®s2); - if (!MemoryMatchStruct(®s1, ®s2)){ - printf("mismatch at single_step_counter=%llu\n", single_step_counter); - } - - if (single_step_counter == 1000){ - goto end_loop; - } - }break; - - case DEMON_EventKind_NotAttached: - { - fprintf(stderr, "not attached - exiting\n"); - goto end_loop; - }break; - - case DEMON_EventKind_NotInitialized: - case DEMON_EventKind_UnexpectedFailure: - { - fprintf(stderr, "unexpected error - exiting\n"); - goto end_loop; - }break; - } - } - - goto end_it; - end_loop: - temp_end(temp); - goto loop_exit; - end_it:; - } - - loop_exit:; - } - - printf("[done]\n"); - scratch_end(scratch); -} - diff --git a/src/demon/test/demon_scratch.cpp b/src/demon/test/demon_scratch.cpp deleted file mode 100644 index beb1cc40..00000000 --- a/src/demon/test/demon_scratch.cpp +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "demon/demon_inc.h" -#include "syms_helpers/syms_internal_overrides.h" -#include "syms/syms_inc.h" -#include "syms_helpers/syms_helpers.h" - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "demon/demon_inc.c" -#include "syms_helpers/syms_internal_overrides.c" -#include "syms/syms_inc.c" -#include "syms_helpers/syms_helpers.c" - -internal SYMS_String8 -file_load_func_for_syms(void *user, SYMS_Arena *arena, SYMS_String8 file_name){ - String8 data = os_read_file(arena, str8_from_syms(file_name)); - SYMS_String8 result = syms_from_str8(data); - return(result); -} - -int -main(int argument_count, char **arguments) -{ - os_init(argument_count, arguments); - demon_init(); - - String8Node node[2]; - -#define TARGET_EXE "C:\\devel\\projects\\debugger\\build\\mule_unwind_20210511_clang11_lldlink.exe" - - OS_LaunchOptions options = {0}; -#if OS_WINDOWS - str8_list_push(&options.cmd_line, &node[0], str8_lit(TARGET_EXE)); - options.path = str8_lit("C:\\devel\\projects\\debugger\\build\\"); -#else - str8_list_push(&options.cmd_line, &node[0], str8_lit("/home/allenw/projects_copy/debugger/build/mule_main")); - options.path = str8_lit("/home/allenw/projects_copy/debugger/build/"); -#endif - U32 process_id = demon_launch_process(&options); - if (process_id == 0){ - printf("Could not launch process\n"); - exit(1); - } - -#if OS_WINDOWS - U64 bp_addr = 0x140001134; -#else - U64 bp_addr = 0x400918; -#endif - - DEMON_Handle process = 0; - DEMON_Handle thread = 0; - DEMON_Handle module = 0; - U64 module_base = 0; - SYMS_Group *group = 0; - - B32 hit_bp = false; - U64 counter = 0; - - for (;;){ - DEMON_RunCtrls run_controls = {0}; - DEMON_Trap trap_memory[2]; - - DEMON_Trap *trap_ptr = trap_memory; - if (process != 0 && !hit_bp){ - trap_ptr->process = process; - trap_ptr->address = bp_addr; - trap_ptr += 1; - } - run_controls.traps = trap_memory; - run_controls.trap_count = (U64)(trap_ptr - trap_memory); - - Temp scratch = scratch_begin(0, 0); - DEMON_EventList events = demon_run(scratch.arena, run_controls); - - for (DEMON_Event *event = events.first; - event != 0; - event = event->next){ - printf("STEP[%05llx] -- ", counter); - counter += 1; - - switch (event->kind){ - case DEMON_EventKind_NotInitialized: - { - printf("Not Initialized\n"); - exit(1); - }break; - - case DEMON_EventKind_NotAttached: - { - printf("Not Attached\n"); - exit(1); - }break; - - case DEMON_EventKind_UnexpectedFailure: - { - printf("Unexpected Failure\n"); - exit(1); - }break; - - case DEMON_EventKind_CreateProcess: - { - printf("Create Process\n"); - if (process == 0){ - process = event->process; - } - }break; - - case DEMON_EventKind_CreateThread: - { - printf("Create Thread\n"); - if (thread == 0){ - thread = event->thread; - } - }break; - - case DEMON_EventKind_LoadModule: - { - Temp temp = temp_begin(scratch.arena); - String8 file_name = demon_full_path_from_module(scratch.arena, event->module); - printf("Load Module: %.*s\n", str8_varg(file_name)); - if (module == 0 && str8_match(file_name, str8_lit(TARGET_EXE), 0)){ - module = event->module; - module_base = event->address; - - // setup syms group - group = syms_group_alloc(); - - SYMS_FileLoadCtx ctx = {0}; - ctx.file_load_func = file_load_func_for_syms; - - SYMS_String8List file_names = {0}; - syms_string_list_push(group->arena, &file_names, syms_from_str8(file_name)); - - SYMS_FileInfOptions opts = {0}; - - SYMS_FileInfResult inf_result = syms_file_inf_infer_from_file_list(group->arena, ctx, file_names, &opts); - syms_group_init(group, &inf_result.data_parsed); - } - temp_end(temp); - }break; - - case DEMON_EventKind_ExitProcess: - { - printf("Exit Process\n"); - exit(0); - }break; - - case DEMON_EventKind_ExitThread: - { - printf("Exit Thread\n"); - }break; - - case DEMON_EventKind_UnloadModule: - { - printf("Unload Module\n"); - }break; - - case DEMON_EventKind_Breakpoint: - { - Architecture arch = demon_arch_from_object(event->process); - U64 ip = event->instruction_pointer; - printf("Breakpoint: %llx\n", ip); - - hit_bp = true; - - //- unwind - - // setup bin - SYMS_String8 bin_data = group->bin_data; - SYMS_BinAccel *generic_bin = group->bin; - SYMS_PeBinAccel *pe_bin = 0; - if (generic_bin->format == SYMS_FileFormat_PE){ - pe_bin = (SYMS_PeBinAccel*)generic_bin; - } - - if (pe_bin != 0){ - // read regs - SYMS_RegX64 regs = {0}; - demon_read_x64_regs(event->thread, ®s); - - // read stack - SYMS_U64 sp = regs.rsp.u64; - SYMS_U64 sp_rounded_down = sp&~(KB(4) - 1); - - SYMS_String8 stack_memory = {0}; - stack_memory.size = KB(8); - stack_memory.str = push_array_no_zero(scratch.arena, U8, stack_memory.size); - - SYMS_U64 stack_memory_addr = sp_rounded_down; - stack_memory.size = demon_read_memory_amap(event->process, stack_memory.str, - stack_memory_addr, stack_memory.size); - - // unwind loop - U64 counter = 1; - for (;; counter += 1){ - printf("%02llu: ip=%llx; sp=%llx\n", counter, regs.rip.u64, regs.rsp.u64); - SYMS_MemoryView memview = syms_memory_view_make(stack_memory, stack_memory_addr); - SYMS_UnwindResult unwind_result = syms_unwind_pe_x64(bin_data, pe_bin, module_base, &memview, ®s); - if (unwind_result.dead){ - break; - } - } - } - }break; - - case DEMON_EventKind_Trap: - { - Architecture arch = demon_arch_from_object(event->process); - U64 ip = event->instruction_pointer; - printf("Trap: %llx\n", ip); - }break; - - case DEMON_EventKind_SingleStep: - { - printf("Single Step: %llx\n", event->instruction_pointer); - }break; - - case DEMON_EventKind_Exception: - { - printf("Exception: %llx\n", event->instruction_pointer); - }break; - - case DEMON_EventKind_Halt: - { - printf("Halt\n"); - }break; - - case DEMON_EventKind_Memory: - { - printf("Memory\n"); - }break; - - default: - { - printf("Unhandled Event\n"); - exit(1); - }break; - } - } - scratch_end(scratch); - } - - printf("Done\n"); -} - diff --git a/src/demon/test/demon_win32_freeze_test.cpp b/src/demon/test/demon_win32_freeze_test.cpp deleted file mode 100644 index 86b564ba..00000000 --- a/src/demon/test/demon_win32_freeze_test.cpp +++ /dev/null @@ -1,935 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -// NOTE(rjf): (18 October 2021) Notes on Win32 process halting via -// DebugBreakProcess: -// -// Calling DebugBreakProcess seems to cause a few events to come back: -// 1. Thread Creation Event -// 2. Breakpoint Event (with the thread matching that of #1) -// 3. Thread Exiting Event (matching #1) -// -// Having done this experiment on a single-threaded program (mule_loop.exe), -// I can only infer that what is happening here is that when DebugBreakProcess -// is called, it first injects a thread into the target process that runs -// code with an int3. This is very similar to the old approach that Demon -// took. -// -// It's going to be difficult to distinguish between these CreateThreads and -// ExitThreads from others (not caused by halting), even though we can match -// the hit breakpoint to the associated thread. -// -// What could be possible (in order to distinguish the hit breakpoint as a -// halt event, instead of an arbitrary breakpoint) is looking at the breakpoint -// address. This injected thread has a breakpoint that's different from the -// initial breakpoint that the kernel automatically hits when a process is -// first being debugged. -// -// With DebugBreakProcess: -// - first breakpoint that is hit: 0x7ff8ad9806b0 in kernel code -// - last breakpoint that is hit: 0x7ff8ad950860 in kernel code (halt) -// -// Without DebugBreakProcess: -// - first breakpoint that is hit: 0x7ff8ad9806b0 -// - -// NOTE(rjf): (18 October 2021) Notes on suspending processes via -// NtSuspendProcess: -// -// NtSuspendProcess is an undocumented API that is exported by ntdll. It is -// fairly simple but could be unstable. To call it, the main trick is that -// you need a handle with certain privileges (PROCESS_SUSPEND_RESUME), so -// you can't just take any handle and use it. -// -// To use it, we can manually load it from ntdll, grab an elevated handle -// for a given process HANDLE, and then call it. We can resume, then, with -// NtResumeProcess. -// -// Other than this, our options seem to more-or-less lie in individually -// suspending all of the threads in the process-to-be-halted. - -#include - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "syms_helpers/syms_internal_overrides.h" -#include "syms/syms_inc.h" -#include "syms_helpers/syms_helpers.h" - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "syms_helpers/syms_internal_overrides.c" -#include "syms/syms_inc.c" -#include "syms_helpers/syms_helpers.c" - -typedef LONG NtSuspendProcessFunction(HANDLE ProcessHandle); -global NtSuspendProcessFunction *NtSuspendProcess = 0; - -//////////////////////////////// -// NOTE(allen): Win32 Demon Exceptions - -#define DEMON_W32_EXCEPTION_BREAKPOINT 0x80000003u -#define DEMON_W32_EXCEPTION_SINGLE_STEP 0x80000004u -#define DEMON_W32_EXCEPTION_LONG_JUMP 0x80000026u -#define DEMON_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u -#define DEMON_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu -#define DEMON_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u -#define DEMON_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u -#define DEMON_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du -#define DEMON_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu -#define DEMON_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu -#define DEMON_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u -#define DEMON_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u -#define DEMON_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u -#define DEMON_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u -#define DEMON_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u -#define DEMON_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u -#define DEMON_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u -#define DEMON_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du -#define DEMON_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u -#define DEMON_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u -#define DEMON_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u -#define DEMON_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu -#define DEMON_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u -#define DEMON_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u -#define DEMON_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u -#define DEMON_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u -#define DEMON_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u -#define DEMON_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u -#define DEMON_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au -#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u -#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u -#define DEMON_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u -#define DEMON_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u -#define DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u -#define DEMON_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u -#define DEMON_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u -#define DEMON_W32_EXCEPTION_NO_MEMORY 0xC0000017u -#define DEMON_W32_EXCEPTION_THROW 0xE06D7363u - -//////////////////////////////// -// NOTE(allen): Win32 Demon Register API Codes - -#define DEMON_W32_CTX_X86 0x00010000 -#define DEMON_W32_CTX_X64 0x00100000 - -#define DEMON_W32_CTX_INTEL_CONTROL 0x0001 -#define DEMON_W32_CTX_INTEL_INTEGER 0x0002 -#define DEMON_W32_CTX_INTEL_SEGMENTS 0x0004 -#define DEMON_W32_CTX_INTEL_FLOATS 0x0008 -#define DEMON_W32_CTX_INTEL_DEBUG 0x0010 -#define DEMON_W32_CTX_INTEL_EXTENDED 0x0020 -#define DEMON_W32_CTX_INTEL_XSTATE 0x0040 - -#define DEMON_W32_CTX_X86_ALL (DEMON_W32_CTX_X86 | \ -DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ -DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_DEBUG | \ -DEMON_W32_CTX_INTEL_EXTENDED) -#define DEMON_W32_CTX_X64_ALL (DEMON_W32_CTX_X64 | \ -DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ -DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_FLOATS | \ -DEMON_W32_CTX_INTEL_DEBUG) - -struct TEST_DebugEvent -{ - String8 name; - U64 process_id; - U64 thread_id; - HANDLE process; - HANDLE thread; - U64 addr; - DEBUG_EVENT evt; -}; - -struct TEST_Trap -{ - HANDLE process; - U64 address; -}; - -internal U16 -test_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave) -{ - U16 result = 0; - U32 top = (fxsave->StatusWord >> 11) & 7; - for (U32 fpr = 0; fpr < 8; fpr += 1){ - U32 tag = 3; - if (fxsave->TagWord & (1 << fpr)){ - U32 st = (fpr - top)&7; - - SYMS_Reg80 *fp = (SYMS_Reg80*)&fxsave->FloatRegisters[st*16]; - U16 exponent = fp->sign1_exp15 & bitmask15; - U64 integer_part = fp->int1_frac63 >> 63; - U64 fraction_part = fp->int1_frac63 & bitmask63; - - // tag: 0 - normal; 1 - zero; 2 - special - tag = 2; - if (exponent == 0){ - if (integer_part == 0 && fraction_part == 0){ - tag = 1; - } - } - else if (exponent != bitmask15 && integer_part != 0){ - tag = 0; - } - } - result |= tag << (2 * fpr); - } - return(result); -} - -internal U16 -test_w32_xsave_tag_word_from_real_tag_word(U16 ftw) -{ - U16 compact = 0; - for (U32 fpr = 0; fpr < 8; fpr++){ - U32 tag = (ftw >> (fpr * 2)) & 3; - if (tag != 3){ - compact |= (1 << fpr); - } - } - return(compact); -} - -internal B32 -test_w32_read_x64_regs(HANDLE thread, SYMS_RegX64 *dst) -{ - Temp scratch = scratch_begin(0, 0); - - // NOTE(allen): Check available features - U32 feature_mask = GetEnabledXStateFeatures(); - B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); - - // NOTE(allen): Setup the context - CONTEXT *ctx = 0; - U32 ctx_flags = DEMON_W32_CTX_X64_ALL; - if (avx_enabled){ - ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; - } - 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; - } - } - - B32 avx_available = false; - - if (ctx != 0){ - // NOTE(allen): Finish Context Setup - if (avx_enabled){ - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); - } - - // NOTE(allen): Determine what features are available on this particular ctx - // TODO(allen): Experiment carefully with this nonsense. - // Does avx_enabled = avx_available in all circumstances or not? - DWORD64 xstate_flags = 0; - if (GetXStateFeaturesMask(ctx, &xstate_flags)){ - if (xstate_flags & XSTATE_MASK_AVX){ - avx_available = true; - } - } - } - - // get thread context - HANDLE thread_handle = thread; - if (!GetThreadContext(thread_handle, ctx)){ - ctx = 0; - } - - B32 result = false; - if (ctx != 0){ - result = true; - - // NOTE(allen): Convert CONTEXT -> SYMS_RegX64 - dst->rax.u64 = ctx->Rax; - dst->rcx.u64 = ctx->Rcx; - dst->rdx.u64 = ctx->Rdx; - dst->rbx.u64 = ctx->Rbx; - dst->rsp.u64 = ctx->Rsp; - dst->rbp.u64 = ctx->Rbp; - dst->rsi.u64 = ctx->Rsi; - dst->rdi.u64 = ctx->Rdi; - dst->r8.u64 = ctx->R8; - dst->r9.u64 = ctx->R9; - dst->r10.u64 = ctx->R10; - dst->r11.u64 = ctx->R11; - dst->r12.u64 = ctx->R12; - dst->r13.u64 = ctx->R13; - dst->r14.u64 = ctx->R14; - dst->r15.u64 = ctx->R15; - dst->rip.u64 = ctx->Rip; - dst->cs.u16 = ctx->SegCs; - dst->ds.u16 = ctx->SegDs; - dst->es.u16 = ctx->SegEs; - dst->fs.u16 = ctx->SegFs; - dst->gs.u16 = ctx->SegGs; - dst->ss.u16 = ctx->SegSs; - dst->dr0.u32 = ctx->Dr0; - dst->dr1.u32 = ctx->Dr1; - dst->dr2.u32 = ctx->Dr2; - dst->dr3.u32 = ctx->Dr3; - dst->dr6.u32 = ctx->Dr6; - dst->dr7.u32 = ctx->Dr7; - - // NOTE(allen): This bit is "supposed to always be 1" I guess. - // TODO(allen): Not sure what this is all about but I haven't investigated it yet. - // This might be totally not necessary or something. - dst->rflags.u64 = ctx->EFlags | 0x2; - - XSAVE_FORMAT *xsave = &ctx->FltSave; - dst->fcw.u16 = xsave->ControlWord; - dst->fsw.u16 = xsave->StatusWord; - dst->ftw.u16 = test_w32_real_tag_word_from_xsave(xsave); - dst->fop.u16 = xsave->ErrorOpcode; - dst->fcs.u16 = xsave->ErrorSelector; - dst->fds.u16 = xsave->DataSelector; - dst->fip.u32 = xsave->ErrorOffset; - dst->fdp.u32 = xsave->DataOffset; - dst->mxcsr.u32 = xsave->MxCsr; - dst->mxcsr_mask.u32 = xsave->MxCsr_Mask; - - M128A *float_s = xsave->FloatRegisters; - SYMS_Reg80 *float_d = &dst->fpr0; - for (U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1){ - MemoryCopy(float_d, float_s, sizeof(*float_d)); - } - - if (!avx_available){ - M128A *xmm_s = xsave->XmmRegisters; - SYMS_Reg256 *xmm_d = &dst->ymm0; - for (U32 n = 0; n < 16; n += 1, xmm_s += 1, xmm_d += 1){ - MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s)); - } - } - - if (avx_available){ - DWORD part0_length = 0; - M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); - DWORD part1_length = 0; - M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); - Assert(part0_length == part1_length); - - DWORD count = part0_length/sizeof(part0[0]); - count = ClampTop(count, 16); - SYMS_Reg256 *ymm_d = &dst->ymm0; - for (DWORD i = 0; - i < count; - i += 1, part0 += 1, part1 += 1, ymm_d += 1){ - // TODO(allen): Are we writing these out in the right order? Seems weird right? - ymm_d->u64[3] = part0->Low; - ymm_d->u64[2] = part0->High; - ymm_d->u64[1] = part1->Low; - ymm_d->u64[0] = part1->High; - } - } - - } - - scratch_end(scratch); - return(result); -} - -internal B32 -test_w32_write_x64_regs(HANDLE thread, SYMS_RegX64 *src) -{ - Temp scratch = scratch_begin(0, 0); - - // NOTE(allen): Check available features - U32 feature_mask = GetEnabledXStateFeatures(); - B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); - - // NOTE(allen): Setup the context - CONTEXT *ctx = 0; - U32 ctx_flags = DEMON_W32_CTX_X64_ALL; - if (avx_enabled){ - ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; - } - 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; - } - } - - B32 avx_available = false; - - if (ctx != 0){ - // NOTE(allen): Finish Context Setup - if (avx_enabled){ - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); - } - - // NOTE(allen): Determine what features are available on this particular ctx - // TODO(allen): Experiment carefully with this nonsense. - // Does avx_enabled = avx_available in all circumstances or not? - DWORD64 xstate_flags = 0; - if (GetXStateFeaturesMask(ctx, &xstate_flags)){ - if (xstate_flags & XSTATE_MASK_AVX){ - avx_available = true; - } - } - } - - B32 result = false; - if (ctx != 0){ - // NOTE(allen): Convert SYMS_RegX64 -> CONTEXT - ctx->ContextFlags = ctx_flags; - - ctx->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32; - - ctx->Rax = src->rax.u64; - ctx->Rcx = src->rcx.u64; - ctx->Rdx = src->rdx.u64; - ctx->Rbx = src->rbx.u64; - ctx->Rsp = src->rsp.u64; - ctx->Rbp = src->rbp.u64; - ctx->Rsi = src->rsi.u64; - ctx->Rdi = src->rdi.u64; - ctx->R8 = src->r8.u64; - ctx->R9 = src->r9.u64; - ctx->R10 = src->r10.u64; - ctx->R11 = src->r11.u64; - ctx->R12 = src->r12.u64; - ctx->R13 = src->r13.u64; - ctx->R14 = src->r14.u64; - ctx->R15 = src->r15.u64; - ctx->Rip = src->rip.u64; - ctx->SegCs = src->cs.u16; - ctx->SegDs = src->ds.u16; - ctx->SegEs = src->es.u16; - ctx->SegFs = src->fs.u16; - ctx->SegGs = src->gs.u16; - ctx->SegSs = src->ss.u16; - ctx->Dr0 = src->dr0.u32; - ctx->Dr1 = src->dr1.u32; - ctx->Dr2 = src->dr2.u32; - ctx->Dr3 = src->dr3.u32; - ctx->Dr6 = src->dr6.u32; - ctx->Dr7 = src->dr7.u32; - - ctx->EFlags = src->rflags.u64; - - XSAVE_FORMAT *fxsave = &ctx->FltSave; - fxsave->ControlWord = src->fcw.u16; - fxsave->StatusWord = src->fsw.u16; - fxsave->TagWord = test_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16); - fxsave->ErrorOpcode = src->fop.u16; - fxsave->ErrorSelector = src->fcs.u16; - fxsave->DataSelector = src->fds.u16; - fxsave->ErrorOffset = src->fip.u32; - fxsave->DataOffset = src->fdp.u32; - - M128A *float_d = fxsave->FloatRegisters; - SYMS_Reg80 *float_s = &src->fpr0; - for (U32 n = 0; - n < 8; - n += 1, float_s += 1, float_d += 1){ - MemoryCopy(float_d, float_s, 10); - } - - if (!avx_available){ - M128A *xmm_d = fxsave->XmmRegisters; - SYMS_Reg256 *xmm_s = &src->ymm0; - for (U32 n = 0; - n < 8; - n += 1, xmm_d += 1, xmm_s += 1){ - MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d)); - } - } - - if (avx_available){ - DWORD part0_length = 0; - M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); - DWORD part1_length = 0; - M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); - Assert(part0_length == part1_length); - - DWORD count = part0_length/sizeof(part0[0]); - count = ClampTop(count, 16); - SYMS_Reg256 *ymm_d = &src->ymm0; - for (DWORD i = 0; - i < count; - i += 1, part0 += 1, part1 += 1, ymm_d += 1){ - // TODO(allen): Are we writing these out in the right order? Seems weird right? - part0->Low = ymm_d->u64[3]; - part0->High = ymm_d->u64[2]; - part1->Low = ymm_d->u64[1]; - part1->High = ymm_d->u64[0]; - } - } - - //- set thread context - HANDLE thread_handle = thread; - if (SetThreadContext(thread_handle, ctx)){ - result = true; - } - } - - scratch_end(scratch); - return(result); -} - -internal B32 -test_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size) -{ - B32 result = true; - U8 *ptr = (U8*)dst; - U8 *opl = ptr + size; - U64 cursor = src_address; - for (;ptr < opl;){ - SIZE_T to_read = (SIZE_T)(opl - ptr); - SIZE_T actual_read = 0; - if (!ReadProcessMemory(process_handle, (LPCVOID)cursor, ptr, to_read, &actual_read)){ - result = false; - break; - } - ptr += actual_read; - cursor += actual_read; - } - return(result); -} - -internal B32 -test_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size) -{ - B32 result = true; - U8 *ptr = (U8*)src; - U8 *opl = ptr + size; - U64 cursor = dst_address; - for (;ptr < opl;){ - SIZE_T to_write = (SIZE_T)(opl - ptr); - SIZE_T actual_write = 0; - if (!WriteProcessMemory(process_handle, (LPVOID)cursor, ptr, to_write, &actual_write)){ - result = false; - break; - } - ptr += actual_write; - cursor += actual_write; - } - return(result); -} - -internal B32 -test_launch_process(OS_LaunchOptions *options) -{ - B32 result = false; - Temp scratch = scratch_begin(0, 0); - - StringJoin join_params = {0}; - join_params.pre = str8_lit("\""); - join_params.sep = str8_lit("\" \""); - join_params.post = str8_lit("\""); - String8 cmd = str8_list_join(scratch.arena, &options->cmd_line, &join_params); - - StringJoin join_params2 = {0}; - join_params2.sep = str8_lit("\0"); - join_params2.post = str8_lit("\0"); - String8 env = str8_list_join(scratch.arena, &options->env, &join_params2); - - 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); - - DWORD access_flags = PROCESS_QUERY_INFORMATION | DEBUG_PROCESS | PROCESS_VM_READ | PROCESS_VM_WRITE; - STARTUPINFOW startup_info = {sizeof(startup_info)}; - PROCESS_INFORMATION process_info = {0}; - if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, - &startup_info, &process_info)) - { - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); - result = true; - } - - scratch_end(scratch); - return(result); -} - -global HANDLE g_process_1 = 0; -global DWORD g_process_id_1 = 0; -global U64 g_process_injection_addr_1 = 0; -global HANDLE g_process_2 = 0; -global DWORD g_process_id_2 = 0; - -internal B32 -test_w32_inject_thread(HANDLE process, U64 start_address) -{ - B32 result = false; - LPTHREAD_START_ROUTINE start = (LPTHREAD_START_ROUTINE)start_address; - HANDLE thread = CreateRemoteThread(process, 0, 0, start, 0, 0, 0); - if(thread != 0) - { - CloseHandle(thread); - result = true; - } - return result; -} - -internal void -test_halt(void) -{ - test_w32_inject_thread(g_process_1, g_process_injection_addr_1); -} - -internal TEST_DebugEvent -test_run_process(HANDLE step_thread, HANDLE suspend_thread, U64 traps_count, TEST_Trap *traps) -{ - Temp scratch = scratch_begin(0, 0); - TEST_DebugEvent result = {0}; - - //- rjf: freeze thread - if(suspend_thread) - { - DWORD result = SuspendThread(suspend_thread); - DWORD error = GetLastError(); - int x = 0; - } - - //- rjf: write traps - U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, traps_count); - { - TEST_Trap *trap = traps; - for(U64 i = 0; i < traps_count; i += 1, trap += 1) - { - if(test_w32_read_memory(trap->process, trap_swap_bytes + i, trap->address, 1)) - { - U8 int3 = 0xCC; - test_w32_write_memory(trap->process, trap->address, &int3, 1); - } - else - { - trap_swap_bytes[i] = 0xCC; - } - } - } - - //- rjf: set single step bit - if(step_thread != 0) - { - SYMS_RegX64 regs = {0}; - test_w32_read_x64_regs(step_thread, ®s); - regs.rflags.u64 |= 0x100; - test_w32_write_x64_regs(step_thread, ®s); - } - - //- rjf: continue - local_persist B32 need_resume = 0; - local_persist DWORD resume_pid = 0; - local_persist DWORD resume_tid = 0; - - if(need_resume) - { - need_resume = 0; - ContinueDebugEvent(resume_pid, resume_tid, DBG_CONTINUE); - } - - //- rjf: get event - DEBUG_EVENT evt = {0}; - if(WaitForDebugEvent(&evt, INFINITE)) - { - need_resume = 1; - resume_pid = evt.dwProcessId; - resume_tid = evt.dwThreadId; - result.evt = evt; - - switch(evt.dwDebugEventCode) - { - default:break; - - case CREATE_PROCESS_DEBUG_EVENT: - { - result.name = str8_lit("create process"); - result.process_id = evt.dwProcessId; - result.process = evt.u.CreateProcessInfo.hProcess; - result.thread_id = evt.dwThreadId; - result.thread = evt.u.CreateProcessInfo.hThread; - if(g_process_1 == 0) - { - g_process_1 = result.process; - g_process_id_1 = result.process_id; - - // injection memory - { - U8 injection_code[64]; - injection_code[0] = 0xCC; - injection_code[1] = 0xC3; - for (U64 i = 2; i < 64; i += 1){ - injection_code[i] = 0xCC; - } - - U64 injection_size = 64; - U64 injection_address = (U64)VirtualAllocEx(g_process_1, 0, injection_size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE); - test_w32_write_memory(g_process_1, injection_address, injection_code, sizeof(injection_code)); - g_process_injection_addr_1 = injection_address; - } - - - } - else - { - g_process_2 = result.process; - g_process_id_2 = result.process_id; - } - }break; - - case EXIT_PROCESS_DEBUG_EVENT: - { - result.name = str8_lit("exit process"); - result.process_id = evt.dwProcessId; - }break; - - case CREATE_THREAD_DEBUG_EVENT: - { - result.name = str8_lit("create thread"); - result.thread_id = evt.dwThreadId; - result.thread = evt.u.CreateThread.hThread; - }break; - - case EXIT_THREAD_DEBUG_EVENT: - { - result.name = str8_lit("exit thread"); - result.thread_id = evt.dwThreadId; - }break; - - case LOAD_DLL_DEBUG_EVENT: - { - result.name = str8_lit("load dll"); - }break; - - case UNLOAD_DLL_DEBUG_EVENT: - { - result.name = str8_lit("unload dll"); - }break; - - case EXCEPTION_DEBUG_EVENT: - { - result.name = str8_lit("exception"); - - EXCEPTION_DEBUG_INFO *edi = &evt.u.Exception; - EXCEPTION_RECORD *exception = &edi->ExceptionRecord; - - switch(exception->ExceptionCode) - { - case DEMON_W32_EXCEPTION_BREAKPOINT: - { - result.name = str8_lit("breakpoint"); - result.addr = (U64)exception->ExceptionAddress; - }break; - - case DEMON_W32_EXCEPTION_SINGLE_STEP: - { - result.name = str8_lit("single_step"); - }break; - - case DEMON_W32_EXCEPTION_THROW: - { - result.name = str8_lit("exception throw"); - }break; - - case DEMON_W32_EXCEPTION_ACCESS_VIOLATION: - case DEMON_W32_EXCEPTION_IN_PAGE_ERROR: - { - result.name = str8_lit("exception access violation"); - }break; - - default: - { - }break; - } - - }break; - - case OUTPUT_DEBUG_STRING_EVENT: - { - Temp scratch = scratch_begin(0, 0); - result.name = str8_lit("output debug string"); - - U64 string_address = (U64)evt.u.DebugString.lpDebugStringData; - U64 string_size = (U64)evt.u.DebugString.nDebugStringLength; - - // TODO(allen): is the string in UTF-8 or UTF-16? - - U8 *buffer = push_array_no_zero(scratch.arena, U8, string_size + 1); - test_w32_read_memory(g_process_id_1 == evt.dwProcessId ? g_process_1 : g_process_2, buffer, string_address, string_size); - buffer[string_size] = 0; - - printf("%s\n", buffer); - scratch_end(scratch); - }break; - - case RIP_EVENT: - { - result.name = str8_lit("rip event"); - }break; - - } - } - - //- rjf: set single step bit - if(step_thread != 0) - { - SYMS_RegX64 regs = {0}; - test_w32_read_x64_regs(step_thread, ®s); - regs.rflags.u64 &= ~0x100; - test_w32_write_x64_regs(step_thread, ®s); - } - - //- rjf: unset traps - { - TEST_Trap *trap = traps; - for(U64 i = 0; i < traps_count; i += 1, trap += 1) - { - U8 og_byte = trap_swap_bytes[i]; - if(og_byte != 0xCC) - { - test_w32_write_memory(trap->process, trap->address, &og_byte, 1); - } - } - } - - //- rjf: resume thread - if(suspend_thread) - { - ResumeThread(suspend_thread); - } - - scratch_end(scratch); - return result; -} - -internal DWORD -test_halter_thread(void *params) -{ - HANDLE original_process_handle = params; - Sleep(1500); - test_halt(); -#if 0 - DWORD process_id = GetProcessId(original_process_handle); - HANDLE elevated_process_handle = OpenProcess(PROCESS_SUSPEND_RESUME, 0, process_id); - LONG result = NtSuspendProcess(elevated_process_handle); - CloseHandle(elevated_process_handle); - DebugBreakProcess(process); -#endif - return 0; -} - -int -main(int argument_count, char **arguments) -{ - os_init(argument_count, arguments); - Arena *arena = arena_alloc(); - - NtSuspendProcess = (NtSuspendProcessFunction *)GetProcAddress(GetModuleHandle("ntdll"), "NtSuspendProcess"); - - // rjf: launch - { - OS_LaunchOptions opts = {0}; - opts.path = os_get_path(arena, OS_SystemPath_Current); - str8_list_push(arena, &opts.cmd_line, str8_lit("R:\\projects\\debugger\\build\\mule_loop.exe")); - B32 launch_good = test_launch_process(&opts); - int x = 0; - } - - // rjf: get process/thread handles - HANDLE process = 0; - HANDLE thread1 = 0; - U64 thread1_id = 0; - { - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, 0, 0); - if(evt.process) - { - process = evt.process; - } - if(evt.thread) - { - thread1 = evt.thread; - thread1_id = evt.thread_id; - } - if(process != 0 && thread1 != 0) - { - break; - } - } - } - - // rjf: get first breakpoint - { - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, 0, 0); - if(evt.evt.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) - { - break; - } - } - } - - // rjf: launch halter thread - DWORD halter_id = 0; - { - CreateThread(0, 0, test_halter_thread, process, 0, &halter_id); - } - - // rjf: run + wait for event - for(;;) - { - TEST_DebugEvent evt = test_run_process(0, 0, 0, 0); - int x = 0; - } - -#if 0 - //- rjf: run until 2nd thread starts up - HANDLE thread2 = 0; - U64 thread2_id = 0; - { - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, 0, 0/*ArrayCount(traps), traps*/); - if(evt.thread) - { - thread2 = evt.thread; - thread2_id = evt.thread_id; - break; - } - } - } - - //- rjf: wait for first output string - { - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, 0, 0); - if(evt.evt.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) - { - break; - } - } - } - - //- rjf: wait for bps - { - // U64 thread1_stop_vaddr = 0x0000000140001119; - // U64 thread2_stop_vaddr = 0x00000001400010C8; - // TEST_Trap traps[] = - { - // {process, thread1_stop_vaddr}, - //{process, thread2_stop_vaddr}, - }; - TEST_DebugEvent evt = {0}; - //for(;;) - { - evt = test_run_process(0, thread2, 0, 0/*ArrayCount(traps), traps*/); - int x = 0; - } - for(;;) {} - } -#endif -} diff --git a/src/demon/test/demon_win32_thread_test.cpp b/src/demon/test/demon_win32_thread_test.cpp deleted file mode 100644 index 6ecd4780..00000000 --- a/src/demon/test/demon_win32_thread_test.cpp +++ /dev/null @@ -1,874 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#include - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "syms_helpers/syms_internal_overrides.h" -#include "syms/syms_inc.h" -#include "syms_helpers/syms_helpers.h" - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "syms_helpers/syms_internal_overrides.c" -#include "syms/syms_inc.c" -#include "syms_helpers/syms_helpers.c" - -//////////////////////////////// -// NOTE(allen): Win32 Demon Exceptions - -#define DEMON_W32_EXCEPTION_BREAKPOINT 0x80000003u -#define DEMON_W32_EXCEPTION_SINGLE_STEP 0x80000004u -#define DEMON_W32_EXCEPTION_LONG_JUMP 0x80000026u -#define DEMON_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u -#define DEMON_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu -#define DEMON_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u -#define DEMON_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u -#define DEMON_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du -#define DEMON_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu -#define DEMON_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu -#define DEMON_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u -#define DEMON_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u -#define DEMON_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u -#define DEMON_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u -#define DEMON_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u -#define DEMON_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u -#define DEMON_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u -#define DEMON_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du -#define DEMON_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u -#define DEMON_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u -#define DEMON_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u -#define DEMON_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu -#define DEMON_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u -#define DEMON_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u -#define DEMON_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u -#define DEMON_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u -#define DEMON_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u -#define DEMON_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u -#define DEMON_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au -#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u -#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u -#define DEMON_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u -#define DEMON_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u -#define DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u -#define DEMON_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u -#define DEMON_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u -#define DEMON_W32_EXCEPTION_NO_MEMORY 0xC0000017u -#define DEMON_W32_EXCEPTION_THROW 0xE06D7363u - -//////////////////////////////// -// NOTE(allen): Win32 Demon Register API Codes - -#define DEMON_W32_CTX_X86 0x00010000 -#define DEMON_W32_CTX_X64 0x00100000 - -#define DEMON_W32_CTX_INTEL_CONTROL 0x0001 -#define DEMON_W32_CTX_INTEL_INTEGER 0x0002 -#define DEMON_W32_CTX_INTEL_SEGMENTS 0x0004 -#define DEMON_W32_CTX_INTEL_FLOATS 0x0008 -#define DEMON_W32_CTX_INTEL_DEBUG 0x0010 -#define DEMON_W32_CTX_INTEL_EXTENDED 0x0020 -#define DEMON_W32_CTX_INTEL_XSTATE 0x0040 - -#define DEMON_W32_CTX_X86_ALL (DEMON_W32_CTX_X86 | \ -DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ -DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_DEBUG | \ -DEMON_W32_CTX_INTEL_EXTENDED) -#define DEMON_W32_CTX_X64_ALL (DEMON_W32_CTX_X64 | \ -DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ -DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_FLOATS | \ -DEMON_W32_CTX_INTEL_DEBUG) - -struct TEST_DebugEvent -{ - String8 name; - U64 process_id; - U64 thread_id; - HANDLE process; - HANDLE thread; - U64 addr; - DEBUG_EVENT evt; -}; - -struct TEST_Trap -{ - HANDLE process; - U64 address; -}; - -internal U16 -test_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave) -{ - U16 result = 0; - U32 top = (fxsave->StatusWord >> 11) & 7; - for (U32 fpr = 0; fpr < 8; fpr += 1){ - U32 tag = 3; - if (fxsave->TagWord & (1 << fpr)){ - U32 st = (fpr - top)&7; - - SYMS_Reg80 *fp = (SYMS_Reg80*)&fxsave->FloatRegisters[st*16]; - U16 exponent = fp->sign1_exp15 & bitmask15; - U64 integer_part = fp->int1_frac63 >> 63; - U64 fraction_part = fp->int1_frac63 & bitmask63; - - // tag: 0 - normal; 1 - zero; 2 - special - tag = 2; - if (exponent == 0){ - if (integer_part == 0 && fraction_part == 0){ - tag = 1; - } - } - else if (exponent != bitmask15 && integer_part != 0){ - tag = 0; - } - } - result |= tag << (2 * fpr); - } - return(result); -} - -internal U16 -test_w32_xsave_tag_word_from_real_tag_word(U16 ftw) -{ - U16 compact = 0; - for (U32 fpr = 0; fpr < 8; fpr++){ - U32 tag = (ftw >> (fpr * 2)) & 3; - if (tag != 3){ - compact |= (1 << fpr); - } - } - return(compact); -} - -internal B32 -test_w32_read_x64_regs(HANDLE thread, SYMS_RegX64 *dst) -{ - Temp scratch = scratch_begin(0, 0); - - // NOTE(allen): Check available features - U32 feature_mask = GetEnabledXStateFeatures(); - B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); - - // NOTE(allen): Setup the context - CONTEXT *ctx = 0; - U32 ctx_flags = DEMON_W32_CTX_X64_ALL; - if (avx_enabled){ - ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; - } - 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; - } - } - - B32 avx_available = false; - - if (ctx != 0){ - // NOTE(allen): Finish Context Setup - if (avx_enabled){ - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); - } - - // NOTE(allen): Determine what features are available on this particular ctx - // TODO(allen): Experiment carefully with this nonsense. - // Does avx_enabled = avx_available in all circumstances or not? - DWORD64 xstate_flags = 0; - if (GetXStateFeaturesMask(ctx, &xstate_flags)){ - if (xstate_flags & XSTATE_MASK_AVX){ - avx_available = true; - } - } - } - - // get thread context - HANDLE thread_handle = thread; - if (!GetThreadContext(thread_handle, ctx)){ - ctx = 0; - } - - B32 result = false; - if (ctx != 0){ - result = true; - - // NOTE(allen): Convert CONTEXT -> SYMS_RegX64 - dst->rax.u64 = ctx->Rax; - dst->rcx.u64 = ctx->Rcx; - dst->rdx.u64 = ctx->Rdx; - dst->rbx.u64 = ctx->Rbx; - dst->rsp.u64 = ctx->Rsp; - dst->rbp.u64 = ctx->Rbp; - dst->rsi.u64 = ctx->Rsi; - dst->rdi.u64 = ctx->Rdi; - dst->r8.u64 = ctx->R8; - dst->r9.u64 = ctx->R9; - dst->r10.u64 = ctx->R10; - dst->r11.u64 = ctx->R11; - dst->r12.u64 = ctx->R12; - dst->r13.u64 = ctx->R13; - dst->r14.u64 = ctx->R14; - dst->r15.u64 = ctx->R15; - dst->rip.u64 = ctx->Rip; - dst->cs.u16 = ctx->SegCs; - dst->ds.u16 = ctx->SegDs; - dst->es.u16 = ctx->SegEs; - dst->fs.u16 = ctx->SegFs; - dst->gs.u16 = ctx->SegGs; - dst->ss.u16 = ctx->SegSs; - dst->dr0.u32 = ctx->Dr0; - dst->dr1.u32 = ctx->Dr1; - dst->dr2.u32 = ctx->Dr2; - dst->dr3.u32 = ctx->Dr3; - dst->dr6.u32 = ctx->Dr6; - dst->dr7.u32 = ctx->Dr7; - - // NOTE(allen): This bit is "supposed to always be 1" I guess. - // TODO(allen): Not sure what this is all about but I haven't investigated it yet. - // This might be totally not necessary or something. - dst->rflags.u64 = ctx->EFlags | 0x2; - - XSAVE_FORMAT *xsave = &ctx->FltSave; - dst->fcw.u16 = xsave->ControlWord; - dst->fsw.u16 = xsave->StatusWord; - dst->ftw.u16 = test_w32_real_tag_word_from_xsave(xsave); - dst->fop.u16 = xsave->ErrorOpcode; - dst->fcs.u16 = xsave->ErrorSelector; - dst->fds.u16 = xsave->DataSelector; - dst->fip.u32 = xsave->ErrorOffset; - dst->fdp.u32 = xsave->DataOffset; - dst->mxcsr.u32 = xsave->MxCsr; - dst->mxcsr_mask.u32 = xsave->MxCsr_Mask; - - M128A *float_s = xsave->FloatRegisters; - SYMS_Reg80 *float_d = &dst->fpr0; - for (U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1){ - MemoryCopy(float_d, float_s, sizeof(*float_d)); - } - - if (!avx_available){ - M128A *xmm_s = xsave->XmmRegisters; - SYMS_Reg256 *xmm_d = &dst->ymm0; - for (U32 n = 0; n < 16; n += 1, xmm_s += 1, xmm_d += 1){ - MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s)); - } - } - - if (avx_available){ - DWORD part0_length = 0; - M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); - DWORD part1_length = 0; - M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); - Assert(part0_length == part1_length); - - DWORD count = part0_length/sizeof(part0[0]); - count = ClampTop(count, 16); - SYMS_Reg256 *ymm_d = &dst->ymm0; - for (DWORD i = 0; - i < count; - i += 1, part0 += 1, part1 += 1, ymm_d += 1){ - // TODO(allen): Are we writing these out in the right order? Seems weird right? - ymm_d->u64[3] = part0->Low; - ymm_d->u64[2] = part0->High; - ymm_d->u64[1] = part1->Low; - ymm_d->u64[0] = part1->High; - } - } - - } - - scratch_end(scratch); - return(result); -} - -internal B32 -test_w32_write_x64_regs(HANDLE thread, SYMS_RegX64 *src) -{ - Temp scratch = scratch_begin(0, 0); - - // NOTE(allen): Check available features - U32 feature_mask = GetEnabledXStateFeatures(); - B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); - - // NOTE(allen): Setup the context - CONTEXT *ctx = 0; - U32 ctx_flags = DEMON_W32_CTX_X64_ALL; - if (avx_enabled){ - ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; - } - 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; - } - } - - B32 avx_available = false; - - if (ctx != 0){ - // NOTE(allen): Finish Context Setup - if (avx_enabled){ - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); - } - - // NOTE(allen): Determine what features are available on this particular ctx - // TODO(allen): Experiment carefully with this nonsense. - // Does avx_enabled = avx_available in all circumstances or not? - DWORD64 xstate_flags = 0; - if (GetXStateFeaturesMask(ctx, &xstate_flags)){ - if (xstate_flags & XSTATE_MASK_AVX){ - avx_available = true; - } - } - } - - B32 result = false; - if (ctx != 0){ - // NOTE(allen): Convert SYMS_RegX64 -> CONTEXT - ctx->ContextFlags = ctx_flags; - - ctx->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32; - - ctx->Rax = src->rax.u64; - ctx->Rcx = src->rcx.u64; - ctx->Rdx = src->rdx.u64; - ctx->Rbx = src->rbx.u64; - ctx->Rsp = src->rsp.u64; - ctx->Rbp = src->rbp.u64; - ctx->Rsi = src->rsi.u64; - ctx->Rdi = src->rdi.u64; - ctx->R8 = src->r8.u64; - ctx->R9 = src->r9.u64; - ctx->R10 = src->r10.u64; - ctx->R11 = src->r11.u64; - ctx->R12 = src->r12.u64; - ctx->R13 = src->r13.u64; - ctx->R14 = src->r14.u64; - ctx->R15 = src->r15.u64; - ctx->Rip = src->rip.u64; - ctx->SegCs = src->cs.u16; - ctx->SegDs = src->ds.u16; - ctx->SegEs = src->es.u16; - ctx->SegFs = src->fs.u16; - ctx->SegGs = src->gs.u16; - ctx->SegSs = src->ss.u16; - ctx->Dr0 = src->dr0.u32; - ctx->Dr1 = src->dr1.u32; - ctx->Dr2 = src->dr2.u32; - ctx->Dr3 = src->dr3.u32; - ctx->Dr6 = src->dr6.u32; - ctx->Dr7 = src->dr7.u32; - - ctx->EFlags = src->rflags.u64; - - XSAVE_FORMAT *fxsave = &ctx->FltSave; - fxsave->ControlWord = src->fcw.u16; - fxsave->StatusWord = src->fsw.u16; - fxsave->TagWord = test_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16); - fxsave->ErrorOpcode = src->fop.u16; - fxsave->ErrorSelector = src->fcs.u16; - fxsave->DataSelector = src->fds.u16; - fxsave->ErrorOffset = src->fip.u32; - fxsave->DataOffset = src->fdp.u32; - - M128A *float_d = fxsave->FloatRegisters; - SYMS_Reg80 *float_s = &src->fpr0; - for (U32 n = 0; - n < 8; - n += 1, float_s += 1, float_d += 1){ - MemoryCopy(float_d, float_s, 10); - } - - if (!avx_available){ - M128A *xmm_d = fxsave->XmmRegisters; - SYMS_Reg256 *xmm_s = &src->ymm0; - for (U32 n = 0; - n < 8; - n += 1, xmm_d += 1, xmm_s += 1){ - MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d)); - } - } - - if (avx_available){ - DWORD part0_length = 0; - M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); - DWORD part1_length = 0; - M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); - Assert(part0_length == part1_length); - - DWORD count = part0_length/sizeof(part0[0]); - count = ClampTop(count, 16); - SYMS_Reg256 *ymm_d = &src->ymm0; - for (DWORD i = 0; - i < count; - i += 1, part0 += 1, part1 += 1, ymm_d += 1){ - // TODO(allen): Are we writing these out in the right order? Seems weird right? - part0->Low = ymm_d->u64[3]; - part0->High = ymm_d->u64[2]; - part1->Low = ymm_d->u64[1]; - part1->High = ymm_d->u64[0]; - } - } - - //- set thread context - HANDLE thread_handle = thread; - if (SetThreadContext(thread_handle, ctx)){ - result = true; - } - } - - scratch_end(scratch); - return(result); -} - -internal B32 -test_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size) -{ - B32 result = true; - U8 *ptr = (U8*)dst; - U8 *opl = ptr + size; - U64 cursor = src_address; - for (;ptr < opl;){ - SIZE_T to_read = (SIZE_T)(opl - ptr); - SIZE_T actual_read = 0; - if (!ReadProcessMemory(process_handle, (LPCVOID)cursor, ptr, to_read, &actual_read)){ - result = false; - break; - } - ptr += actual_read; - cursor += actual_read; - } - return(result); -} - -internal B32 -test_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size) -{ - B32 result = true; - U8 *ptr = (U8*)src; - U8 *opl = ptr + size; - U64 cursor = dst_address; - for (;ptr < opl;){ - SIZE_T to_write = (SIZE_T)(opl - ptr); - SIZE_T actual_write = 0; - if (!WriteProcessMemory(process_handle, (LPVOID)cursor, ptr, to_write, &actual_write)){ - result = false; - break; - } - ptr += actual_write; - cursor += actual_write; - } - return(result); -} - -internal B32 -test_launch_process(OS_LaunchOptions *options) -{ - B32 result = false; - Temp scratch = scratch_begin(0, 0); - - StringJoin join_params = {0}; - join_params.pre = str8_lit("\""); - join_params.sep = str8_lit("\" \""); - join_params.post = str8_lit("\""); - String8 cmd = str8_list_join(scratch.arena, &options->cmd_line, &join_params); - - StringJoin join_params2 = {0}; - join_params2.sep = str8_lit("\0"); - join_params2.post = str8_lit("\0"); - String8 env = str8_list_join(scratch.arena, &options->env, &join_params2); - - 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); - - DWORD access_flags = PROCESS_QUERY_INFORMATION | DEBUG_PROCESS | PROCESS_VM_READ | PROCESS_VM_WRITE; - STARTUPINFOW startup_info = {sizeof(startup_info)}; - PROCESS_INFORMATION process_info = {0}; - if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, - &startup_info, &process_info)) - { - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); - result = true; - } - - scratch_end(scratch); - return(result); -} - -global HANDLE g_process = 0; -global DWORD g_process_id = 0; -global HANDLE g_thread1 = 0; -global DWORD g_thread1_id = 0; -global HANDLE g_thread2 = 0; -global DWORD g_thread2_id = 0; - -internal TEST_DebugEvent -test_run_process(HANDLE step_thread, HANDLE suspend_thread, U64 traps_count, TEST_Trap *traps) -{ - Temp scratch = scratch_begin(0, 0); - TEST_DebugEvent result = {0}; - - //- rjf: freeze thread - if(suspend_thread) - { - DWORD result = SuspendThread(suspend_thread); - DWORD error = GetLastError(); - int x = 0; - } - - //- rjf: write traps - U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, traps_count); - { - TEST_Trap *trap = traps; - for(U64 i = 0; i < traps_count; i += 1, trap += 1) - { - if(test_w32_read_memory(trap->process, trap_swap_bytes + i, trap->address, 1)) - { - U8 int3 = 0xCC; - test_w32_write_memory(trap->process, trap->address, &int3, 1); - } - else - { - trap_swap_bytes[i] = 0xCC; - } - } - } - - //- rjf: set single step bit - if(step_thread != 0) - { - SYMS_RegX64 regs = {0}; - test_w32_read_x64_regs(step_thread, ®s); - regs.rflags.u64 |= 0x100; - test_w32_write_x64_regs(step_thread, ®s); - } - - //- rjf: continue - local_persist B32 need_resume = 0; - local_persist DWORD resume_pid = 0; - local_persist DWORD resume_tid = 0; - - if(need_resume) - { - need_resume = 0; - ContinueDebugEvent(resume_pid, resume_tid, DBG_CONTINUE); - } - - //- rjf: get event - DEBUG_EVENT evt = {0}; - if(WaitForDebugEvent(&evt, INFINITE)) - { - need_resume = 1; - resume_pid = evt.dwProcessId; - resume_tid = evt.dwThreadId; - result.evt = evt; - - switch(evt.dwDebugEventCode) - { - default:break; - - case CREATE_PROCESS_DEBUG_EVENT: - { - result.name = str8_lit("create process"); - result.process_id = evt.dwProcessId; - result.process = evt.u.CreateProcessInfo.hProcess; - result.thread_id = evt.dwThreadId; - result.thread = evt.u.CreateProcessInfo.hThread; - if(g_process == 0) - { - g_process = result.process; - g_process_id = result.process_id; - } - if(g_thread1 == 0) - { - g_thread1 = result.thread; - g_thread1_id = result.thread_id; - } - }break; - - case EXIT_PROCESS_DEBUG_EVENT: - { - result.name = str8_lit("exit process"); - result.process_id = evt.dwProcessId; - }break; - - case CREATE_THREAD_DEBUG_EVENT: - { - result.name = str8_lit("create thread"); - result.thread_id = evt.dwThreadId; - result.thread = evt.u.CreateThread.hThread; - g_thread2 = result.thread; - g_thread2_id = result.thread_id; - }break; - - case EXIT_THREAD_DEBUG_EVENT: - { - result.name = str8_lit("exit thread"); - result.thread_id = evt.dwThreadId; - }break; - - case LOAD_DLL_DEBUG_EVENT: - { - result.name = str8_lit("load dll"); - }break; - - case UNLOAD_DLL_DEBUG_EVENT: - { - result.name = str8_lit("unload dll"); - }break; - - case EXCEPTION_DEBUG_EVENT: - { - result.name = str8_lit("exception"); - - EXCEPTION_DEBUG_INFO *edi = &evt.u.Exception; - EXCEPTION_RECORD *exception = &edi->ExceptionRecord; - - switch(exception->ExceptionCode) - { - case DEMON_W32_EXCEPTION_BREAKPOINT: - { - result.name = str8_lit("breakpoint"); - result.addr = (U64)exception->ExceptionAddress; - - local_persist B32 did_first_bp = 0; - if(did_first_bp != 0) - { - HANDLE thread = evt.dwThreadId == g_thread1_id ? g_thread1 : g_thread2; - SYMS_RegX64 regs = {0}; - test_w32_read_x64_regs(thread, ®s); - regs.rip.u64 = result.addr; - test_w32_write_x64_regs(thread, ®s); - } - did_first_bp = 1; - - }break; - - case DEMON_W32_EXCEPTION_SINGLE_STEP: - { - result.name = str8_lit("single_step"); - }break; - - case DEMON_W32_EXCEPTION_THROW: - { - result.name = str8_lit("exception throw"); - }break; - - case DEMON_W32_EXCEPTION_ACCESS_VIOLATION: - case DEMON_W32_EXCEPTION_IN_PAGE_ERROR: - { - result.name = str8_lit("exception access violation"); - }break; - - default: - { - }break; - } - - }break; - - case OUTPUT_DEBUG_STRING_EVENT: - { - Temp scratch = scratch_begin(0, 0); - result.name = str8_lit("output debug string"); - - U64 string_address = (U64)evt.u.DebugString.lpDebugStringData; - U64 string_size = (U64)evt.u.DebugString.nDebugStringLength; - - // TODO(allen): is the string in UTF-8 or UTF-16? - - U8 *buffer = push_array_no_zero(scratch.arena, U8, string_size + 1); - test_w32_read_memory(g_process, buffer, string_address, string_size); - buffer[string_size] = 0; - - printf("%s\n", buffer); - scratch_end(scratch); - }break; - - case RIP_EVENT: - { - result.name = str8_lit("rip event"); - }break; - - } - } - - //- rjf: set single step bit - if(step_thread != 0) - { - SYMS_RegX64 regs = {0}; - test_w32_read_x64_regs(step_thread, ®s); - regs.rflags.u64 &= ~0x100; - test_w32_write_x64_regs(step_thread, ®s); - } - - //- rjf: unset traps - { - TEST_Trap *trap = traps; - for(U64 i = 0; i < traps_count; i += 1, trap += 1) - { - U8 og_byte = trap_swap_bytes[i]; - if(og_byte != 0xCC) - { - test_w32_write_memory(trap->process, trap->address, &og_byte, 1); - } - } - } - - //- rjf: check for more events - for(int i = 0; i < 100; i += 1) - { - DEBUG_EVENT evt = {0}; - if(WaitForDebugEvent(&evt, 0)) - { - int x = 0; - } - } - - //- rjf: resume thread - if(suspend_thread) - { - ResumeThread(suspend_thread); - } - - scratch_end(scratch); - return result; -} - -int -main(int argument_count, char **arguments) -{ - os_init(argument_count, arguments); - Arena *arena = arena_alloc(); - - U64 before_loop_stop_vaddr = 0x0000000140001089; - U64 inner_loop_stop_vaddr = 0x0000000140001098; - - // rjf: launch - { - OS_LaunchOptions opts = {0}; - opts.path = os_get_path(arena, OS_SystemPath_Current); - str8_list_push(arena, &opts.cmd_line, str8_lit("R:\\projects\\debugger\\build\\mule_loop_threads_win32.exe")); - B32 launch_good = test_launch_process(&opts); - int x = 0; - } - - // rjf: get process/thread handles - HANDLE process = 0; - HANDLE thread1 = 0; - U64 thread1_id = 0; - { - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, 0, 0); - if(evt.process) - { - process = evt.process; - } - if(evt.thread) - { - thread1 = evt.thread; - thread1_id = evt.thread_id; - } - if(process != 0 && thread1 != 0) - { - break; - } - } - } - - // rjf: get first breakpoint - { - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, 0, 0); - if(evt.evt.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) - { - break; - } - } - } - - //- rjf: run until 2nd thread starts up - HANDLE thread2 = 0; - U64 thread2_id = 0; - { - TEST_Trap traps[] = - { - {process, before_loop_stop_vaddr}, - }; - int trap_count = 0; //ArrayCount(traps); - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, trap_count, traps); - if(str8_match(evt.name, str8_lit("breakpoint"), 0)) - { - trap_count = 0; - } - if(evt.thread) - { - thread2 = evt.thread; - thread2_id = evt.thread_id; - break; - } - } - } - - //- rjf: wait for bps - { - Temp scratch = scratch_begin(0, 0); - TEST_Trap traps[] = - { - {process, 0x0000000140001098}, - {process, 0x00000001400010fb}, - {process, 0x00000001400010bc}, - {process, 0x00000001400010d7}, - }; - - for(int i = 0;; i += 1) - { - TEST_DebugEvent evt = test_run_process(0, 0, 1, &traps[i % ArrayCount(traps)]); - - // rjf: check regs - { - U64 rip = 0; - SYMS_RegX64 *regs = push_array(scratch.arena, SYMS_RegX64, 1); - if(evt.evt.dwThreadId == g_thread1_id && test_w32_read_x64_regs(thread1, regs)) - { - rip = regs->rip.u64; - } - if(evt.evt.dwThreadId == g_thread2_id && test_w32_read_x64_regs(thread2, regs)) - { - rip = regs->rip.u64; - } - - for(int i = 0; i < ArrayCount(traps); i += 1) - { - if(traps[i].address == rip) - { - printf("WRONG BP! 0x%I64x\n", rip); - break; - } - } - } - - if(str8_match(evt.name, str8_lit("breakpoint"), 0)) - { - HANDLE step = 0; - HANDLE suspend = 0; - step = evt.evt.dwThreadId == thread2_id ? thread2 : thread1; - suspend = step == thread2 ? thread1 : thread2; - evt = test_run_process(step, suspend, 0, 0); - } - } - scratch_end(scratch); - } - - return 0; -}